ODTK Scripting Guide

Introduction
Cross-Platform API
Language Specific Notes
Connecting to ODTK
Using the Scripting Tool
Creating, Deleting, Saving, and Loading Objects
Testing To See If An Object Exists
Basic Types
    Type REAL
    Type INT
    Type BOOL
    Type STRING
    Type STRING ENUMERATION
Compound Types
    Type QUANTITY
    Type DATE
    Type LINKTO
    Type LINKTO ENUMERATION
    Type LIST
    Type SETLINKTOOBJ
    Type SET
    Special Cases
    Maneuver Sets
    Multiple representations: Facility.Position
    Multiple representations: Satellite.OrbitState
    Type LINKTOOBJ with "not specified" choice
Product Builder: Creating Reports and Graphs
    Using an Existing Data Product List
    Building and Using a Data Product List
Migrating from VBScript to Visual Basic .NET
Setting a custom location for the ODTK log file
Using ODTK.WriteMessage() function
Closing child windows
Custom scripts for event handling
Automate ODTK Engine with C# and C++
Using External Scripts to Perform Date Time and Unit Conversion
Functional Attributes


Introduction

ODTK provides scripting support via the Microsoft Component Object Model (COM) IDispatch interface and Cross-Platform API. COM is accessible to many scripting engines including VBScript, JScript, Perl, Python, MATLAB, .NET platform (C#, VB.NET, ...), and to C, C#, and C++ applications via a special COM wrapper. Examples for COM are provided in VBScript, Perl, Python, and MATLAB.

Cross-Platform API is accessible to Python, MATLAB and C++. The examples througout the Scripting Guide are in Python, MATLAB, and C++.

A typical use case for controlling ODTK from the outside world is to automate some analysis or standard operations process. Often this is done by an engineer who would be happy if he/she didn't have to learn the intricacies of COM - vs. a classic computer science person. This guide is therefore oriented more toward a scripting approach rather than the use of compiled code (C#, C++, VB.NET). However, the concepts and interfaces are the same regardless of the language.

A question often asked is "What language should I use when working with ODTK?" So it's worth pointing out a few pros and cons of various choices.

It's often the case that for quick and dirty scripts at AGI that we use VBScript (because it's always available on any Windows PC). If automating a more complicated task that interfaces with the operating system a lot (file I/O, parsing, and interfacing with other software) that we'll use Perl. If you are building a more robust front end for typical day to day operations then VB.NET is often used.

The code for the Cross Platform API samples seems similar to the COM samples, but there are subtle differences. The differences are discuss in the Cross-Platform API section.

Language Specific Notes

VBScript

The VBScript engine does not release handles to the objects returned by ODTK functions if they are not stored into variables. If your script must shut down ODTK and continue running, then you have to assign all returned handles to some variables. For example, Clear() returns a handle to the empty list container:

ODTK.ProductBuilder.DataProducts.clear() ' Anonymous reference is kept
set unused = ODTK.ProductBuilder.DataProducts.clear()
set unused = Nothing                     ' This releases the reference
JScript

Some functions require String Objects, not just the String data type, so use conventions such as:

str = new String("string");

when creating strings. For-in loops do not function well, please use iterated for loops.

Perl

All the Perl examples were tested using Perl 5.8.8 from Active State (www.activestate.com). They have a free download of the Perl interpreter and we have had great success using their implementation.

The Win32:OLE module is required in order to interface with ODTK. You must include the following at the top of your Perl script:

use Win32::OLE;

When working with file and directory paths on Windows Perl returns '/' instead of '\'. Use the following or similar code to convert paths before assigning them to the ODTK variable:

$topdir = cwd();
$topdir =~ s/\//\\/g;

Various methods in ODTK will return an OLE collection object. To use these from Perl, you must use the Win32::OLE::Enum module. Alternatively (and somewhat cleaner) is the shortcut keyword "in". We will use this in some of the examples later on.

Python

All the Python examples were tested using Python 3.4.3 from Continuum Analytics (Anaconda). They have a free download of the Python interpreter.

The PyWin32 package is required in order to interface with ODTK. You must include the following at the top of your Python script:

import win32com.client as w32c

When concatenating strings and CDispatch variables into strings, you must cast CDispatch variables to strings with str() first.

If ODTK does not recognise Python as a valid scripting language, please initialize Python ActiveX by running pyscript.py, found in:

Python\Lib\site-packages\win32comext\axscript\client\
MATLAB

If you will be using MATLAB, please read the MATLAB help topic "External Interfaces | COM Support in MATLAB". MATLAB is case sensitive, so you will find that the Set() method will not work but set() will.

ODTK Runtime

The ODTK Cross-Platform API provides a mechanism to interact with ODTK on both Windows and Linux via HTTP. It is available on Windows via the 32-bit ODTK Desktop application, as well as the new 32-bit ODTK Runtime console application. It is available on Linux via the 64-bit ODTK Runtime application. AGI currently provides client API libraries for Python, MATLAB, and C++.

Client APIs

Prerequisites

The client libraries assume that the target ODTK application is already running with the HTTP server enabled. There is currently no way to manage the lifetime of an ODTK application using the API.

The HTTP server is always enabled on the Runtime application, but is disabled by default on the ODTK Desktop application.

Configuration on Windows Desktop Application

The HTTP server can be configured using the following command line switches:

Command Description
/enablehttpserver Enables the HTTP server, if specified
/httpserverport <portnumber> Sets the port to use for hosting the HTTP server, where <port number> is the number of the port to use; port 9393 is used if this command line switch is not specified.

Below is an example command line to enable the HTTP server on port 9494:

<ODTK bin>\AgUiApplication.exe /pers ODTK /enablehttpserver /httpserverport 9494

<ODTK bin> is the path to the 'bin' folder under the ODTK install folder (default is C:\Program Files (x86)\AGI\ODTK 6\bin).

Configuration on Windows Runtime Application

The HTTP server can be configured using the following command line switch:

Command Description
port <portnumber> Sets the port to use for hosting the HTTP server, where <portnumber> is the number of the port to use; port 9393 is used if this command line switch is not specified.

Below is an example command line to enable the HTTP server on port 9494:

<ODTK bin>\ODTKRuntime.exe /port 9494

<ODTK bin> is the path to the 'bin' folder under the ODTK install folder (default is C:\Program Files (x86)\AGI\ODTK 6\bin).

Configuration on Linux Runtime Application

The HTTP server can be configured using the following command line switch:

Command Description
port <portnumber> Sets the port to use for hosting the HTTP server, where <portnumber> is the number of the port to use; port 9393 is used if this command line switch is not specified.

Below is an example command line to enable the HTTP server on port 9494:

<ODTK bin>/odtkruntime --port=9494

<ODTK bin> is the path to the folder containing the ODTK binaries.

Connecting to ODTK

There are three common modes for interacting with ODTK. The final result of each of them is that they provide a handle to the root object in ODTK. Standard automation server properties are also available either to make the application invisible or to disable user control while the script is running. Note that "ODTK.Application" refers to the most recently installed version of ODTK. Alternatively, you can specify a version number, e.g. "ODTK6.Application".

1. To start a new instance of ODTK

COM

VBScript
set app = CreateObject("ODTK.Application")
set ODTK = app.Personality
app.visible = true
app.UserControl = true
JScript
var app = new ActiveXObject("ODTK.Application");
var ODTK = app.personality;
app.visible = true;
app.UserControl = true;
Perl
my $app = Win32::OLE->new("ODTK.Application", sub {$_[0]->Quit;})
my $ODTK = $app->personality;
$app->{Visible} = 1;
$app->{UserControl} = 1;
Python
app = w32c.Dispatch("ODTK.Application")
ODTK = app.Personality
app.Visible = True
app.UserControl = True
            
MATLAB
app = actxserver( 'ODTK.Application' );
odtk = app.get('Personality');
app.visible = true;
app.usercontrol = true;
            

2. To attach to an already running instance of ODTK:

VBScript
set app  = GetObject(,"ODTK.Application")
set ODTK = app.personality
JScript
var app = GetObject("","ODTK.Application");
var ODTK = app.personality;
Perl
my $app  = Win32::OLE->GetActiveObject("ODTK.Application");
my $ODTK = $app->personality;
Python
app  = w32c.GetActiveObject("ODTK.Application")
ODTK = app.Personality
MATLAB
app  = actxGetRunningServer('ODTK.Application');
odtk = app.get('Personality');

3. Finally, you can embed a script inside an HTML page and load that page into ODTK's HTML Viewer.

COM

VBScript
set app  = window.external
set ODTK = app.personality
JScript
var app  = window.external;
var ODTK = app.Personality;
Python
app  = window.external
ODTK = app.Personality

Python Client API

The Python Client API library is provided as a single odtk.py module and requires Python 3.6.2 or higher. Use the code below to import the module and access a default ODTK instance (on localhost:9393).

from odtk import Client

            

# Make sure ODTK is running with the HTTP server started (default port is 9393) before running this script

# The following initializes the client to connect to ODTK at the default port
client = Client()

#Get the application root attribute
odtk = client.get_root()

To connect to ODTK running the API on a different port, initialize a Client with a 'port' argument. Example:

client = Client(port=9494)

The API provides a hierarchical object model that exposes data and functionality by accessing ‘ODTK attributes’ starting from the application root. You can navigate the object hierarchy by addressing a desired object by name at each level, using a dot (‘.’) as a level separator. For example:

Command Description
odtk.scenario[0] Corresponds to the current ODTK scenario or the first item contained by the 'scenario' attribute (as indicated by the [0]) contained by the 'odtk' attribute.
odtk.application.appVersion Corresponds to the 'appVersion' attribute contained by the 'application' attribute of the 'odtk' attribute.

Keep in mind the following when accessing attributes:

More details on API usage can be found in the scripting_guide.py and the AttrProxyTest.py in <ODTK Install dir>/CodeSamples/CrossPlatform/ODTK/python.

MATLAB Client API

The MATLAB client API library is provided as a set of MATLAB *.m script files and requires MATLAB R2017b or higher. Make sure that the script files are discoverable to MATLAB at runtime. The following is sample code for accessing a default ODTK instance (on localhost:9393)

% Add the ODTK client API to the search path
addpath('../lib');
% Make sure ODTK is running with the HTTP server started (default port is 9393)
% before running this script
client = Client();
% Get the application root attribute
odtk = client.Root;

To connect to ODTK running the API on a different port, initialize a Client with a 'port' argument. Example:

client = Client("127.0.0.1", 9494);

The API provides a hierarchical object model that exposes data and functionality by accessing ‘ODTK attributes’ starting from the application root. You can navigate the object hierarchy by addressing a desired object by name at each level, using a dot (‘.’) as a level separator. For example:

Command Description
odtk.scenario[0] Corresponds to the current ODTK scenario or the first item contained by the 'scenario' attribute (as indicated by the [0]) contained by the 'odtk' attribute.
odtk.application.appVersion Corresponds to the 'appVersion' attribute contained by the 'application' attribute of the 'odtk' attribute.

Keep in mind the following when accessing attributes:

More details on API usage can be found in the scripting_guide.m and the AttrProxyTest.m in <ODTK Install dir>/CodeSamples/CrossPlatform/ODTK/matlab.

C++ Client API

The C++ client API library is provided as a set of header and source files that need to be compiled into your C++ application and requires C++ 11 or higher. Setup your code by including the ‘ODTKClient.h’ header file. The following is sample code for accessing a default ODTK instance (on localhost:9393):

// Make sure ODTK is running, with the HTTP server started(default port is 9393) before running this method
// The following initializes the client to connect to ODTK at the default port
const agi::odtk::Client client;
// Get the application root attribute
const agi::odtk::AttrProxy odtk = client.GetRoot();

To connect to ODTK running the API on a different port, initialize a Client with a 'port' argument. Example:

const agi::odtk::Client client("127.0.0.1", 9494);

The API provides a hierarchical object model that exposes data and functionality by accessing ‘ODTK attributes’ starting from the application root. You can Navigate the object hierarchy by addressing a desired object by name at each level, using a dot (‘.’) as a level separator. For example:

Command Description
odtk.("scenario")[0] Corresponds to the current ODTK scenario or the first item contained by the 'scenario' attribute (as indicated by the '[0]' (ODTK's collections are 0 based) contained by the 'odtk' attribute.
odtk("application")("appVersion") Corresponds to the 'appVersion' attribute contained by the 'application' attribute of the 'odtk' attribute.

Keep in mind the following when accessing attributes:

More details on API usage can be found in the scripting_guide.cpp and the AttrProxyTest.cpp in <ODTK Install dir>/CodeSamples/CrossPlatform/ODTK/cpp.

Disconnecting from ODTK

To disconnect from the application, release all object handles in the order in which they were set. Then, unless you set UserControl=true, the application will shut down. If the application is to be immediately reopened it may be necessary to "sleep" and allow the shutdown procedure to complete before opening another instance of ODTK:

COM

VBScript
set ODTK = Nothing     ' Release ODTK root object
set app  = Nothing     ' Release application GUI handle
wscript.sleep(5000)    ' Wait 5 seconds while ODTK terminates
JScript
ODTK = undefined;
app = undefined;
var WshShell = WScript.CreateObject("WScript.Shell");
WScript.Sleep(5000);
Perl
undef $ODTK;
undef $app;
Python
ODTK = None
app = None
MATLAB
odtk.release;
app.release;
clear odtk;
clear app;

Preference Files

Access to user Preference files is optional.

odtk.release;
ePrefFiles_NoLoad_NoSave = 0,
ePrefFiles_Load_NoSave = 1,
ePrefFiles_Load_And_Save = 2
                

These control load the Application and User Preferences when Personality is loaded/initialized and saves the User Preference files upon exiting the application. User Preference files are usually found in user home/Documents/ODTK 6/Config.

Example:

uiApp = CreateObject("ODTK6.Automation") // or "ODTK6.Engine"
uiApp.Visible = false
uiApp.UserControl - false
uiApp.PrefFilesMode = AgEPrefFilesMode.ePrefFiles_Load_No_Save
ODTK = uiApp.LoadPersonality("ODTK")
        

The default value for ODTK6.Application and ODTK6.Automation is ePrefFiles_Load_And_Save and the default mode for ODTK6.Engine is ePrefFile_Load_No_Save.

The UserControl property should indicate that when it is set to false, saving of the preference files, formats, MRU file lists is disabled and when it set to true/enabled. UserControl = false setting does not prevent users from interacting with the application, but ODTK will not pop-up any Message Boxes if this is the case.

Using the Scripting Tool

Throughout this guide we are going to use the Scripting Tool utility, available from the LaunchPad, to examine the ODTK object hierarchy and run included code examples. The scripting tool can be used to execute VBScript and javascript code as a means for prototyping.

Copy Attribute Path

Starting with the ODTK root object each object provides access to its sub objects via the Children scope. As a side effect of supporting various languages there are multiple ways to get access to the same object. For instance, "Sat1" could be referred to as:

COM

VBScript
set scen = ODTK.Scenario(0)       ' There's only one scenario
set sat = scen.Sat1               ' Not very portable if you rename your satellite
set sat = scen.Satellite(0)       ' Gets the first satellite in the scenario
set sat = scen.Satellite("Sat1")
set sat = scen.Children.Satellite(0)
set sat = scen.Children("Satellite")(0)
JScript
var scen = ODTK.Scenario(0);       // There's only one scenario
var sat = scen.Sat1;               // Not very portable if you rename your satellite
var sat = scen.Satellite(0);       // Gets the first satellite in the scenario
var sat = scen.Satellite("Sat1");
var sat = scen.Children.Satellite(0);
var sat = scen.Children("Satellite")(0);
Perl
my $scen = $ODTK->Scenario(0);
my $sat = $scen->Satellite(0);
$sat = $scen->Satellite("Sat1");
$sat = $scen->Children->Satellite(0);
$sat = $scen->Children("Satellite")(0);
                    
Python
scen = ODTK.Scenario(0)
sat = scen.Sat1
sat = scen.Satellite(0)
sat = scen.Satellite("Sat1")
sat = scen.Children.Satellite(0)
sat = scen.Children("Satellite")(0)
MATLAB
scen = odtk.invoke('Scenario').invoke('Item', 0);
sat = scen.invoke('Sat1')
sat = scen.invoke('Satellite').invoke('Sat1');

sat = scen.invoke('Satellite').invoke('Item', 0);
sat = scen.invoke('Satellite').invoke('Sat1');

sat = scen.invoke('Children').invoke('Satellite').invoke('Item', 0);
                    

Cross-Platform API

Python
scenario = odtk.scenario[0]
satellite = scenario.mySat
print(f'Satellite name using scenario.mySat: {satellite.name.eval()}')
satellite = scenario.Satellite[0]
print(f'Satellite name using scenario.Satellite[0]: {satellite.name.eval()}')
satellite = scenario.Satellite[zeroth_satellite_name]
print(f'Satellite name using scenario.Satellite[\'{zeroth_satellite_name}\']: {satellite.name.eval()}')
satellite = scenario.Children.Satellite[0]
print(f'Satellite name using scenario.Children.Satellite[0]: {satellite.name.eval()}')
satellite = scenario.Children['Satellite'][0]
print(f'Satellite name using scenario.Children[\'Satellite\'][0]: {satellite.name.eval()}')
satellite = scenario.Children['Satellite'].Item[0]
print(f'Satellite name using scenario.Children[\'Satellite\'].Item[0]: {satellite.name.eval()}')
satellite = scenario.Children['Satellite'].Item[zeroth_satellite_name]
print(f'Satellite name using scenario.Children[\'Satellite\'].Item[\'{zeroth_satellite_name}\']: '
f'{satellite.name.eval()}')
satellite = scenario.Children['Satellite'].ItemByName[zeroth_satellite_name]
print(f'Satellite name using scenario.Children[\'Satellite\'].ItemByName[\'{zeroth_satellite_name}\']: '
f'{satellite.name.eval()}')
            
MATLAB
scenario = odtk.scenario{0};
satellite = scenario.mySat;
fprintf("Satellite name using scenario.mySat: %s\n", satellite.name);
satellite = scenario.Satellite{0};
fprintf("Satellite name using scenario.Satellite{0}: %s\n", satellite.name);
satellite = scenario.Satellite{zerothSatelliteName};
fprintf("Satellite name using scenario.Satellite{""%s""} : %s\n", zerothSatelliteName, satellite.name);
satellite = scenario.Children.Satellite{0};
fprintf("Satellite name using scenario.Children.Satellite{0}: %s\n", satellite.name);
satellite = scenario.Children{"Satellite"}{0};
fprintf("Satellite name using scenario.Children{""Satellite""}{0}: %s\n", satellite.name);
satellite = scenario.Children{"Satellite"}.Item{0};
fprintf("Satellite name using scenario.Children{""Satellite""}.Item{0}: %s\n", satellite.name);
satellite = scenario.Children{"Satellite"}.Item{zerothSatelliteName};
fprintf("Satellite name using scenario.Children{""Satellite""}.Item{%s}: %s\n", zerothSatelliteName, satellite.name);
satellite = scenario.Children{"Satellite"}.ItemByName{zerothSatelliteName};
fprintf("Satellite name using scenario.Children{""Satellite""}.ItemByName{""%s""}: %s\n", zerothSatelliteName, satellite.name);
            
C++
const agi::odtk::AttrProxy scenario = odtk("scenario")[0];
std::cout << R"(Satellite name using scenario(")" << zerothSatelliteName << R"()): )" << scenario(zerothSatelliteName)("name").AsString() << "\n";
std::cout << R"(Satellite name using scenario("Satellite")[0]: )" << scenario("Satellite")[0]("name").AsString() << "\n";
std::cout << R"(Satellite name using scenario("Satellite")(")" << zerothSatelliteName << "\"): " << scenario("Satellite")(zerothSatelliteName)("name").AsString() << "\n";
std::cout << R"(Satellite name using scenario("Children")("Satellite")[0]: )" << scenario("Children")("Satellite")[0]("name").AsString() << "\n";
std::cout << R"(Satellite name using scenario("Children")("Satellite")("Item")[0]: )" << scenario("Children")("Satellite")("Item")[0]("name").AsString() << "\n";
std::cout << R"(Satellite name using scenario("Children")("Satellite")("Item")[")" << zerothSatelliteName << R"("]: )" << scenario("Children")("Satellite")("Item")[zerothSatelliteName]("name").AsString() << "\n";
std::cout << R"(Satellite name using scenario("Children")("Satellite")("ItemByName")[")" << zerothSatelliteName << R"("]: )" << scenario("Children")("Satellite")("ItemByName")[zerothSatelliteName]("name").AsString() << "\n";

            

Use Children to test if there are any objects and then use class name to access them. For example, to display the names of each of the satellites in your scenario you could use the following:

COM

VBScript
if ODTK.Children.Count = 0 then
    MsgBox "No scenario exists."
else
    for each sat in ODTK.Scenario(0).Children("Satellite")
        MsgBox sat.name
    next
end if
            
JScript
var Shell = new ActiveXObject("WScript.Shell");
if (ODTK.Children.Count == 0)
{
    Shell.Popup("No scenario exists.");
}
else
{
    var i;
    for(i = 0; i < ODTK.Scenario(0).Children("Satellite").Count; i++)
    {
        Shell.Popup(ODTK.Scenario(0).Children("Satellite")(i).name);
    }
}
Perl
if ($ODTK->Children->{Count} == 0)
{
    Win32::MsgBox("No scenario exists.");
}
else
{
    # You must define the collection first before using
    # it with the "in" keyword.
    my $coll = $ODTK->Scenario(0)->Children("Satellite");
    foreach my $sat (in $coll)
    {
        Win32::MsgBox($sat->{name}->{Value});
    }
}
            
Python
if ODTK.Children.Count == 0:
    print("No scenario exists.")
else:
    for sat in ODTK.Scenario(0).Children("Satellite"):
        print(sat.name)
MATLAB
if odtk.invoke('Children').invoke('Count') == 0
    error('No scenario exists.');
else
    scen = odtk.invoke('Scenario').invoke('Item', 0);
    fprintf('%s\n', scen.invoke('name').invoke('Value'));

    coll = scen.invoke('Children').invoke('Satellite');
    size = coll.invoke('Size').invoke('Value');
    for i = 0:size - 1
        sat = coll.invoke('Item', i);
        fprintf('%s\n', sat.invoke('name').invoke('Value'));
    end;
end
                

Cross-Platform API

Python
# To display the names of each of the satellites in your scenario you could use the following:
print('Names of satellites in the scenario:')
for satellite in odtk.scenario[0].Children['Satellite']:
    print(f'   {satellite.name.eval()}')
    
MATLAB

% To display the names of each of the satellites in your scenario you could use the following:
fprintf("Names of satellites in the scenario:\n")
satellites = odtk.scenario{0}.children{"Satellite"};
for i = 0: satellites.Count-1
    fprintf("  %i. %s\n", i, satellite.name);
end
    
C++
// To display the names of each of the satellites in your scenario you could use the following :
std::cout << "Names of satellites in the scenario:\n";
const agi::odtk::AttrProxy satellites = scenario("children")("Satellite");
for (int i = 0; i <; satellites("Count").AsInt(); ++i)
{
    std::cout << "  " << i << "." << satellites[i]("name").AsString() << "\n";
}


        

Creating, Deleting, Saving, and Loading Objects

There are a number of functions in ODTK to manage the scenario and other objects. New objects are created with the CreateObj function. It takes three parameters: the parent object of the new object, the type of object to create, and the name of the new object. This function returns a handle to the new object.

Do not give objects ODTK class names ("Scenario", "Satellite", "Filter", etc.).

COM

VBScript
dim scen, sat1, trkSys, trkFac
set scen   = ODTK.CreateObj(ODTK,   "Scenario",       "Example1")
set sat1   = ODTK.CreateObj(scen,   "Satellite",      "GEO_Sat1")
set trkSys = ODTK.CreateObj(scen,   "TrackingSystem", "TrkSys1")
set trkFac = ODTK.CreateObj(trkSys, "Facility",       "BOSS-A")
JScript
var scen, sat1, trkSys, trkFac;
scen   = ODTK.CreateObj(ODTK,   "Scenario",       "Example1");
sat1   = ODTK.CreateObj(scen,   "Satellite",      "GEO_Sat1");
trkSys = ODTK.CreateObj(scen,   "TrackingSystem", "TrkSys1");
trkFac = ODTK.CreateObj(trkSys, "Facility",       "BOSS-A");
Perl
my ($scen, $sat1, $trkSys, $trkFac);
$scen   = $ODTK->CreateObj($ODTK,   "Scenario",       "Example1");
$sat1   = $ODTK->CreateObj($scen,   "Satellite",      "GEO_Sat1");
$trkSys = $ODTK->CreateObj($scen,   "TrackingSystem", "TrkSys1");
$trkFac = $ODTK->CreateObj($trkSys, "Facility",       "BOSS-A");
Python
scen   = ODTK.CreateObj(ODTK,   "Scenario",       "Example1")
sat1   = ODTK.CreateObj(scen,   "Satellite",      "GEO_Sat1")
trkSys = ODTK.CreateObj(scen,   "TrackingSystem", "TrkSys1")
trkFac = ODTK.CreateObj(trkSys, "Facility",       "BOSS-A")
MATLAB
scen   = odtk.invoke('CreateObj', odtk,   'Scenario',       'MyScenario');
sat    = odtk.invoke('CreateObj', scen,   'Satellite',      'MySat');
trkSys = odtk.invoke('CreateObj', scen,   'TrackingSystem', 'TrkSys1');
trkFac = odtk.invoke('CreateObj', trkSys, 'Facility',       'BOSS-A');

Cross-Platform API

Python
# ensure new scenario
if odtk_child_count > 0:
    # close scenario
    odtk.application.deleteObject('', odtk.scenario[0])
    print('Scenario closed.')
odtk.application.createObj(odtk, 'Scenario', 'TestScenario')
print('Scenario created.')

# create satellites
zeroth_satellite_name = 'mySat'
zero_as_satellite_name = '0'
odtk.application.createObj(odtk.scenario[0], 'Satellite', zeroth_satellite_name)
my_other_sat = odtk.application.createObj(odtk.scenario[0], 'Satellite', 'myOtherSat')
odtk.application.createObj(odtk.scenario[0], 'Satellite', zero_as_satellite_name)
print('Satellites created.')

# create filter
odtk.application.createObj(odtk.scenario[0], 'Filter', 'Filter1')
        
MATLAB
% ensure new scenario
if odtkChildCount > 0
    % close scenario
    odtk.application.deleteObject("", odtk.scenario{0});
    fprintf("Scenario closed.\n");
end
odtk.application.createObj(odtk, "Scenario", "TestScenario");
fprintf("Scenario created.\n");

% create satellites
zerothSatelliteName = "mySat";
zeroAsSatelliteName = "0";
odtk.application.createObj(odtk.scenario{0}, "Satellite", zerothSatelliteName);
myOtherSat = odtk.application.createObj(odtk.scenario{0}, "Satellite", "myOtherSat");
odtk.application.createObj(odtk.scenario{0}, "Satellite", zeroAsSatelliteName);
fprintf("Satellites created.\n");

% create filter
odtk.application.createObj(odtk.scenario{0}, "Filter", "Filter1");
        
C++
// ensure new scenario
if (odtkChildCount > 0)
{
    // close scenario
    odtk("application")("deleteObject").Invoke("", odtk("scenario")[0]);
    std::cout << "Scenario closed.\n";
}

odtk("application")("createObj").Invoke(odtk, "Scenario", "TestScenario");
std::cout << "Scenario created.\n";

// create satellites
const auto zerothSatelliteName = "mySat";
const auto zeroAsSatelliteName = "0";
const auto fourthSatName = "fourth_sat";
odtk("application")("createObj").Invoke(odtk("scenario")[0], "Satellite", zerothSatelliteName);
const auto myOtherSat = odtk("application")("createObj").InvokeAttrProxy(odtk("scenario")[0], "Satellite", "myOtherSat");
odtk("application")("createObj").Invoke(odtk("scenario")[0], "Satellite", zeroAsSatelliteName);
odtk("application")("createObj").Invoke(odtk("scenario")[0], "Satellite", fourthSatName);
std::cout << "Satellites created.\n";

// create filter
odtk("application")("createObj").Invoke(odtk("scenario")[0], "Filter", "Filter1");
        

You can save the scenario or any object to a file with the SaveObj function. It takes three parameters: the object handle, the destination file name, and the boolean SaveObjectChildren flag:

COM

VBScript
set newSat = ODTK.SaveObj(scen,   "C:\Temp\Example1.sco", true)
set newSat = ODTK.SaveObj(sat,    "C:\Temp\GEO_Sat1.sao", false)
set newSat = ODTK.SaveObj(trkSys, "C:\Temp\TrkSys1.tso",  true)
JScript
var newSat = ODTK.SaveObj(scen,   "C:\\Temp\\Example1.sco", true)
newSat = ODTK.SaveObj(sat,    "C:\\Temp\\GEO_Sat1.sao", false)
newSat = ODTK.SaveObj(trkSys, "C:\\Temp\\TrkSys1.tso",  true)
Perl
my $newSat = $ODTK->SaveObj($scen,   "C:\\Temp\\Example1.sco", true);
$newSat = $ODTK->SaveObj($sat,    "C:\\Temp\\GEO_Sat1.sao", false);
$newSat = $ODTK->SaveObj($trkSys, "C:\\Temp\\TrkSys1.tso",  true);
Python
newSat = ODTK.SaveObj(scen, "C:\\Temp\\Example1.sco", True)
newSat = ODTK.SaveObj(sat, "C:\\Temp\\GEO_Sat1.sao", False)
newSat = ODTK.SaveObj(trkSys, "C:\\Temp\\TrkSys1.tso", True)
MATLAB
newSat = odtk.invoke('SaveObj', scen,   'C:\Temp\Example1.sco', true);
newSat = odtk.invoke('SaveObj', sat,    'C:\Temp\GEO_Sat1.sao', false);
newSat = odtk.invoke('SaveObj', trkSys, 'C:\Temp\TrkSys1.tso',  true);

Cross-Platform API

Python
# It takes three parameters: the object handle, the destination file name, and the boolean SaveObjectChildren flag.
this_dir_path = os.path.dirname(os.path.realpath(__file__))
scenario_file_path = os.path.join(this_dir_path, 'Example1.sco')
odtk.SaveObj(odtk.scenario[0], scenario_file_path, True)
print(f'Scenario saved to {scenario_file_path}')
            
MATLAB
% It takes three parameters: the object handle, the destination file name,
% and the boolean SaveObjectChildren flag.
[thisFolderPath] = fileparts(mfilename('fullpath'));
scenarioFilePath = [thisFolderPath, filesep, 'Example1.sco'];
odtk.SaveObj(odtk.scenario{0}, scenarioFilePath, true);
fprintf("Scenario saved to %s.\n", scenarioFilePath);
                
C++
// It takes three parameters : the object handle, the destination file name,
// and the boolean SaveObjectChildren flag.
const std::string thisFolderPath = GetThisFolderPath();
const auto scenarioFilePath = thisFolderPath + s_pathSeparator + "Example1.sco";
odtk("SaveObj").Invoke(odtk("scenario")[0], scenarioFilePath, true);
std::cout << "Scenario saved to " << scenarioFilePath << "\n";
            

The DeleteObject function takes an object handle and returns a success status:

COM

VBScript
bSuccess = ODTK.DeleteObject(trkSys.Facility("BOSS-A"))
JScript
bSuccess = ODTK.DeleteObject(trkSys.Facility("BOSS-A"));
Perl
my $bSuccess = $ODTK->DeleteObject($trkSys->Facility("BOSS-A"));
Python
bSuccess = ODTK.DeleteObject(trkSys.Facility("BOSS-A"))
MATLAB
bSuccess = odtk.invoke('DeleteObject', trkSys.invoke('Facility').invoke('BOSS-A'));

Cross-Platform API

Python
deleted = odtk.deleteobject(my_other_sat)

                
MATLAB
deleted = odtk.deleteobject(myOtherSat);
C++
const auto deleted = odtk("deleteobject").InvokeBool(myOtherSat);
std::cout << "Deleted myOtherSat: " << BoolToString(deleted) << "\n";

Only one scenario at a time is allowed; unload the current scenario before loading the next one.

To load an object at a later time, use the LoadObject function. Its parameters are the path of the parent object where the new object is to be loaded and the source file name containing the object to be loaded. You can load Satellite and Facility objects that are produced by either ODTK or STK.

COM

VBScript
bSuccess = ODTK.LoadObject("",                  "C:\Temp\Scenario1.sco")
bSuccess = ODTK.LoadObject("Scenario1",         "C:\Temp\STK_Sat.sa")
bSuccess = ODTK.LoadObject("Scenario1",         "C:\Temp\ODTK_Sat.sao")
bSuccess = ODTK.LoadObject("Scenario1",         "C:\Temp\TrkSys1.tso")
bSuccess = ODTK.LoadObject("Scenario1.TrkSys1", "C:\Temp\STK_Fac.f")
bSuccess = ODTK.LoadObject("Scenario1.TrkSys1", "C:\Temp\ODTK_Fac.fo")
JScript
bSuccess = ODTK.LoadObject("",                  "C:\\Temp\\Scenario1.sco");
bSuccess = ODTK.LoadObject("Scenario1",         "C:\\Temp\\STK_Sat.sa");
bSuccess = ODTK.LoadObject("Scenario1",         "C:\\Temp\\ODTK_Sat.sao");
bSuccess = ODTK.LoadObject("Scenario1",         "C:\\Temp\\TrkSys1.tso");
bSuccess = ODTK.LoadObject("Scenario1.TrkSys1", "C:\\Temp\\STK_Fac.f");
bSuccess = ODTK.LoadObject("Scenario1.TrkSys1", "C:\\Temp\\ODTK_Fac.fo");
                    
Perl
$bSuccess = $ODTK->LoadObject("",                  "C:\\Temp\\Scenario1.sco");
$bSuccess = $ODTK->LoadObject("Scenario1",         "C:\\Temp\\STK_Sat.sa");
$bSuccess = $ODTK->LoadObject("Scenario1",         "C:\\Temp\\ODTK_Sat.sao");
$bSuccess = $ODTK->LoadObject("Scenario1",         "C:\\Temp\\TrkSys1.tso");
$bSuccess = $ODTK->LoadObject("Scenario1.TrkSys1", "C:\\Temp\\STK_Fac.f");
$bSuccess = $ODTK->LoadObject("Scenario1.TrkSys1", "C:\\Temp\\ODTK_Fac.fo");
                    
Python
bSuccess = ODTK.LoadObject("",                  "C:\\Temp\\Scenario1.sco")
bSuccess = ODTK.LoadObject("Scenario1",         "C:\\Temp\\STK_Sat.sa")
bSuccess = ODTK.LoadObject("Scenario1",         "C:\\Temp\\ODTK_Sat.sao")
bSuccess = ODTK.LoadObject("Scenario1",         "C:\\Temp\\TrkSys1.tso")
bSuccess = ODTK.LoadObject("Scenario1.TrkSys1", "C:\\Temp\\STK_Fac.f")
bSuccess = ODTK.LoadObject("Scenario1.TrkSys1", "C:\\Temp\\ODTK_Fac.fo")
MATLAB
bSuccess = odtk.invoke('LoadObject', '',                   'C:\Temp\Example1.sco');
bSuccess = odtk.invoke('LoadObject', 'Scenario1',          'C:\Temp\STK_Sat.sa');
bSuccess = odtk.invoke('LoadObject', 'Scenario1',          'C:\Temp\ODTK_Sat.sao');
bSuccess = odtk.invoke('LoadObject', 'Scenario1',          'C:\Temp\TrkSys1.tso');
bSuccess = odtk.invoke('LoadObject', 'Scenario1.TrkSys1',  'C:\Temp\STK_Fac.f');
bSuccess = odtk.invoke('LoadObject', 'Scenario1.TrkSys1',  'C:\Temp\ODTK_Fac.fo');
                    

Cross-Plaform API

Python
# close the scenario
odtk.application.deleteObject('', odtk.scenario[0])
# load the scenario
scenario_loaded = odtk.LoadObject('', scenario_file_path)
MATLAB
% close the scenario
odtk.application.deleteObject("", odtk.scenario{0});
% load the scenario
scenarioLoaded = odtk.LoadObject("", scenarioFilePath);
            
C++
// close the scenario
odtk("application")("deleteObject").Invoke(odtk("scenario")[0]);
// load the scenario
const auto scenarioLoaded = odtk("LoadObject").InvokeBool("", scenarioFilePath);
std::cout << "Scenario loaded from " << scenarioFilePath << ": " << BoolToString(scenarioLoaded) << "\n";
                

Testing To See If An Object Exists

The scripting interface supports an

ItemExists
method to test if an object exists.

Consider an ODTK scenario with Facilities named "02", "07", and "33" accessed with the following script:

set tc = ODTK.Scenario(0).TrackingSystem("TrackingSystem1").Children.Facility
alert tc.Item(2).Name  'this will likely return "33" because Item() always looks up by id if the index could be interpreted as an integer
'alert tc.Item(7).Name  'this will fail generating an exception
alert tc.ItemExists("05") 'this will return false without exception
alert tc.ItemExists("07") 'this will return true
alert tc.ItemByName("02").Name 'this will correctly return facility "2"
alert tc.ItemByName("07").Name 'this will correctly return facility "7"

Cross-Platform API

Python
# Testing To See If An Object Exists
satellites = odtk.scenario[0].Children['Satellite']
# access by index
satellite_name = satellites[0].name.eval()
print(f'satellites[0] name: {satellite_name}')
# access by name
print(f'satellites[\"' + satellite_name + '\"] name: {satellites[satellite_name].name.eval()}')
# access using a name that is numeric (string)
satellite_name = satellites[zero_as_satellite_name].name.eval()
print(f'satellites[\"{zero_as_satellite_name}\"] name: {satellite_name}')

try:
    # access by invalid index should throw an exception
    satellite_name = satellites[7].name.eval()
    raise Exception('The expected exception was not thrown.')
except ClientException as e:
    if e.error_code == ClientExceptionCodes.INVALID_ATTRIBUTE_PATH and 'Index Out of Range' in str(e):
        print('Non-existent satellite reference threw an exception as expected.')
    else:
        raise Exception('Unexpected exception was raised.')

# ItemExists returns true on existing name
exists = satellites.ItemExists(zeroth_satellite_name)
print(f'satellite \"{zeroth_satellite_name}\" exists: {exists}')

# ItemExists returns false on non-existent name
exists = satellites.ItemExists('07')
print(f'satellite \"07\" exists: {exists}')
            
MATLAB
% Testing To See If An Object Exists
% access by index
satelliteName = satellites{0}.name;
fprintf("satellites{0} name: %s\n", satelliteName);
% access by name
fprintf("satellites{""%1$s""} name: %2$s\n", satelliteName, satellites{satelliteName}.name);
% access using a name that is numeric (string)
satelliteName = satellites{zeroAsSatelliteName}.name;
fprintf("satellites{""%1$s""} name: %2$s\n", zeroAsSatelliteName, satelliteName);

try
    % access by invalid index should throw an exception
    satelliteName = satellites{7}.name;
    throw(MException('ScriptingGuide:unexpectedError', 'The expected exception was not thrown.'));
catch ex
    if ex.identifier == ClientExceptionIDs.InvalidAttributePath && contains(ex.message, "Index Out of Range")
        fprintf("Non-existent satellite reference threw an exception as expected.\n");
    else
        throw(MException('ScriptingGuide:unexpectedError', 'An unexpected exception was thrown.'));
    end
end

% ItemExists returns true on existing name
exists = satellites.ItemExists(zerothSatelliteName);
fprintf("satellite ""%1$s"" exists: %2$s\n", zerothSatelliteName, string(exists));

% ItemExists returns false on non-existent name
exists = satellites.ItemExists("07");
fprintf("satellite ""07"" exists: %s\n", string(exists));
        
C++
// Testing To See If An Object Exists
// access by index
const auto satelliteName = satellites[0]("name").AsString();
std::cout << "satellites[0] name: " << satelliteName << "\n";
// access by name
std::cout << R"(satellites[")" << satelliteName << R"("] name: )" << satellites[satelliteName]("name").AsString() << "\n";
// access using a name that is numeric(string)
std::cout << R"(satellites[")" << zeroAsSatelliteName << R"("] name: )" << satellites[zeroAsSatelliteName]("name").AsString() << "\n";
try
{
    // access by invalid index should throw an exception
    const auto satellite7Name = satellites[7]("name").AsString();
    throw std::runtime_error("The expected exception was not thrown.");
}
catch (const agi::odtk::ClientException& clientException)
{
    if (clientException.ErrorCode == agi::odtk::clientExceptionCodes::InvalidAttributePath && strstr(clientException.what(), "Index Out of Range"))
    {
        std::cout << "Non-existent satellite reference threw an exception as expected.\n";
    }
    else
    {
        throw std::runtime_error("An unexpected exception was thrown.");
    }
}

// ItemExists returns true on existing name
std::cout << "satellite \"" << zerothSatelliteName << "\" exists: " << BoolToString(satellites("ItemExists").InvokeBool(zerothSatelliteName)) << "\n";

// ItemExists returns false on non-existent name
std::cout << "satellite \"07\" exists: " << BoolToString(satellites("ItemExists").InvokeBool("07")) << "\n";
                        

Please note that internal names used by the Automation Interface itself, such as "Name", "Class", "Count", "Item", "ItemExists", "ItemByName", and "GetProp", as well as class names of the object families such as "Satellite", "Filter", and "Smoother", are still illegal names for ODTK objects and could cause issues.

Basic Types

Most of the ODTK attributes are simple scalar types that have equivalents in many programming languages: {REAL, INT, BOOL, STRING, STRING ENUMERATION}.

To learn about the type, right-click on the attribute, then click Attribute Information. A dialog box will pop up with the attribute type and additional information such as min/max or allowed enumeration choices.

The discussion of each type includes the appropriate syntax for setting and getting its value. Note that some of the attributes are grayed out, indicating that they are read only.

Type REAL

Real attributes are used for unit-less real numbers (min/max constraint may apply).

COM

VBScript
scen.OrbitClassifications.LEO.EccentricityMax = 0.15
ecc = scen.OrbitClassifications.LEO.EccentricityMax
JScript
scen.OrbitClassifications.LEO.EccentricityMax = 0.15;
var ecc = scen.OrbitClassifications.LEO.EccentricityMax;
Perl
$scen->OrbitClassifications->LEO->{EccentricityMax} = 0.15;
$ecc = $scen->OrbitClassifications->LEO->EccentricityMax->{Value};
Python
scen.OrbitClassifications.LEO.EccentricityMax = 0.15
ecc = scen.OrbitClassifications.LEO.EccentricityMax
MATLAB
scen.invoke('OrbitClassifications').invoke('LEO').set('EccentricityMax', 0.15);
ecc = scen.invoke('OrbitClassifications').invoke('LEO').invoke('EccentricityMax').invoke('Value');

Cross-Platform API

Python
scenario.OrbitClassifications.LEO.EccentricityMax = 0.15
eccentricity_max = scenario.OrbitClassifications.LEO.EccentricityMax.eval()
print(f'Eccentricity max: {eccentricity_max}')
                
MATLAB
scenario.OrbitClassifications.LEO.EccentricityMax = 0.15;
eccentricityMax = scenario.OrbitClassifications.LEO.EccentricityMax;
fprintf("Eccentricity max: %f\n", eccentricityMax);
C++
scenario("OrbitClassifications")["LEO"]("EccentricityMax").Assign(0.15);
std::cout << "Eccentricity max: " << scenario("OrbitClassifications")["LEO"]("EccentricityMax").AsDouble() << "\n";
                        

Type INT

These attributes are for integer values (min/max constraint may apply).

COM

VBScript
scen.Filter("Filter1").Restart.MaxRecordsInFile = 200
maxrec = scen.Filter("Filter1").Restart.MaxRecordsInFile
JScript
scen.Filter("Filter1").Restart.MaxRecordsInFile = 200;
var maxrec = scen.Filter("Filter1").Restart.MaxRecordsInFile;
Perl
$scen->Filter("Filter1")->Restart->{MaxRecordsInFile} = 200;
$maxrec = $scen->Filter("Filter1")->Restart->MaxRecordsInFile->{Value};
Python
scen.Filter("Filter1").Restart.MaxRecordsInFile = 200
maxrec = scen.Filter("Filter1").Restart.MaxRecordsInFile
MATLAB
scen.invoke('Filter').invoke('Filter1').invoke('Restart').set('MaxRecordsInFile', 200);
maxrec = scen.invoke('Filter').invoke('Filter1').invoke('Restart').invoke('MaxRecordsInFile').invoke('Value');

Cross-Platform API

Python
scenario.Measurements.LookAheadBufferSize = 200
look_ahead_buffer_size = scenario.Measurements.LookAheadBufferSize.eval()
print(f'Measurements look ahead buffer size: {look_ahead_buffer_size}')
                
MATLAB
scenario.Measurements.LookAheadBufferSize = 200;
lookAheadBufferSize = scenario.Measurements.LookAheadBufferSize;
fprintf("Measurements look ahead buffer size: %i\n", lookAheadBufferSize);
                
C++
scenario("Measurements")("LookAheadBufferSize").Assign(200);
std::cout << "Measurements look ahead buffer size: " << scenario("Measurements")("LookAheadBufferSize").AsInt() << "\n";

                

Type BOOL

Boolean attributes accept values of true and false (false =0, true = 1):

COM

VBScript
scen.Filter("Filter1").Output.SmootherData.Generate = true
genflag = scen.Filter("Filter1").Output.SmootherData.Generate
JScript
scen.Filter("Filter1").Output.SmootherData.Generate = true;
var genflag = scen.Filter("Filter1").Output.SmootherData.Generate;
Perl
$scen->Filter("Filter1")->Output->SmootherData->{Generate} = 1;
$genflag = $scen->Filter("Filter1")->Output->SmootherData->Generate->{Value};
Python
scen.Filter("Filter1").Output.SmootherData.Generate = True
genflag = scen.Filter("Filter1").Output.SmootherData.Generate
MATLAB
scen.invoke('Filter').invoke('Filter1').invoke('Output').invoke('SmootherData').set('Generate', true);
genflag = scen.invoke('Filter').invoke('Filter1').invoke('Output').invoke('SmootherData').invoke('Generate').invoke('Value');

Cross-Platform API

Python
filter1 = scenario.Filter['Filter1']
filter1.Output.SmootherData.Generate = True
generate = filter1.Output.SmootherData.Generate.eval()
print(f'Generate: {generate}')
        
MATLAB
filter1 = scenario.Filter{"Filter1"};
filter1.Output.SmootherData.Generate = true;
generate = filter1.Output.SmootherData.Generate;
fprintf("Generate: %s\n", string(generate));
                
C++
const agi::odtk::AttrProxy filter1 = scenario("Filter")["Filter1"];
filter1("Output")("SmootherData")("Generate").Assign(true);
std::cout << "Generate: " << BoolToString(filter1("Output")("SmootherData")("Generate").AsBool()) << "\n";
                

Type STRING

An example of a string is a "Description" field available on all ODTK objects:

COM

VBScript
scen.Description = "This is an example ..."
str = scen.Description
JScript
scen.Description = "This is an example ...";
var str = scen.Description;
Perl
$scen->{Description} = "This is an example ...";
$str = $scen->Description->{Value};
Python
scen.Description = "This is an example ..."
str = scen.Description
MATLAB
scen.set('Description', 'This is an example ...');
str = scen.invoke('Description').invoke('Value');

Cross-Platform API

Python
scenario.Description = 'This is an example ...'
scenario_description = scenario.Description.eval()
print(f'Scenario description: {scenario_description}')
                
MATLAB
scenario.Description = "This is an example ...";
scenarioDescription = scenario.Description;
fprintf("Scenario description: %s\n", scenarioDescription);
                
C++
scenario("Description").Assign("This is an example ...");
std::cout << "Scenario description: " << scenario("Description").AsString() << "\n";
                

Type STRING ENUMERATION

This type of STRING attribute can only accept a specific pre-defined set of values. For instance, Filter.StartMode can be either "Initial", "Restart", or "AutoRestart".

COM

VBScript
if scen.Filter("Filter1").ProcessControl.StartMode = "Initial" then
    scen.Filter("Filter1").ProcessControl.StartMode = "AutoRestart"
end if
JScript
if (scen.Filter("Filter1").ProcessControl.StartMode == "Initial")
{
    scen.Filter("Filter1").ProcessControl.StartMode = "AutoRestart";
}
Perl
if ($scen->Filter("Filter1")->ProcessControl->StartMode->{Value} eq "Initial" )
{
    $scen->Filter("Filter1")->ProcessControl->{StartMode} = "AutoRestart";
}
Python
if scen.Filter("Filter1").ProcessControl.StartMode.value == "Initial":
    scen.Filter("Filter1").ProcessControl.StartMode = "AutoRestart"
MATLAB
If strcmp(scen.invoke('Filter').invoke('Filter1').invoke('ProcessControl').invoke('StartMode').invoke('Value'), 'Initial')
    scen.invoke('Filter').invoke('Filter1').invoke('ProcessControl').set('StartMode', 'AutoRestart')
end

Cross-Platform API

Python
if filter1.ProcessControl.StartMode.eval() == 'Initial':
    filter1.ProcessControl.StartMode = 'AutoRestart'
print(f'Filter process control start mode: {filter1.ProcessControl.StartMode.eval()}')
            
MATLAB
if filter1.ProcessControl.StartMode == "Initial"
    filter1.ProcessControl.StartMode = "AutoRestart";
end
fprintf("Filter process control start mode: %s\n", filter1.ProcessControl.StartMode);
            
C++
if (filter1("ProcessControl")("StartMode").AsString() == "Initial")
{
    filter1("ProcessControl")("StartMode").Assign("AutoRestart");
}
std::cout << "Filter process control start mode: " << filter1("ProcessControl")("StartMode").AsString() << "\n";
        

To get the list of valid enumeration choices you can right-click on the attribute and open the Attribute Information dialog or use the Scripting Tool's "Props" function:

Attribute Choices

Alternatively, you can retrieve the list in your script via the Choices() property.

COM

VBScript
set proc = scen.Filter(0).ProcessControl
for each sChoice in proc.StartMode.Choices
   MsgBox sChoice
next
proc.StartMode = proc.StartMode.Choices(0) ' sets AutoRestart mode
JScript
var Shell = new ActiveXObject("WScript.Shell");
var proc = scen.Filter(0).ProcessControl;
var i;
for(i = 0; i < proc.StartMode.Choices.Count; i++)
{
   Shell.Popup(proc.StartMode.Choices(i));
}
proc.StartMode = proc.StartMode.Choices(0) // sets AutoRestart mode
Perl
$proc = $scen->Filter(0)->ProcessControl;
$coll = $proc->StartMode->Choices;
foreach $sChoice ( in $coll)
{
   Win32::MsgBox "$sChoice";
}
$proc->{StartMode} = $proc->StartMode->Choices(0)->{Value};
                    
Python
proc = scen.Filter(0).ProcessControl
for sChoice in proc.StartMode.Choices:
    print(sChoice)
proc.StartMode = proc.StartMode.Choices(0)
MATLAB
proc = scen.invoke('Filter').invoke('Item', 0).invoke('ProcessControl');

coll = proc.invoke('StartMode').invoke('Choices');
size = coll.invoke('Size').invoke('Value');
for i = 0:size - 1
    choice = coll.invoke('Item', i);
    fprintf('%s\n', choice.invoke('Value'));
end;
proc.set('StartMode', proc.invoke('StartMode').invoke('Choices').invoke('Item', 0));

One special case of the string enumeration is the SelectedRestartTime for a filter or simulator. The choices in this case change based on each filter or simulator run, and the choices contain a list of date/time strings with units of UTCG or GPSG. The units are determined by the scenario date units setting scen.Units.DateFormat. When setting the SelectedRestartTime in a script, any of the following formats will work ? if no units are defined, the input date string will be assumed to be in the scenario units. If the restart time that you set is not a valid restart time, then the SelectedRestartTime will not be set.

COM

VBScript
set fil = scen.Filter(0)
MsgBox "Scenario default units are: " & scen.Units.DateFormat
fil.ProcessControl.SelectedRestartTime = "1 Jan 2006 00:10:00.000 UTCG"
fil.ProcessControl.SelectedRestartTime = "1 Jan 2006 00:10:00"
JScript
var Shell = new ActiveXObject("WScript.Shell");
var fil = scen.Filter(0);
Shell.Popup("Scenario default units are: " + scen.Units.DateFormat);
fil.ProcessControl.SelectedRestartTime = "1 Jan 2006 00:10:00.000 UTCG";
fil.ProcessControl.SelectedRestartTime = "1 Jan 2006 00:10:00";
Perl
my $fil   = $scen->Filter(0);
my $units = $scen->Units->DateFormat->{Value};
Win32::MsgBox "Scenario default units are: $units";
$fil->ProcessControl->{SelectedRestartTime} = "1 Jul 2006 13:00:00.000 UTCG";
$fil->ProcessControl->{SelectedRestartTime} = "1 Jul 2006 13:00:00";
Python
fil = scen.Filter(0)
print("Scenario default units are: " + str(scen.Units.DateFormat))
fil.ProcessControl.SelectedRestartTime = "1 Jan 2006 00:10:00.000 UTCG"
fil.ProcessControl.SelectedRestartTime = "1 Jan 2006 00:10:00"
MATLAB
fil = scen.invoke('Filter').invoke('Item', 0);

units = scen.invoke('Units').invoke('DateFormat').invoke('Value');
fprintf('Scenario default units are: %s', units);

fil.invoke('ProcessControl').set('SelectedRestartTime', '1 Jul 2008 13:00:00.000 UTCG');
fil.invoke('ProcessControl').set('SelectedRestartTime', '1 Jul 2008 13:00:00.000');

Cross-Platform API

Python
simulator = odtk.application.createObj(scenario, 'Simulator', 'Simulator1')
tracking_system = odtk.application.createObj(scenario, 'TrackingSystem', 'TrackingSystem1')
facility = odtk.application.createObj(tracking_system, 'Facility', 'Facility1')

if not simulator.Go():
    print('Simulator run failed.')
    exit()
filter1.ProcessControl.StartMode = 'Initial'
if not filter1.Go():
    print('Filter run failed.')
    exit()

last_selected_restart_time = ''
print('Selected restart time choices')
for selected_restart_time in filter1.ProcessControl.SelectedRestartTime.Choices:
    last_selected_restart_time = selected_restart_time.eval()
    print(f'   {last_selected_restart_time}')

print(f'Scenario default units are: {scenario.Units.DateFormat.eval()}')
print('SelectedRestartTime will be set to ' + last_selected_restart_time)
filter1.ProcessControl.SelectedRestartTime = last_selected_restart_time
print(f'SelectedRestartTime was set to {filter1.ProcessControl.SelectedRestartTime.eval()}')
        
MATLAB
simulator = odtk.application.createObj(scenario, "Simulator", "Simulator1");
trackingSystem = odtk.application.createObj(scenario, "TrackingSystem", "TrackingSystem1");
facility = odtk.application.createObj(trackingSystem, "Facility", "Facility1");

if ~simulator.Go()
    fprintf("Simulator run failed.\n");
    exit();
end
filter1.ProcessControl.StartMode = "Initial";
if ~filter1.Go()
    fprintf("Filter run failed.\n")
    exit();
end

lastSelectedRestartTime = "";
selectedRestartTimesChoices = filter1.ProcessControl.SelectedRestartTime.Choices;
fprintf("Selected restart time choices\n");
for i = 0: selectedRestartTimesChoices.Count-1
    lastSelectedRestartTime = selectedRestartTimesChoices{i};
    fprintf("   %i. %s\n", i, lastSelectedRestartTime);
end

fprintf("Scenario default units are: %s\n", scenario.Units.DateFormat);
fprintf("SelectedRestartTime will be set to %s\n", lastSelectedRestartTime);
filter1.ProcessControl.SelectedRestartTime = lastSelectedRestartTime;
fprintf("SelectedRestartTime was set to %s\n", filter1.ProcessControl.SelectedRestartTime);

            
C++
const agi::odtk::AttrProxy startModeChoices = filter1("ProcessControl")("StartMode")("Choices");
std::cout << "Start mode choices\n";
for (int i = 0; i < startModeChoices("Count").AsInt(); ++i)
{
    std::cout << "  " << i << ". " << startModeChoices[i].AsString() << "\n";
}

// One special case of the string enumeration is the SelectedRestartTime for a filter or simulator.
// The choices in this case change based on each filter or simulator run, and the choices contain a list of date / time
// strings with units of UTCG or GPSG.The units are determined by the scenario date units setting
// scenario.Units.DateFormat.
// When setting the SelectedRestartTime in a script, any of the following formats will work; if no units are defined,
// the input date string will be assumed to be in the scenario units.If the restart time that you set is not a valid
// restart time, then the SelectedRestartTime will not be set.

const auto simulator = odtk("application")("createObj").InvokeAttrProxy(scenario, "Simulator", "Simulator1");
const auto trackingSystem = odtk("application")("createObj").InvokeAttrProxy(scenario, "TrackingSystem", "TrackingSystem1");
const auto facility = odtk("application")("createObj").InvokeAttrProxy(trackingSystem, "Facility", "Facility1");

if (!simulator("Go").InvokeBool())
{
    std::cout << "Simulator run failed.\n";
    return;
}
filter1("ProcessControl")("StartMode").Assign("Initial");
if (!filter1("Go").InvokeBool())
{
    std::cout << "Filter run failed.\n";
    return;
}

std::string lastSelectedRestartTime;
const agi::odtk::AttrProxy selectedRestartTimesChoices = filter1("ProcessControl")("SelectedRestartTime")("Choices");
std::cout << "Selected restart time choices\n";
for (int i = 0; i < selectedRestartTimesChoices("Count").AsInt(); ++i)
{
    lastSelectedRestartTime = selectedRestartTimesChoices[i].AsString();
    std::cout << "   " << i << ". " << lastSelectedRestartTime << "\n";
}

std::cout << "Scenario default units are: " << scenario("Units")("DateFormat").AsString() << "\n";
std::cout <<"SelectedRestartTime will be set to " << lastSelectedRestartTime << "\n";
filter1("ProcessControl")("SelectedRestartTime").Assign(lastSelectedRestartTime);
std::cout << "SelectedRestartTime was set to " << filter1("ProcessControl")("SelectedRestartTime").AsString() << "\n";
            

Compound Types

OD Tool Kit uses a number of compound types that have special methods for handling Units, Dimensions, Date representations, and coordinate system transformations as well as standard containers such as lists and sets.

Type QUANTITY

Quantities are values that have an associated unit, such as: 1 sec, 5 km, and 3 rad/sec. Several methods and properties are available to work with the quantity attributes.

The properties Unit and Dimension return the default unit and dimension:

COM

VBScript
MsgBox "Unit: "      & scen.Filter(0).ProcessControl.TimeSpan.Unit
MsgBox "Dimension: " & scen.Filter(0).ProcessControl.TimeSpan.Dimension
JScript
var Shell = new ActiveXObject("WScript.Shell");
Shell.Popup("Unit: "      + scen.Filter(0).ProcessControl.TimeSpan.Unit);
Shell.Popup("Dimension: " + scen.Filter(0).ProcessControl.TimeSpan.Dimension);
Perl
my $unit = $scen->Filter(0)->ProcessControl->TimeSpan->Unit->{Value};
my $dim  = $scen->Filter(0)->ProcessControl->TimeSpan->Dimension->{Value};
Win32::MsgBox "Unit: $unit";
Win32::MsgBox "Dimension: $dim";
Python
print("Unit: " + str(scen.Filter(0).ProcessControl.TimeSpan.Unit))
print("Dimension: " + str(scen.Filter(0).ProcessControl.TimeSpan.Dimension))
MATLAB
proc = scen.invoke('Filter').invoke('Item', 0).invoke('ProcessControl');
unit = proc.invoke('TimeSpan').invoke('Unit').invoke('Value');
dim  = proc.invoke('TimeSpan').invoke('Dimension').invoke('Value');
fprintf('Unit: %s\nDimension: %s\n', unit, dim);

Cross-Platform API

Python
print(f'Unit: {filter1.ProcessControl.TimeSpan.Unit.eval()}')
print(f'Dimension: {filter1.ProcessControl.TimeSpan.Dimension.eval()}')
            
MATLAB
fprintf("Unit: %s\n", filter1.ProcessControl.TimeSpan.Unit);
fprintf("Dimension: %s\n", filter1.ProcessControl.TimeSpan.Dimension);
            
C++
std::cout << "Unit: " << filter1("ProcessControl")("TimeSpan")("Unit").AsString() << "\n";
std::cout << "Dimension: " << filter1("ProcessControl")("TimeSpan")("Dimension").AsString() << "\n";
            

The methods GetIn() and Set() perform unit conversion based on the input unit.

COM

VBScript
scen.Filter(0).ProcessControl.TimeSpan.Set 4, "min"
MsgBox scen.Filter(0).ProcessControl.TimeSpan.GetIn("min") & " min"
MsgBox scen.Filter(0).ProcessControl.TimeSpan.GetIn("sec") & " sec"
JScript
var Shell = new ActiveXObject("WScript.Shell");
scen.Filter(0).ProcessControl.TimeSpan.Set(4, "min");
Shell.Popup(scen.Filter(0).ProcessControl.TimeSpan.GetIn("min") + " min");
Shell.Popup(scen.Filter(0).ProcessControl.TimeSpan.GetIn("sec") + " sec");
Perl
$scen->Filter(0)->ProcessControl->TimeSpan->Set(4, "min");
my $mins = $scen->Filter(0)->ProcessControl->TimeSpan->GetIn("min")->{Value};
Win32::MsgBox "$mins min";
my $secs = $scen->Filter(0)->ProcessControl->TimeSpan->GetIn("sec")->{Value};
Win32::MsgBox "$secs sec";
Python
scen.Filter(0).ProcessControl.TimeSpan.Set(4, "min")
print(str(scen.Filter(0).ProcessControl.TimeSpan.GetIn("min")) + " min")
print(str(scen.Filter(0).ProcessControl.TimeSpan.GetIn("sec")) + " sec")
                    
MATLAB
proc = scen.invoke('Filter').invoke('Item', 0).invoke('ProcessControl');
proc.invoke('TimeSpan').invoke('Set', 4, 'min');
mins = proc.invoke('TimeSpan').invoke('GetIn', 'min').invoke('Value');
secs = proc.invoke('TimeSpan').invoke('GetIn', 'sec').invoke('Value');
fprintf('%f mins\n%f secs\n', mins, secs);
                    

Cross-Platform API

Python
filter1.ProcessControl.TimeSpan.Set(4, 'min')
print(f'{filter1.ProcessControl.TimeSpan.GetIn("min")} min')
print(f'{filter1.ProcessControl.TimeSpan.GetIn("sec")} sec')
            
MATLAB
filter1.ProcessControl.TimeSpan.Set(4, 'min');
fprintf("%f min\n", filter1.ProcessControl.TimeSpan.GetIn("min"));
fprintf("%f sec\n", filter1.ProcessControl.TimeSpan.GetIn("sec"));

            
C++
filter1("ProcessControl")("TimeSpan")("Set").Invoke(4, "min");
std::cout << filter1("ProcessControl")("TimeSpan")("GetIn").InvokeDouble("min") << " min\n";
std::cout << filter1("ProcessControl")("TimeSpan")("GetIn").InvokeDouble("sec") << " sec\n";
            

Note that even though the following will work, it is unsafe to assume the default unit.

COM

VBScript
scen.Filter(0).ProcessControl.TimeSpan = 24   ' Do not assume unit!!!
MsgBox scen.Filter(0).ProcessControl.TimeSpan ' Defaults may change!!!
JScript
var Shell = new ActiveXObject("WScript.Shell");
scen.Filter(0).ProcessControl.TimeSpan = 24;   // Do not assume unit!!!
Shell.Popup(scen.Filter(0).ProcessControl.TimeSpan); // Defaults may change!!!
Python
scen.Filter(0).ProcessControl.TimeSpan = 24   # Do not assume unit!!!
print(scen.Filter(0).ProcessControl.TimeSpan) # Defaults may change!!!
                    

We can also get the internal value with the function GetInternal, which is likely to be in different units than the default input/output units. As we fine-tune the application internal units may change from version to version. Avoid using this function.

In addition to working with one of the scenario object quantities you can create a new quantity object with the ODTK.NewQuantity() function. The returned quantity object can be either assigned to one of the existing attributes or used to perform a unit conversion.

COM

VBScript
set temp = ODTK.NewQuantity(2,"arcSec")
set trkSys = scen.TrackingSystem("TrkSys1")
trkSys.Facility("Facility1").MeasurementStatistics(2).Type.Bias = temp
trkSys.IonosphereModel.TransmitFreq = ODTK.NewQuantity(2100,"MHz")
MsgBox ODTK.NewQuantity(100,"mi/hr").GetIn("km/sec")
JScript
var Shell = new ActiveXObject("WScript.Shell");
var temp = ODTK.NewQuantity(2,"arcSec");
var trkSys = scen.TrackingSystem("TrkSys1");
trkSys.Facility("Facility1").MeasurementStatistics(2).Type.Bias = temp;
trkSys.IonosphereModel.TransmitFreq = ODTK.NewQuantity(2100,"MHz");
Shell.Popup(ODTK.NewQuantity(100,"mi/hr").GetIn("km/sec"));
Perl
my $temp = $ODTK->NewQuantity(2,"arcSec");
my $trkSys = $scen->TrackingSystem("TrkSys1");
$trkSys->Facility("Facility1")->MeasurementStatistics(2)->Type->Bias->Assign($temp);
$trkSys->IonosphereModel->TransmitFreq->Assign($ODTK->NewQuantity(2100,"MHz"));
my $kmsec = $ODTK->NewQuantity(100,"mi/hr")->GetIn("km/sec")->{Value};
Win32::MsgBox $kmsec;
Python
temp = ODTK.NewQuantity(2,"arcSec")
trkSys = scen.TrackingSystem("TrkSys1")
trkSys.Facility("Facility1").MeasurementStatistics(2).Type.Bias = temp
trkSys.IonosphereModel.TransmitFreq = ODTK.NewQuantity(2100,"MHz")
print(ODTK.NewQuantity(100,"mi/hr").GetIn("km/sec"))
MATLAB
temp = odtk.invoke('NewQuantity', 2, 'arcSec');
trkSys = scen.invoke('TrackingSystem').invoke('TrkSys1');
trkSys.invoke('Facility').invoke('Facility1').invoke('MeasurementStatistics').invoke('Item', 2).invoke('Type').invoke('Bias').invoke('Assign', temp);
trkSys.invoke('IonosphereModel').invoke('TransmitFreq').invoke('Assign' , odtk.invoke('NewQuantity', 2100, 'MHz'));
mph = odtk.invoke('NewQuantity', 100, 'mi/hr');
mpsec = mph.invoke('GetIn', 'm/sec').invoke('Value');
fprintf('%f\n', mpsec);

When using VBScript it is very important to use the "set" keyword when saving return values from the NewQuantity function. "set" ensures that you save a handle to the Quantity object. Without the "set" keyword VBScript will retrieve the CDbl value of the Quantity value:

X = ODTK.NewQuantity(100,"mi/hr")
MsgBox x.GetIn("km/sec") ' This generates a run-time error: x is CDbl

Cross-Platform API

Python
temp = odtk.NewQuantity(2, 'arcSec')
facility.MeasurementStatistics[2].Type.Bias = temp
tracking_system.IonosphereModel.TransmitFreq = odtk.NewQuantity(2100, 'MHz')
qty = odtk.NewQuantity(100, 'mi/hr')
kmSecQty = qty.GetIn('km/sec')
print(f'qty: {kmSecQty} km/sec')
            
MATLAB
temp = odtk.NewQuantity(2, "arcSec");
facility.MeasurementStatistics{2}.Type.Bias = temp;
trackingSystem.IonosphereModel.TransmitFreq = odtk.NewQuantity(2100, "MHz");
qty = odtk.NewQuantity(100, "mi/hr");
fprintf("Quantity: %f km/sec\n", qty.GetIn("km/sec"));
            
C++
const agi::odtk::AttrProxy temp = odtk("NewQuantity").InvokeAttrProxy(2, "arcSec");
facility("MeasurementStatistics")[2]("Type")("Bias").Assign(temp);
trackingSystem("IonosphereModel")("TransmitFreq").Assign(odtk("NewQuantity").InvokeAttrProxy(2100, "MHz"));
const agi::odtk::AttrProxy qty = odtk("NewQuantity").InvokeAttrProxy(100, "mi/hr");
std::cout << "Quantity: " << qty("GetIn").InvokeDouble("km/sec") << " km/sec\n";
            

Type DATE

Date Format

Dates are treated similarly to Quantities. They have a Set() method to assign a value and a Format() method to retrieve the DateTime string in a specified format. To see available date formats click on the icon while editing any Date field. You can create a new Date object using the ODTK.NewDate() function. The first parameter is the value or string containing the date, the second parameter is one of the standard ODTK date formats.

COM

VBScript
set jd1 = ODTK.NewDate(1, "JDate")
MsgBox "1 JD:" & jd1.Format("UTCG")
JScript
var Shell = new ActiveXObject("WScript.Shell");
var jd1 = ODTK.NewDate(1, "JDate");
Shell.Popup("1 JD:" + jd1.Format("UTCG"));
Perl
my $jd1 = $ODTK->NewDate(1, "JDate");
my $utc = $jd1->Format("UTCG")->{Value};
Win32::MsgBox "1 JD = $utc";
Python
jd1 = ODTK.NewDate(1, "JDate")
print("1 JD:" + str(jd1.Format("UTCG")))
MATLAB
jd1 = odtk.invoke('NewDate', 1, 'JDate');
utc = jd1.invoke('Format', 'UTCG').invoke('Value');
fprintf('1 JD: %s\n',  utc);

Cross-Platform API

Python
jd1 = odtk.NewDate(1, 'JDate')
utcgDate = jd1.Format('UTCG')
print(f'JDate: {utcgDate}')
                
MATLAB
jd1 = odtk.NewDate(1, "JDate");
fprintf("JDate: %s\n", jd1.Format("UTCG"));
            
C++
const agi::odtk::AttrProxy jd1 = odtk("NewDate").InvokeAttrProxy(1, "JDate");
std::cout << "JDate: " << jd1("Format").InvokeString("UTCG") << "\n";
            

As with the Quantity object, make sure to use the "set" with VBScript or you will get an undefined behavior.

The Set() function returns a handle to the Date object that is being modified. The input parameters are the same as the NewDate function.

COM

VBScript
set s = scen.Filter("Filter1").ProcessControl.StartTime.Set(1,"JDate")
MsgBox  scen.Filter("Filter1").ProcessControl.StartTime.Format("GPSG")
JScript
var Shell = new ActiveXObject("WScript.Shell");
var s = scen.Filter("Filter1").ProcessControl.StartTime.Set(1,"JDate");
Shell.Popup(scen.Filter("Filter1").ProcessControl.StartTime.Format("GPSG"));
Perl
$scen->Filter("Filter1")->ProcessControl->StartTime->Set(1,"JDate");
my $gpsg = $scen->Filter("Filter1")->ProcessControl->StartTime->Format("GPSG")->{Value};
Win32::MsgBox $gpsg;
Python
s = scen.Filter("Filter1").ProcessControl.StartTime.Set(1,"JDate")
print(scen.Filter("Filter1").ProcessControl.StartTime.Format("GPSG"))
MATLAB
proc  = scen.invoke('Filter').invoke('Filter1').invoke('ProcessControl');
proc.invoke('StartTime').invoke('Set', 1, 'JDate');
gpsg = proc.invoke('StartTime').invoke('Format', 'GPSG').invoke('Value');
fprintf('%s\n', gpsg);

Cross-Platform API

Python
filter1.ProcessControl.StartTime.Set(1, 'JDate')
start_time = filter1.ProcessControl.StartTime.Format('GPSG')
print(f'Start time: {start_time}')

            
MATLAB
filter1.ProcessControl.StartTime.Set(1, "JDate");
fprintf("JDate: %s\n", filter1.ProcessControl.StartTime.Format("GPSG"));
            
C++
filter1("ProcessControl")("StartTime")("Set").Invoke(1, "JDate");
std::cout << "JDate: " << filter1("ProcessControl")("StartTime")("Format").InvokeString("GPSG") << "\n";
            

ODTK's Date object also implements three Date Time arithmetic methods, AddTime, SubtractTime, and SubtractDate.

COM

VBScript
set d1 = scen.Filter("Filter1").ProcessControl.StartTime
set d2 = scen.Filter("Filter1").ProcessControl.StopTime
set d3 = d1.AddTime(      ODTK.NewQuantity(1,"hr" ) )
set d4 = d2.SubtractTime( ODTK.NewQuantity(5,"min") )
set timeSpan = d4.SubtractDate(d3)

MsgBox timeSpan.GetIn("min")
JScript
var Shell = new ActiveXObject("WScript.Shell");
var d1 = scen.Filter("Filter1").ProcessControl.StartTime;
var d2 = scen.Filter("Filter1").ProcessControl.StopTime;
var d3 = d1.AddTime(      ODTK.NewQuantity(1,"hr" ) );var d4 = d2.SubtractTime( ODTK.NewQuantity(5,"min") );
var timeSpan = d4.SubtractDate(d3);
Shell.Popup(timeSpan.GetIn("min"));
Perl
my $d1 = $scen->Filter("Filter1")->ProcessControl->StartTime;
my $d2 = $scen->Filter("Filter1")->ProcessControl->StopTime;
my $d3 = $d1->AddTime(      $ODTK->NewQuantity(1,"hr" ) );
my $d4 = $d2->SubtractTime( $ODTK->NewQuantity(5,"min") );
my $timeSpan = $d4->SubtractDate($d3);
my $ts = $timeSpan->GetIn("min")->{Value}; Win32::MsgBox $ts;
Python
d1 = scen.Filter("Filter1").ProcessControl.StartTime
d2 = scen.Filter("Filter1").ProcessControl.StopTime
d3 = d1.AddTime(ODTK.NewQuantity(1,"hr" ))
d4 = d2.SubtractTime(ODTK.NewQuantity(5,"min"))
timeSpan = d4.SubtractDate(d3)

print(timeSpan.GetIn("min"))
MATLAB
d1 = scen.invoke('Filter').invoke('Filter1').invoke('ProcessControl').invoke('StartTime');
d2 = scen.invoke('Filter').invoke('Filter1').invoke('ProcessControl').invoke('StopTime');
d3 = d1.invoke('AddTime',      odtk.invoke('NewQuantity', 1, 'hr' ));
d4 = d2.invoke('SubtractTime', odtk.invoke('NewQuantity', 5, 'min'));
timeSpan = d4.invoke('SubtractDate', d3);
ts = timeSpan.invoke('GetIn', 'min').invoke('Value'); fprintf('%f\n', ts);

Cross-Platform API

Python
d1 = filter1.ProcessControl.StartTime
d2 = filter1.ProcessControl.StopTime
d3 = d1.AddTime(odtk.NewQuantity(1, 'hr'))
d4 = d2.SubtractTime(odtk.NewQuantity(5, 'min'))
timeSpan = d4.SubtractDate(d3)
timeSpanMin = timeSpan.GetIn('min')
print(f'Time span: {timeSpanMin} min')
            
MATLAB
d1 = filter1.ProcessControl.StartTime;
d2 = filter1.ProcessControl.StopTime;
d3 = d1.AddTime(odtk.NewQuantity(1, "hr"));
d4 = d2.SubtractTime(odtk.NewQuantity(5, "min"));
timeSpan = d4.SubtractDate(d3);
fprintf("Timespan: %f min\n", timeSpan.GetIn('min'));
            
C++
const agi::odtk::AttrProxy d1 = filter1("ProcessControl")("StartTime");
const agi::odtk::AttrProxy d2 = filter1("ProcessControl")("StopTime");
const agi::odtk::AttrProxy d3 = d1("AddTime").InvokeAttrProxy(odtk("NewQuantity").InvokeAttrProxy(1, "hr"));
const agi::odtk::AttrProxy d4 = d2("SubtractTime").InvokeAttrProxy(odtk("NewQuantity").InvokeAttrProxy(5, "min"));
const agi::odtk::AttrProxy timeSpan = d4("SubtractDate").InvokeAttrProxy(d3);
std::cout << "Timespan: " << timeSpan("GetIn").InvokeDouble("min") << " min\n";
            

In addition to arithmetic functions, these functions allow date comparison:

Equals(), GreaterThan(), GreaterThanOrEqual(),
Inequality(), LessThan(), LessThanOrEqual()

They return a Boolean and can be used to test dates as follows:

COM

VBScript
set t1 = scen.Simulator(0).ProcessControl.StartTime
set t2 = scen.Filter(0).ProcessControl.StartTime
if t1.GreaterThan(t2) then
    MsgBox "Greater than"
end if
if t1.Equals(t2) then
    MsgBox "Equal"
end if
if t1.LessThanOrEqual(t2) then
    MsgBox "Less than or equal"
end if
JScript
var Shell = new ActiveXObject("WScript.Shell");
var t1 = scen.Simulator(0).ProcessControl.StartTime;
var t2 = scen.Filter(0).ProcessControl.StartTime;
if(t1.GreaterThan(t2).value)
    Shell.Popup("Greater than");
if(t1.Equals(t2).value)
    Shell.Popup("Equal");
if(t1.LessThanOrEqual(t2).value)
    Shell.Popup("Less than or equal");
                    
Perl
my $t1 = $scen->Simulator(0)->ProcessControl->StartTime;
my $t2 = $scen->Filter(0)->ProcessControl->StartTime;
if ($t1->GreaterThan($t2)->{Value})
{
    Win32::MsgBox("Greater than");
}
if ($t1->Equals($t2)->{Value})
{
    Win32::MsgBox("Equal");
}
if ($t1->LessThanOrEqual($t2)->{Value})
{
    Win32::MsgBox("Less than or equal");
}
Python
t1 = scen.Simulator(0).ProcessControl.StartTime
t2 = scen.Filter(0).ProcessControl.StartTime
if t1.GreaterThan(t2).value:
    print("Greater than")
if t1.Equals(t2).value:
    print("Equal")
if t1.LessThanOrEqual(t2).value:
    print("Less than or equal")

MATLAB
t1 = scen.invoke('Simulator').invoke('Item', 0).invoke('ProcessControl').invoke('StartTime');
t2 = scen.invoke('Filter').invoke('Item', 0).invoke('ProcessControl').invoke('StartTime');

if (t1.invoke('GreaterThan', t2).invoke('Value'))
    fprintf('Greater than\n');
end
if (t1.invoke('Equals', t2).invoke('Value'))
    fprintf('Equal\n');
end
if (t1.invoke('LessThanOrEqual', t2).invoke('Value'))
    fprintf('Less than or equal\n');
end

Cross-Platform API

Python
t1 = simulator.ProcessControl.StartTime
t2 = filter1.ProcessControl.StartTime

t1_utcg = t1.Format('UTCG')
print(f't1: {t1_utcg}')
t2_utcg = t2.Format('UTCG')
print(f't2: {t2_utcg}')
if t1.GreaterThan(t2):
    print('t1 > t2')
if t1.GreaterThanOrEqual(t2):
    print('t1 >= t2')
if t1.GreaterThanOrEqual(t1):
    print('t1 >= t1')
if t1.LessThanOrEqual(t1):
    print('t1 <= t1')
if t1.Equals(t1):
    print('t1 == t1')
if t1.Inequality(t2):
    print('t1 != t2')
if t2.LessThan(t1):
    print('t2 < t1')
if t2.LessThanOrEqual(t1):
    print('t2 <= t1')
            
MATLAB
t1 = simulator.ProcessControl.StartTime;
t2 = filter1.ProcessControl.StartTime;

fprintf("t1: %s\n", t1.Format('UTCG'));
fprintf("t2: %s\n", t2.Format('UTCG'));
if t1.GreaterThan(t2)
    fprintf("t1 > t2\n");
end
if t1.GreaterThanOrEqual(t2)
    fprintf("t1 >= t2\n");
end
if t1.GreaterThanOrEqual(t1)
    fprintf("t1 >= t1\n")
end
if t1.LessThanOrEqual(t1)
    fprintf("t1 <= t1\n")
end
if t1.Equals(t1)
    fprintf("t1 == t1\n")
end
if t1.Inequality(t2)
    fprintf("t1 != t2\n")
end
if t2.LessThan(t1)
    fprintf("t2 < t1\n")
end
if t2.LessThanOrEqual(t1)
    fprintf("t2 <= t1\n")
end

            
C++
const agi::odtk::AttrProxy t1 = simulator("ProcessControl")("StartTime");
const agi::odtk::AttrProxy t2 = filter1("ProcessControl")("StartTime");

std::cout << "t1: " << t1("Format").InvokeString("UTCG") << "\n";
std::cout << "t2: " << t2("Format").InvokeString("UTCG") << "\n";
if (t1("GreaterThan").InvokeBool(t2))
{
    std::cout << "t1 > t2\n";
}
if (t1("GreaterThanOrEqual").InvokeBool(t2))
{
    std::cout << "t1 <= t2\n";
}
if (t1("GreaterThanOrEqual").InvokeBool(t1))
{
    std::cout << "t1 <<= t1\n";
}
if (t1("LessThanOrEqual").InvokeBool(t1))
{
    std::cout << "t1 <= t1\n";
}
if (t1("Equals").InvokeBool(t1))
{
    std::cout << "t1 == t1\n";
}
if (t1("Inequality").InvokeBool(t2))
{
    std::cout << "t1 != t2\n";
}
if (t2("LessThan").InvokeBool(t1))
{
    std::cout << "t2 < t1\n";
}
if (t2("LessThanOrEqual").InvokeBool(t1))
{
    std::cout << "t2 <= t1\n";
}
                        

Date objects are often useful when converting date and time formats from other software or systems. At times it's useful to start up ODTK and use it as a crude data conversion utility! Sometimes the input format is not one that ODTK natively supports. However, a little judicious string manipulation can often reorganize the input date and time into something that ODTK can handle. For example, you may have a date and time format that consists of the year and the elapsed seconds since the beginning of the year (assumed to be 1 Jan 00:00:00 UTC), e.g. 2009/2560004. You could rely on your own date conversion routines and worry about leap years and leap seconds. Or you could simply pass it into ODTK using something like the following and then request it back out in a different format.

COM

VBScript
set testdate = ODTK.NewDate("1 Jan 2009 00:00:256", "UTCG")
set testdate = ODTK.NewDate("001/2560004 2009",         "GMT" )
JScript
var testdate = ODTK.NewDate("1 Jan 2009 00:00:256", "UTCG");
var testdate = ODTK.NewDate("001/2560004 2009",         "GMT" );
Python
testdate = ODTK.NewDate("1 Jan 2009 00:00:256", "UTCG")
testdate = ODTK.NewDate("001/2560004 2009", "GMT" )

Cross-Plaform API

Python
test_date = odtk.NewDate("1 Jan 2009 00:00:256", "UTCG")
print(f"test_date: {test_date.Format('UTCG')}")
test_date = odtk.NewDate("001/2560004 2009", "GMT")
            
MATLAB
testDate = odtk.NewDate("1 Jan 2009 00:00:256", "UTCG");
fprintf("testDate: %s\n", testDate.Format("UTCG"));
testDate = odtk.NewDate("001/2560004 2009", "GMT");
fprintf("testDate: %s\n", testDate.Format("UTCG"));
            
C++
const agi::odtk::AttrProxy testDate1 = odtk("NewDate").InvokeAttrProxy("1 Jan 2009 00:00:256", "UTCG");
std::cout << "testDate1: " << testDate1("Format").InvokeString("UTCG") << "\n";
const agi::odtk::AttrProxy testDate2 = odtk("NewDate").InvokeAttrProxy("001/2560004 2009", "GMT");
std::cout << "testDate2: " << testDate2("Format").InvokeString("UTCG") << "\n";
            

This trick of using the hour, minute, or second field and putting any value you want in it is perfectly acceptable.

Type LINKTO

File and directory names are strings but they are validated during the assignment. The application makes sure that an input file exists, or an output file can be written. Otherwise it will generate an error and the new value will not be set:

COM

VBScript
scen.EarthDefinition.EOPFilename = "C:\Temp\EOP.txt"
JScript
scen.EarthDefinition.EOPFilename = "C:\\Temp\\EOP.txt";
Perl
$scen->EarthDefinition->{EOPFilename} = "C:\\Temp\\EOP.txt";
Python
scen.EarthDefinition.EOPFilename = "C:\\Temp\\EOP.txt"
MATLAB
scen.invoke('EarthDefinition').set('EOPFilename', 'C:\Temp\EOP.txt');

Cross-Platform API

Python
try
    # set non-existent file
    scenario.EarthDefinition.EOPFilename = 'C:\\Non-Existent-Folder\\none-existent-file.txt'
    raise Exception('The expected exception was not thrown.')
except ClientException as e:
    if e.error_code == ClientExceptionCodes.EXECUTION_ERROR and 'Cannot find file' in str(e):
        print('Non-existent file path threw an exception as expected.')
    else:
        raise Exception('Unexpected exception was raised.')
                    
MATLAB
try
    % set non-existent file
    scenario.EarthDefinition.EOPFilename = "C:\\Non-Existent-Folder\\none-existent-file.txt";
    throw(MException('ScriptingGuide:unexpectedError', 'The expected exception was not thrown.'));
catch ex
    if ex.identifier == ClientExceptionIDs.ExecutionError && contains(ex.message, "Cannot find file")
        fprintf("Non-existent file path threw an exception as expected.\n");
    else
        throw(MException('ScriptingGuide:unexpectedError', 'An unexpected exception was thrown.'));
    end
end
                                    
C++
try
{
    // set non - existent file
    scenario("EarthDefinition")("EOPFilename").Assign("C:\\Non-Existent-Folder\\none-existent-file.txt");
    throw std::runtime_error("The expected exception was not thrown.");
}
catch (const agi::odtk::ClientException& clientException)
{
    if (clientException.ErrorCode == agi::odtk::clientExceptionCodes::ExecutionError && strstr(clientException.what(), "Cannot find file"))
    {
        std::cout << "Non-existent file path threw an exception as expected.\n";
    }
    else
    {
        throw std::runtime_error("An unexpected exception was thrown.");
    }
}
            

Type LINKTO ENUMERATION

Some objects have links to enumerated types such as the solar radiation pressure model or measurement bias model and are identified as having type "LINKTO ENUMERATION". These parameters have an extra attribute "Type" that is used to set and get their values.

COM

VBScript
set sat = scen.Satellite("Satellite1")
sat.ForceModel.SolarPressure.Model.Type = "Spherical"
Msgbox sat.ForceModel.SolarPressure.Model.Type
JScript
var Shell = new ActiveXObject("WScript.Shell");
var sat = scen.Satellite("Satellite1");
sat.ForceModel.SolarPressure.Model.Type = "Spherical";
Shell.Popup(sat.ForceModel.SolarPressure.Model.Type);
Perl
my $sat =$scen->Satellite("Satellite1");
$sat->ForceModel->SolarPressure->Model->{Type} = "Spherical";
print $sat->ForceModel->SolarPressure->Model->{Type};
Python
sat = scen.Satellite("Satellite1")
sat.ForceModel.SolarPressure.Model.Type = "Spherical"
print(sat.ForceModel.SolarPressure.Model.Type)
MATLAB
sat = scen.invoke('Satellte').invoke('Satellite1');
sat.invoke('ForceModel').invoke('SolarPressure').invoke('Model').invoke('Type') = 'Spherical';
fprintf('%s\n', sat.invoke('ForceModel').invoke('SolarPressure').invoke('Model').invoke('Type').invoke('Value'));

Cross-Platform API

Python
satellite.ForceModel.SolarPressure.Model.Type = 'Spherical'
print(f'Solar pressure model: {satellite.ForceModel.SolarPressure.Model.Type.eval()}')

# currently doesn't work with ODTKRuntime (scenario.Measurements.Files is empty)
demonstrate_list = True

            
MATLAB
satellite.ForceModel.SolarPressure.Model.Type = "Spherical";
fprintf("Solar pressure model: %s\n", satellite.ForceModel.SolarPressure.Model.Type);

% currently doesn't work with ODTKRuntime (scenario.Measurements.Files is empty)
demonstrateList = true;

            
C++
const agi::odtk::AttrProxy satellite = scenario[zerothSatelliteName];
satellite("ForceModel")("SolarPressure")("Model")("Type").Assign("Spherical");
std::cout << "Solar pressure model: " << satellite("ForceModel")("SolarPressure")("Model")("Type").AsString() << "\n";

// currently doesn't work with ODTKRuntime (scenario.Measurements.Files is empty)
const bool demonstrateList = true;

            

Type LIST

The List container holds an unordered list of simple types like STRINGs or INTs or compound objects. The easiest way to identify what types of objects are in a list is to add an element through the user interface. The columns in the list identify the names of each of the properties of the elements.

Use the NewElem() method to create a new object that can be added to the list. Actually adding it to the list is accomplished using push_back(ne) or push_front(ne). The entire list can be cleared using clear() and the ith element removed using RemoveAt(i). The number of elements in the list is available using size(). Elements in the list can be accessed by index number or by iterating through the list.

COM

VBScript
set mfiles = ODTK.Scenario(0).Measurements.Files

' Clear the list
set unused = mfiles.clear

' Add a new item to it
dim ne
set ne = mfiles.NewElem()
ne.Enabled  = true
ne.FileName = "C:\Temp\test.geosc"
set unused  = mfiles.push_back(ne)

' Walk through the list using indices
for i = 0 to (mfiles.size - 1)
    MsgBox mfiles(i).FileName
next

' Walk through the list using iterators

for each file in mfiles
    MsgBox file.FileName
Next
JScript
var Shell = new ActiveXObject("WScript.Shell");
var mfiles = ODTK.Scenario(0).Measurements.Files;

// Clear the list
var unused = mfiles.clear;

// Add a new item to itvar ne;
ne = mfiles.NewElem();
ne.Enabled  = true;
ne.FileName = "C:\\Temp\\test.geosc";
unused  = mfiles.push_back(ne);

// Walk through the list using indices
for (i = 0; i < mfiles.size - 1; i++)
{
    Shell.Popup(mfiles(i).FileName);
}
Perl
my $mfiles = $ODTK->Scenario(0)->Measurements->Files;

# Clear the list
$mfiles->clear();

# Add a new item to it
my $ne = $mfiles->NewElem();
$ne->{Enabled}  = 1;
$ne->{Filename} = "C:\\Temp\\test.geosc";
$mfiles->push_back($ne);

# Walk through the list using indices
my $size = $mfiles->size->{Value};
for ($i=0; $i < $size; $i++)
{
    Win32::MsgBox $mfiles->Item($i)->Filename->{Value};
}

# Walk through the list using iterators

foreach $file (in $mfiles)
{
    Win32::MsgBox $file->FileName->{Value};
}
Python
mfiles = ODTK.Scenario(0).Measurements.Files

# Clear the list
unused = mfiles.clear

# Add a new item to it
ne = mfiles.NewElem()
ne.Enabled  = True
ne.FileName = "C:\\Temp\\test.geosc"        # Be sure the file exists in the specified location
unused  = mfiles.push_back(ne)

# Walk through the list using indices
for i in range(int(mfiles.size)):        # Must cast mfiles.size to an integer
    print(mfiles(i).FileName)

# Walk through the list using iterators

for file in mfiles:
    print(file.FileName)
MATLAB
mfiles = odtk.invoke('Scenario').invoke('Item', 0).invoke('Measurements').invoke('Files');


% Clear the list

mfiles.invoke('clear');


% Add a new item to it

ne = mfiles.invoke('NewElem');
ne.set('Enabled', true);
ne.set('Filename', 'C:\Temp\test.geosc');
mfiles.invoke('push_back', ne);


% Walk through the list using indices

size = mfiles.invoke('size').invoke('Value');
for i = 0:size-1
    fprintf('%s\n', mfiles.invoke('Item', i).invoke('Filename').invoke('Value'));
end


% MATLAB does not support a foreach concept

Cross-Platform API

Python
If demonstrate_list:
    measurement_files = scenario.Measurements.Files
    print(f'Measurement files count: {measurement_files.count}')
    measurement_file = measurement_files[0]
    measurement_file_name = measurement_file.FileName.value.eval()
    print(f'First measurement file: {measurement_file_name}')
    # Clear the list
    measurement_files.clear()
    print(f'Measurement files count: {measurement_files.count}')
    # Add a new item to it
    ne = measurement_files.NewElem()
    ne.Enabled = True
    ne.FileName = measurement_file_name
    measurement_files.push_back(ne)
    print(f'Measurement files count: {measurement_files.count}')
    # Walk through the list using indices
    for i in range(measurement_files.size.eval()):  # 'count' can also be used instead of 'size'
        print(f'Measurement file ({i}): {measurement_files[i].FileName.value.eval()}')
    # Walk through the list using iterators
    for file in measurement_files:
        print(f'Measurement file: {file.FileName.value.eval()}')
            
MATLAB
if demonstrateList
    measurementFiles = scenario.Measurements.Files;
    fprintf("Measurement files count: %i\n", measurementFiles.count);
    measurementFile = measurementFiles{0};
    measurementFileName = measurementFile.FileName.value;
    fprintf("First measurement file: %s\n", measurementFileName);
    % Clear the list
    measurementFiles.clear();
    fprintf("Measurement files count: %i\n", measurementFiles.count);
    % Add a new item to it
    ne = measurementFiles.NewElem();
    ne.Enabled = true;
    ne.FileName = measurementFileName;
    measurementFiles.push_back(ne);
    fprintf("Measurement files count: %i\n", measurementFiles.count);
    % Walk through the list using indices
    for i = 0: measurementFiles.size-1
        fprintf("Measurement file (%i): %s\n", i, measurementFiles{i}.FileName.value);
    end
end

            
C++
if (demonstrateList)
{
    const agi::odtk::AttrProxy measurementFiles = scenario("Measurements")("Files");
    std::cout << "Measurement files count: " << measurementFiles("count").AsInt() << "\n";
    const agi::odtk::AttrProxy measurementFile = measurementFiles[0];
    const auto measurementFileName = measurementFile("FileName")("value").AsString();
    std::cout << "First measurement file: " << measurementFileName << "\n";
    // Clear the list
    measurementFiles("clear").Invoke();
    std::cout << "Measurement files count: " << measurementFiles("count").AsInt() << "\n";
    // Add a new item to it
    const auto ne = measurementFiles("NewElem").InvokeAttrProxy();
    ne("Enabled").Assign(true);
    ne("FileName").Assign(measurementFileName);
    measurementFiles("push_back").Invoke(ne);
    std::cout << "Measurement files count: " << measurementFiles("count").AsInt() << "\n";
    // Walk through the list using indices
    for (int i = 0; i < measurementFiles("size").AsInt() - 1; ++i)
    {
        std::cout << "Measurement file " << i << ": " << measurementFiles[i]("FileName")("value").AsString() << "\n";
    }
}
            

Type SETLINKTOOBJ

Some ODTK objects have a special container SetLinkToObj that acts like a Set (in that only unique items can be contained in it) and the unique items are links to other ODTK objects. A common example of this is a Filter object's SatelliteList. You can choose to add specific satellite objects into the SatelliteList, but you can only add the satellite once. Use the InsertbyName() method to add a new object into the list. Alternatively, you can retrieve the list in your script via the Choices property. The entire SetLinkToObj can be cleared using clear() and an individual element removed using erase(). The number of elements in the SetLinkToObj is available using size(). Elements in the SetLinkToObj can be accessed by index number or by iterating through the SetLinkToObj. The methods begin() and end() return iterators that have the following methods: IsSafeToDereference(), Dereference(), Increment(), and Decrement().

COM

VBScript
set scen = ODTK.Scenario(0)
set fil = scen.Filter(0)

' Clear out the existing SatelliteList
fil.SatelliteList.clear()

' Add a particular satellite called Fred
success = fil.SatelliteList.InsertByName("Fred")
MsgBox success

' Iterate through the list of possible choices we could have used
for each sChoice in fil.SatelliteList.Choices
    MsgBox sChoice
next

' Add the 2nd satellite to the list (0 indexed)
fil.SatelliteList.insert(fil.SatelliteList.Choices(1))

' Remove Fred from the list
fil.SatelliteList.erase("Fred")
            
JScript
var Shell = new ActiveXObject("WScript.Shell");
var scen = ODTK.Scenario(0);
var fil = scen.Filter(0);

// Clear out the existing SatelliteList
fil.SatelliteList.clear()

// Add a particular satellite called Fred
var success = fil.SatelliteList.InsertByName("Fred")
Shell.Popup(success)

// Iterate through the list of possible choices we could have used
var i;
for(i = 0; i < fil.SatelliteList.Choices.Count; i++)
{
    Shell.Popup(fil.SatelliteList.Choices(i));
}

// Add the 2nd satellite to the list (0 indexed)
fil.SatelliteList.insert(fil.SatelliteList.Choices(1))

// Remove Fred from the list
fil.SatelliteList.erase("Fred")
Perl
my $scen = $ODTK->Scenario(0);
my $fil = $scen->Filter(0);

# Clear out the existing SatelliteList
$fil->SatelliteList->clear();

# Add a particular satellite called Fred
my $success = $fil->SatelliteList->InsertByName("Fred");
Win32::MsgBox success;

# Iterate through the list of possible choices we could have used
$coll = $fil->SatelliteList->Choices;
foreach $sChoice (in $coll)
{
    Win32::MsgBox "$sChoice";
}

# Add the 2nd satellite to the list (0 indexed)
$fil->SatelliteList->insert($fil->SatelliteList->Choices(1));

# Remove Fred from the list
$fil->SatelliteList->erase("Fred");
                
Python
scen = ODTK.Scenario(0)
fil = scen.Filter("Filter1")

# Clear out the existing SatelliteList
fil.SatelliteList.clear()

# Add a particular satellite called Fred
success = fil.SatelliteList.InsertByName("Fred")
print(success)

# Iterate through the list of possible choices we could have used
for sChoice in fil.SatelliteList.Choices:
    print(sChoice)

# Add the 2nd satellite to the list (0 indexed)
fil.SatelliteList.insert(fil.SatelliteList.Choices(1))

# Remove Fred from the list
fil.SatelliteList.erase("Fred")
                
MATLAB
fil = scen.invoke('Filter').invoke('Item', 0);

% Clear out the existing SatelliteList
fil.invoke('SatelliteList').invoke('clear');

% Add a particular satellite called Fred
success = fil.invoke('SatelliteList').invoke('InsertByName','Fred');
disp(success.invoke('Value'))

% Iterate through the list of possible choices we could have used
coll = fil.invoke('SatelliteList').invoke('Choices');
size = coll.invoke('Size').invoke('Value');
for i = 0:size - 1
    choice = coll.invoke('Item', i);
    disp(choice.invoke('Value'));
end

% Add the 2nd satellite to the list (0 indexed)
fil.invoke('SatelliteList').invoke('insert', fil.invoke('SatelliteList').invoke('Choices').invoke('Item', 1));
% Remove Fred from the list
fil.invoke('SatelliteList').invoke('erase', 'Fred');
            

Cross-Plaform API

Python
# Clear out the existing SatelliteList
filter1.SatelliteList.clear()

# Add a particular satellite called mySat
success = filter1.SatelliteList.InsertByName("mySat")
print(success)

# Iterate through the list of possible choices we could have used
for choice in filter1.SatelliteList.Choices:
    print(choice.eval())

# Add the 2nd satellite to the list (0 indexed)
filter1.SatelliteList.insert(filter1.SatelliteList.Choices[1])

# Remove mySat from the list
filter1.SatelliteList.erase("mySat")

            
MATLAB
% Clear out the existing SatelliteList
filter1.SatelliteList.clear();

% Add a particular satellite called Fred
success = filter1.SatelliteList.InsertByName("mySat");
    fprintf("%s\n", string(success));

% Iterate through the list of possible choices we could have used
satelliteChoices = filter1.SatelliteList.Choices;
for i = 0: satelliteChoices.Count-1
    fprintf("  %i. %s\n", i, satelliteChoices{i});
end

% Add the 2nd satellite to the list (0 indexed)
filter1.SatelliteList.insert(filter1.SatelliteList.Choices{1});

% Remove Fred from the list
filter1.SatelliteList.erase("mySat");
            
C++
// Clear out the existing SatelliteList
filter1("SatelliteList")("Clear").Invoke();

// Add a particular satellite called mySat
bool success = filter1("SatelliteList")("InsertByName").InvokeBool("mySat");
std::cout << success << "\n";

// Iterate through the list of possible choices we could have used
const agi::odtk::AttrProxy satelliteChoices = filter1("SatelliteList")("Choices");
for (int i = 0; i < satelliteChoices("Count").AsInt(); ++i)
{
    std::cout << "  " << i << ". " << satelliteChoices[i].AsString() << "\n";
}

// Add the 2nd satellite to the list(0 indexed)
filter1("SatelliteList")("Insert").Invoke(filter1("SatelliteList")("Choices")[1].AsString());

// Remove mySat from the list
filter1("SatelliteList")("Erase").Invoke("mySat");
            

Type SET

The Set container is similar to a list but is ordered by an internal constraint and will reject duplicates. Use the NewElem() method to create a new object that can be added to the Set. Actually adding it to the list is accomplished using insert(ne). The entire Set can be cleared using clear() and an individual element removed using erase(). The number of elements in the Set is available using size(). Elements in the Set can be accessed by index number or by iterating through the Set. Some Sets such as MeasurementStatistics have additional methods that are useful such as InsertByName(string), RemoveByName(string), and FindByName(string) where string is the name of the element being inserted, found, or removed. InsertByName() and RemoveByName() return a boolean indicating whether the element was successfully added or removed. Not all sets implement FindByName() and RemoveByName(), only the more commonly used sets do.

The methods begin(), end(), and FindByName() return iterators that have the following methods: IsSafeToDereference(), Dereference(), Increment(), and Decrement().

COM

VBScript
set scen = ODTK.Scenario(0)
set f = scen.TrackingSystem("TrkSys1").Facility("BOSS-A")

' Clear out the set
set mstats = f.MeasurementStatistics
mstats.clear()

' Add a range measurement model
success = mstats.InsertByName("Range")
set msIter = mstats.FindByName("Range")
if msIter.IsSafeToDereference() then
    set m = msIter.Dereference()
    set unused = m.Type.BiasSigma.Set(10, "m")
    set unused = m.Type.BiasHalfLife.Set(6, "hr")
    set unused = m.Type.WhiteNoiseSigma.Set(4, "m")
end if

' Add an azimuth measurement model
success = mstats.InsertByName("Azimuth")
set msIter = mstats.FindByName("Azimuth")
if msIter.IsSafeToDereference() then
    set m = msIter.Dereference()
    set unused = m.Type.BiasSigma.Set(0.1, "deg")

    set unused = m.Type.BiasHalfLife.Set(6, "hr")
    set unused = m.Type.WhiteNoiseSigma.Set(0.05, "deg")
end if

' Now remove the range model
success = mstats.RemoveByName("Range")
MsgBox "Range removed: " & success
JScript
var Shell = new ActiveXObject("WScript.Shell");
var scen = ODTK.Scenario(0);
var f = scen.TrackingSystem("TrkSys1").Facility("BOSS-A");

// Clear out the set
var mstats = f.MeasurementStatistics;
mstats.clear();

// Add a range measurement model
var success = mstats.InsertByName("Range");
var msIter = mstats.FindByName("Range");
if (msIter.IsSafeToDereference())
{
    var m = msIter.Dereference();
    var unused = m.Type.BiasSigma.Set(10, "m");
    unused = m.Type.BiasHalfLife.Set(6, "hr");
    unused = m.Type.WhiteNoiseSigma.Set(4, "m");
}

// Add an azimuth measurement model
success = mstats.InsertByName("Azimuth");
msIter = mstats.FindByName("Azimuth");
if (msIter.IsSafeToDereference())
{
    m = msIter.Dereference();
    unused = m.Type.BiasSigma.Set(0.1, "deg");
    unused = m.Type.BiasHalfLife.Set(6, "hr");
    unused = m.Type.WhiteNoiseSigma.Set(0.05, "deg");
}

// Now remove the range model
success = mstats.RemoveByName("Range"); Shell.Popup("Range removed: " + success);
Perl
my $scen = $ODTK->Scenario(0);
my $f = $scen->TrackingSystem("TrkSys1")->Facility("BOSS-A");

# Clear out the set
my $mstats = $f->MeasurementStatistics;
$mstats->clear();

# Add a range measurement model
my $success = $mstats->InsertByName("Range")->{Value};
my $msIter = $mstats->FindByName("Range");
if ($msIter->IsSafeToDereference()->{Value})
{
    my $m = $msIter->Dereference();
    $m->Type->BiasSigma->Set(10, "m");
    $m->Type->BiasHalfLife->Set(6, "hr");
    $m->Type->WhiteNoiseSigma->Set(4, "m");
}

# Add an azimuth measurement model

$success = $mstats->InsertByName("Azimuth");
$msIter = $mstats->FindByName("Azimuth");
if ($msIter->IsSafeToDereference()->{Value})
{
    my $m = $msIter->Dereference();
    $m->Type->BiasSigma->Set(0.1, "deg");
    $m->Type->BiasHalfLife->Set(6, "hr");
    $m->Type->WhiteNoiseSigma->Set(0.05, "deg");
}

# Now remove the range model
$success = $mstats->RemoveByName("Range");
Win32::MsgBox "Range removed: " . $success->{Value};
Python
scen = ODTK.Scenario(0)
f = scen.TrackingSystem("TrkSys1").Facility("BOSS-A")

# Clear out the set
mstats = f.MeasurementStatistics
mstats.clear()

# Add a range measurement model
success = mstats.InsertByName("Range")
ms = mstats(mstats.size()-1)
ms.Type.BiasSigma.Set(10, "m")
ms.Type.BiasHalfLife.Set(6, "hr")
ms.Type.WhiteNoiseSigma.Set(4, "m")

# Add an azimuth measurement model
success = mstats.InsertByName("Azimuth")
ms = mstats(mstats.size()-1)
ms.Type.BiasSigma.Set(0.1, "deg")
ms.Type.BiasHalfLife.Set(6, "hr")
ms.Type.WhiteNoiseSigma.Set(0.05, "deg")

# Now remove the range model
success = mstats.RemoveByName("Range")
print("Range removed: " + str(success))
MATLAB
scen = odtk.invoke('Scenario').invoke('Item', 0);

f = scen.invoke('TrackingSystem').invoke('TrkSys1').invoke('Facility').invoke('BOSS-A');


% Clear out the set

mstats = f.invoke('MeasurementStatistics');
mstats.invoke('clear');


% Add a range measurement model

success = mstats.invoke('InsertByName', 'Range').invoke('Value');
msIter = mstats.invoke('FindByName', 'Range');

if (msIter.invoke('IsSafeToDereference').invoke('Value'))
    m = msIter.invoke('Dereference');
    m.invoke('Type').invoke('BiasSigma').invoke('Set', 10, 'm');
    m.invoke('Type').invoke('BiasHalfLife').invoke('Set', 6, 'hr');
    m.invoke('Type').invoke('WhiteNoiseSigma').invoke('Set', 4, 'm');
end


% Add an azimuth measurement model

success = mstats.invoke('InsertByName', 'Azimuth');
msIter = mstats.invoke('FindByName', 'Azimuth');

if (msIter.invoke('IsSafeToDereference').invoke('Value'))
    m = msIter.invoke('Dereference');
    m.invoke('Type').invoke('BiasSigma').invoke('Set', 0.1, 'deg');
    m.invoke('Type').invoke('BiasHalfLife').invoke('Set', 6, 'hr');
    m.invoke('Type').invoke('WhiteNoiseSigma').invoke('Set', 0.05, 'deg');
end


% Now remove the range model

success = mstats.invoke('RemoveByName', 'Range');

fprintf('Range removed: %d\n', success.invoke('Value'));

Cross-Platform API

Python
# Clear out the set
measurement_statistics = facility.MeasurementStatistics
measurement_statistics.clear()

# Add a range measurement model
success = measurement_statistics.InsertByName('Range')
print(f'Range measurement model added: {success}')
ms = measurement_statistics[measurement_statistics.count - 1]

ms.Type.BiasSigma.Set(10, 'm')
ms.Type.BiasHalfLife.Set(6, 'hr')
ms.Type.WhiteNoiseSigma.Set(4, 'm')

# Add an azimuth measurement model
success = measurement_statistics.InsertByName('Azimuth')
print(f'Azimuth measurement model added: {success}')
ms = measurement_statistics[measurement_statistics.count - 1]

ms.Type.BiasSigma.Set(0.1, 'deg')
ms.Type.BiasHalfLife.Set(6, 'hr')
ms.Type.WhiteNoiseSigma.Set(0.05, 'deg')

# Now remove the range model
success = measurement_statistics.RemoveByName('Range')
print(f'Range model removed: {success}')

                
MATLAB
% Clear out the set
measurementStatistics = facility.MeasurementStatistics;
measurementStatistics.clear();

% Add a range measurement model
success = measurementStatistics.InsertByName("Range");
fprintf("Range measurement model added: %s\n", string(success));
ms = measurementStatistics{measurementStatistics.count - 1};

ms.Type.BiasSigma.Set(10, "m");
ms.Type.BiasHalfLife.Set(6, "hr");
ms.Type.WhiteNoiseSigma.Set(4, "m");

% Add an azimuth measurement model
success = measurementStatistics.InsertByName("Azimuth");
fprintf("Azimuth measurement model added: %s\n", string(success));
ms = measurementStatistics{measurementStatistics.count - 1};

ms.Type.BiasSigma.Set(0.1, "deg");
ms.Type.BiasHalfLife.Set(6, "hr");
ms.Type.WhiteNoiseSigma.Set(0.05, "deg");

% Now remove the range model
success = measurementStatistics.RemoveByName("Range");
fprintf("Range model removed: %s\n", string(success));
            
C++
// Clear out the set
const agi::odtk::AttrProxy measurementStatistics = facility("MeasurementStatistics");
measurementStatistics("clear").Invoke();

// Add a range measurement model
bool success = measurementStatistics("InsertByName").InvokeBool("Range");
std::cout << "Range measurement model added: " << BoolToString(success) << "\n";
const agi::odtk::AttrProxy ms = measurementStatistics[measurementStatistics("count").AsInt() - 1];

ms("Type")("BiasSigma")("Set").Invoke(10, "m");
ms("Type")("BiasHalfLife")("Set").Invoke(6, "hr");
ms("Type")("WhiteNoiseSigma")("Set").Invoke(4, "m");

// Add an azimuth measurement model
success = measurementStatistics("InsertByName").InvokeBool("Azimuth");
std::cout << "Azimuth measurement model added: " << BoolToString(success) << "\n";
const auto ms2 = measurementStatistics[measurementStatistics("count").AsInt() - 1];

ms2("Type")("BiasSigma")("Set").Invoke(0.1, "deg");
ms2("Type")("BiasHalfLife")("Set").Invoke(6, "hr");
ms2("Type")("WhiteNoiseSigma")("Set").Invoke(0.05, "deg");

// Now remove the range model
success = measurementStatistics("RemoveByName").InvokeBool("Range");
std::cout << "Range model removed: " << BoolToString(success) << "\n";
            

In addition to the unlimited sets there are pre-defined sets (SET ENUMERATION), and sets of the objects (SET LINKTOOBJ). Please note that for some sets, insert() and erase() accept either an object name or the handle. However, you have to check that it works for a particular set.

Special Cases

Maneuver Sets

Maneuvers and their interfaces to work with them have been completely overhauled in ODTK 6 to make things easier and more intuitive. Because of this, there are several changes to call out explicitly for those porting scripts from ODTK 5 (or earlier versions).

  • Maneuvers are now managed as ordered Sets rather than unordered Lists.
  • The maneuvers are automatically sorted by:
    1. Start Time (finite maneuvers) or Epoch (instantaneous maneuvers)
    2. Maneuver type
    3. Enabled / disabled status
    4. Name
  • Maneuver sets have an method InsertNew(string) where the string is the name of the various maneuver Choices.
  • Maneuvers now have methods FindByName(string) and RemoveByName(string) where string is the name of a maneuver.
  • The old method of creating a new maneuver element and then push it onto the bottom of the list using push_back() will not work as Sets do not support push_back(). Simply replacing push_back() with insert() does not guarantee that the new element will be at the end of the set since the set is sorted.

The recommended methods for working with the maneuver sets are demonstrated in the sample code below. Note the use of iterators to work with items in the Set.

COM

VBScript
set sat = ODTK.Scenario(0).Satellite("Satellite1")
'-------------------------------------------------------
' Finite maneuver example
'-------------------------------------------------------
' Clear out any existing finite maneuvers and add a new
' one in.
set fmSet = sat.ForceModel.FiniteManeuvers
fmSet.clear()
' Create a new maneuver to model a cross-track delta-I
set fmIter = fmSet.InsertNew("FiniteManConstThrust")
if fmIter.IsSafeToDereference() then
   set fm = fmIter.Dereference()
   fm.Name     = "FMTest1"
   fm.Enabled  = true
   fm.Frame    = "Gaussian (RIC)"
   fm.Estimate = "MagnitudeAndPointing"


   ' Configure the burn time

   fm.Time.StopMode = "TimeSpan"
   set unused = fm.Time.StartTime.Set("1 Jun 2009 00:00:00", "UTCG")
   set unused = fm.Time.TimeSpan.Set("45", "min")


   ' Configure the burn parameters

   fm.Thrust.Specification = "ByComponent"
   set unused = fm.Thrust.ThrustX.Set(0, "N")
   set unused = fm.Thrust.ThrustY.Set(0, "N")
   set unused = fm.Thrust.ThrustZ.Set(2, "lbf")


   ' Configure the mass loss

   fm.Mass.LossMethod = "BasedOnIsp"
   set unused = fm.Mass.Isp.Set(325.0,"sec")


   ' Configure the burn uncertainty

   fm.Uncertainty.Type = "%MagnitudeAndPointing"
   set unused = fm.Uncertainty.PercentMagnitudeSigma.Set( 3.0, "%")
   set unused = fm.Uncertainty.PointingSigma.Set(1.5, "deg")
   set unused = fm.Uncertainty.MagnitudeHalfLife.Set(1, "hr")
   set unused = fm.Uncertainty.PointingHalfLife.Set(1, "hr")
end if

' Add in a second maneuver as a dummy maneuver just
' to prove that we can find the right maneuver

set fmIter = fmSet.InsertNew("FiniteManConstThrust")
if fmIter.IsSafeToDereference() then
   set fm = fmIter.Dereference()


   ' We'll set the name and accept the defaults for all the
                               ' other parameters.

   fm.Name = "FMTest2"

end if
' Now try to find the first maneuver and report the
' thrust.
set fmIter = fmset.FindByName("FMTest1")
if fmIter.IsSafeToDereference() then
    set fm = fmIter.Dereference()

    MsgBox "Found maneuver " & fm.Name & vbCrLf & "Thrust is " & fm.Thrust.ThrustZ.GetIn("lbf") & " lbf"

end if

' Now delete the second maneuver
set fmIter = fmset.FindByName("FMTest2")
if fmIter.IsSafeToDereference() then
   MsgBox "Found second maneuver"

   fmset.RemoveByName("FMTest2")
end if

' Verify that the second maneuver is gone.
set fmIter = fmset.FindByName("FMTest2")
if not fmIter.IsSafeToDereference() then
    MsgBox "Second maneuver was deleted"
end if
'-------------------------------------------------------
' Impulsive maneuver example
'-------------------------------------------------------
' Clear out any existing instant maneuvers and add a new
' one in.
set imSet = sat.ForceModel.InstantManeuvers
imSet.clear()

' Create a new maneuver to model an in-track Delta-V
set imIter = imSet.InsertNew("InstantManDeltaV")
if imIter.IsSafeToDereference() then
   set im = imIter.Dereference()

   im.Name    = "IMTest1"
   im.Enabled = true
   im.Frame   = "Gaussian (RIC)"


   ' Configure the burn time (assumes the actual burn is
   ' 4 minutes long but is modeled as an impulsive burn)

   set unused = im.Epoch.Set("1 Jan 2009 01:23:45", "UTCG")
   set unused = im.TimeAfterStart.Set(2, "min")
   set unused = im.TimeBeforeEnd.Set(2, "min")


   ' Configure the burn parameters

   im.DeltaV.Specification = "ByComponent"
   set unused = im.DeltaV.DeltaVX.Set(0.0, "m/sec")
   set unused = im.DeltaV.DeltaVY.Set(0.1, "m/sec")
   set unused = im.DeltaV.DeltaVZ.Set(0.0, "m/sec")


   ' Configure the mass loss

   im.Mass.LossMethod = "Explicit"
   set unused = im.Mass.MassLoss.Set(1,"kg")


   ' Configure the burn uncertainty

   im.Uncertainty.Type = "ByComponent"
       set unused = im.Uncertainty.XSigma.Set(0.01, "m/sec")
       set unused = im.Uncertainty.YSigma.Set(0.02, "m/sec")
       set unused = im.Uncertainty.ZSigma.Set(0.01, "m/sec")

end if

' Add in a second maneuver as a dummy maneuver just
' to prove that we can find the right maneuver
set imIter = imSet.InsertNew("InstantManDeltaV")
if imIter.IsSafeToDereference() then
   set im = imIter.Dereference()

   ' We'll set the name and accept the defaults for all the
   ' other parameters.

   im.Name = "IMTest2"

end if

' Now try to find the first maneuver and report the Delta-V
set imIter = imSet.FindByName("IMTest1")
if imIter.IsSafeToDereference() then
    set im = imIter.Dereference()
    MsgBox "Found maneuver " & im.Name & vbCrLf & "Delta-V is " & im.DeltaV.DeltaVY.GetIn("m/sec") & " m/sec"

end if

' Now delete the second maneuver
set imIter = imSet.FindByName("IMTest2")
if imIter.IsSafeToDereference() then
   MsgBox "Found second maneuver"

   imSet.RemoveByName("IMTest2")
end if

' Verify that it is gone.
set imIter = imSet.FindByName("IMTest2")
if not imIter.IsSafeToDereference() then
    MsgBox "Second maneuver was deleted"
end if

' At this point the only maneuvers left on the satellite should be
' FMTest1 and IMTest1.
JScript
var Shell = new ActiveXObject("WScript.Shell");
var sat = ODTK.Scenario(0).Satellite("Satellite1");
//-------------------------------------------------------
// Finite maneuver example
//-------------------------------------------------------
// Clear out any existing finite maneuvers and add a new
// one in.
var fmSet = sat.ForceModel.FiniteManeuvers;
fmSet.clear();

// Create a new maneuver to model a cross-track delta-I
var fmIter = fmSet.InsertNew("FiniteManConstThrust")
if (fmIter.IsSafeToDereference())
{
   var fm = fmIter.Dereference();

   fm.Name     = "FMTest1"
   fm.Enabled  = true;
   fm.Frame    = "Gaussian (RIC)";
   fm.Estimate = "MagnitudeAndPointing";


   // Configure the burn time

   fm.Time.StopMode = "TimeSpan";
   var unused = fm.Time.StartTime.Set("1 Jun 2009 00:00:00", "UTCG");
   unused = fm.Time.TimeSpan.Set("45", "min");


   // Configure the burn parameters

   fm.Thrust.Specification = "ByComponent"
   unused = fm.Thrust.ThrustX.Set(0, "N");
   unused = fm.Thrust.ThrustY.Set(0, "N");
   unused = fm.Thrust.ThrustZ.Set(2, "lbf");


   // Configure the mass loss

   fm.Mass.LossMethod = "BasedOnIsp";
   unused = fm.Mass.Isp.Set(325.0,"sec");


   // Configure the burn uncertainty

   fm.Uncertainty.Type = "%MagnitudeAndPointing";
   fm.Uncertainty.PercentMagnitudeSigma = 3.0;
   unused = fm.Uncertainty.PointingSigma.Set(1.5, "deg");
   unused = fm.Uncertainty.MagnitudeHalfLife.Set(1, "hr");
   unused = fm.Uncertainty.PointingHalfLife.Set(1, "hr");
}

// Add in a second maneuver as a dummy maneuver just
// to prove that we can find the right maneuver
fmIter = fmSet.InsertNew("FiniteManConstThrust");
if (fmIter.IsSafeToDereference())
{
   fm = fmIter.Dereference();

   // We'll set the name and accept the defaults for all the
   // other parameters.

   fm.Name = "FMTest2";
}

// Now try to find the first maneuver and report the
// thrust.
fmIter = fmSet.FindByName("FMTest1");
if (fmIter.IsSafeToDereference())
{
    fm = fmIter.Dereference();

    Shell.Popup("Found maneuver " + fm.Name + "\n" + "Thrust is " + fm.Thrust.ThrustZ.GetIn("lbf") + " lbf");
}
// Now delete the second maneuver
fmIter = fmSet.FindByName("FMTest2");
if (fmIter.IsSafeToDereference())
{
   Shell.Popup("Found second maneuver");
   fmSet.RemoveByName("FMTest2");
}

// Verify that the second maneuver is gone.
fmIter = fmSet.FindByName("FMTest2")
if (fmIter.IsSafeToDereference() == false)
{
    Shell.Popup("Second maneuver was deleted");
}
//-------------------------------------------------------
// Impulsive maneuver example
//-------------------------------------------------------
// Clear out any existing instant maneuvers and add a new
// one in.
var imSet = sat.ForceModel.InstantManeuvers;
imSet.clear();

// Create a new maneuver to model an in-track Delta-V
imIter = imSet.InsertNew("InstantManDeltaV");
if (imIter.IsSafeToDereference())
{
   var im = imIter.Dereference();

   im.Name    = "IMTest1";
   im.Enabled = true;
   im.Frame   = "Gaussian (RIC)";


   // Configure the burn time (assumes the actual burn is
   // 4 minutes long but is modeled as an impulsive burn)

   unused = im.Epoch.Set("1 Jan 2009 01:23:45", "UTCG");
   unused = im.TimeAfterStart.Set(2, "min");
   unused = im.TimeBeforeEnd.Set(2, "min");


   // Configure the burn parameters

   im.DeltaV.Specification = "ByComponent";
   unused = im.DeltaV.DeltaVX.Set(0.0, "m/sec");
   unused = im.DeltaV.DeltaVY.Set(0.1, "m/sec");
   unused = im.DeltaV.DeltaVZ.Set(0.0, "m/sec");


   // Configure the mass loss

   im.Mass.LossMethod = "Explicit";
   unused = im.Mass.MassLoss.Set(1,"kg");


   // Configure the burn uncertainty

   im.Uncertainty.Type = "ByComponent";
   unused = im.Uncertainty.XSigma.Set(0.01, "m/sec");
   unused = im.Uncertainty.YSigma.Set(0.02, "m/sec");
   unused = im.Uncertainty.ZSigma.Set(0.01, "m/sec");
}

// Add in a second maneuver as a dummy maneuver just
// to prove that we can find the right maneuver
imIter = imSet.InsertNew("InstantManDeltaV");
if (imIter.IsSafeToDereference())
{
   im = imIter.Dereference();

   // We'll set the name and accept the defaults for all the
   // other parameters.
   im.Name = "IMTest2";
}

// Now try to find the first maneuver and report the Delta-V
imIter = imSet.FindByName("IMTest1");
if (imIter.IsSafeToDereference())
{
    im = imIter.Dereference();
       Shell.Popup("Found maneuver " + im.Name + "\n" + "Delta-V is " + im.DeltaV.DeltaVY.GetIn("m/sec") + " m/sec");
}
// Now delete the second maneuver
imIter = imSet.FindByName("IMTest2")
if (imIter.IsSafeToDereference())
{
   Shell.Popup("Found second maneuver");
   imSet.RemoveByName("IMTest2");
}

// Verify that it is gone.
imIter = imSet.FindByName("IMTest2");
if (imIter.IsSafeToDereference() == false)
{
    Shell.Popup("Second maneuver was deleted");
}
// At this point the only maneuvers left on the satellite should be
// FMTest1 and IMTest1.
Perl
my $sat = $ODTK->Scenario(0)->$satellite("Satellite1");
#-------------------------------------------------------
# Finite maneuver example
#-------------------------------------------------------
# Clear out any existing finite maneuvers and add a new
# one in.
my $fmSet = $sat->ForceModel->FiniteManeuvers;
$fmSet->clear();

# Create a new maneuver to model a cross-track delta-I
my $fmIter = $fmSet->InsertNew("FiniteManConstThrust");
if ($fmIter->IsSafeToDereference()-{Value})
{
    my $fm = $fmIter->Dereference();
    $fm->{Name}     = "FMTest1";
    $fm->{Enabled}  = 1;
    $fm->{Frame}    = "Gaussian (RIC)";
    $fm->{Estimate} = "MagnitudeAndPointing";
    # Configure the burn time
    $fm->Time->{StopMode} = "TimeSpan";
    my $unused = $fm->Time->StartTime->Set("1 Jun 2009 00:00:00", "UTCG");
    $unused = $fm->Time->TimeSpan->Set("45", "min");
    # Configure the burn parameters
    $fm->Thrust->{Specification} = "ByComponent";
    $unused = $fm->Thrust->ThrustX->Set(0, "N");
    $unused = $fm->Thrust->ThrustY->Set(0, "N");
    $unused = $fm->Thrust->ThrustZ->Set(2, "lbf");
    # Configure the mass loss
    $fm->Mass->{LossMethod} = "BasedOnIsp";
    $unused = $fm->Mass->Isp->Set(325.0,"sec");
    # Configure the burn uncertainty
    $fm->Uncertainty->{Type} = "%MagnitudeAndPointing";
    $unused = $fm->Uncertainty->PercentMagnitudeSigma->Set(3.0, "%");
    $unused = $fm->Uncertainty->PointingSigma->Set(1.5, "deg");
    $unused = $fm->Uncertainty->MagnitudeHalfLife->Set(1, "hr");
    $unused = $fm->Uncertainty->PointingHalfLife->Set(1, "hr");
}
# Add in a second maneuver as a dummy maneuver just
# to prove that we can find the right maneuver
$fmIter = $fmSet->InsertNew("FiniteManConstThrust");
if ($fmIter->IsSafeToDereference()->{Value})
{
    my $fm = $fmIter->Dereference();
    # We'll set the name and accept the defaults for all the
    # other parameters.
    $fm->{Name} = "FMTest2";
}
# Now try to find the first maneuver and report the
# thrust.
$fmIter = $fmSet->FindByName("FMTest1");
if ($fmIter->IsSafeToDereference()->{Value})
{
    my $fm = $fmIter->Dereference();
    Win32::MsgBox "Found maneuver " . $fm->Name->{Value} . "\nThrust is " . $fm->Thrust->ThrustZ->GetIn("lbf")->{Value} . " lbf";
}
# Now delete the second maneuver
$fmIter = $fmSet->FindByName("FMTest2");
if ($fmIter->IsSafeToDereference()->{Value})
{
    Win32::MsgBox "Found second maneuver";
    $fmSet->RemoveByName("FMTest2");
}

# Verify that the second maneuver is gone
$fmIter = $fmSet->FindByName("FMTest2");
if (! $fmIter->IsSafeToDereference()->{Value})
{
    Win32::MsgBox "Second maneuver was deleted";
}
#-------------------------------------------------------
# Impulsive maneuver example
#-------------------------------------------------------
# Clear out any existing instant maneuvers and add a new
# one in.
my $imSet = $sat->ForceModel->InstantManeuvers;
$imSet->clear();
# Create a new maneuver to model an in-track Delta-V
my $imIter = $imSet->InsertNew("InstantManDeltaV");
if ($imIter->IsSafeToDereference()->{Value})
{
    my $im = $imIter->Dereference();
    $im->{Name}    = "IMTest1";
    $im->{Enabled} = 1;
    $im->{Frame}   = "Gaussian (RIC)";
    # Configure the burn time (assumes the actual burn is
    # 4 minutes long but is modeled as an impulsive burn)
    my $unused = $im->Epoch->Set("1 Jan 2009 01:23:45", "UTCG");
    $unused = $im->TimeAfterStart->Set(2, "min");
    $unused = $im->TimeBeforeEnd->Set(2, "min");
    # Configure the burn parameters
    $im->DeltaV->{Specification} = "ByComponent";
    $unused = $im->DeltaV->DeltaVX->Set(0.0, "m/sec");
    $unused = $im->DeltaV->DeltaVY->Set(0.1, "m/sec");
    $unused = $im->DeltaV->DeltaVZ->Set(0.0, "m/sec");
    # Configure the mass loss
    $im->Mass->{LossMethod} = "Explicit";
    $unused = $im->Mass->MassLoss->Set(1,"kg");
    # Configure the burn uncertainty
    $im->Uncertainty->{Type} = "ByComponent";
    $unused = $im->Uncertainty->XSigma->Set(0.01, "m/sec");
    $unused = $im->Uncertainty->YSigma->Set(0.02, "m/sec");
    $unused = $im->Uncertainty->ZSigma->Set(0.01, "m/sec");
}
# Add in a second maneuver as a dummy maneuver just
# to prove that we can find the right maneuver
$imIter = $imSet->InsertNew("InstantManDeltaV");
if ($imIter->IsSafeToDereference()->{Value})
{
    my $im = $imIter->Dereference();
    # We'll set the name and accept the defaults for all the
    # other parameters->
    $im->{Name} = "IMTest2";
}
# Now try to find the first maneuver and report the Delta-V
$imIter = $imSet->FindByName("IMTest1");
if ($imIter->IsSafeToDereference()->{Value})
{
    my $im = $imIter->Dereference();
    Win32::MsgBox "Found maneuver " . $im->Name->{Value} . "\nDelta-V is " . $im->DeltaV->DeltaVY->GetIn("m/sec")->{Value} . " m/sec";
}
# Now delete the second maneuver
$imIter = $imSet->FindByName("IMTest2");
if ($imIter->IsSafeToDereference()->{Value})
{
    Win32::MsgBox "Found second maneuver";
    $imSet->RemoveByName("IMTest2");
}
# Verify that it is gone->
$imIter = $imSet->FindByName("IMTest2");
if (! $imIter->IsSafeToDereference()->{Value})
{
    Win32::MsgBox  "Second maneuver was deleted";
}
# At this point the only maneuvers left on the satellite should be
# FMTest1 and IMTest1.
Python
sat = ODTK.Scenario(0).Satellite("Satellite1")
#-------------------------------------------------------
# Finite maneuver example
#-------------------------------------------------------
# Clear out any existing finite maneuvers and add a new
# one in.
fmSet = sat.ForceModel.FiniteManeuvers
fmSet.clear()
# Create a new maneuver to model a cross-track delta-I
fmIter = fmSet.InsertNew("FiniteManConstThrust")
if fmIter.IsSafeToDereference():
    fm = fmIter.Dereference()
    fm.Name = "FMTest1"
    fm.Enabled  = True
    fm.Frame = "Gaussian (RIC)"
    fm.Estimate = "MagnitudeAndPointing"
    # Configure the burn time
    fm.Time.StopMode = "TimeSpan"
    fm.Time.StartTime.Set("1 Jun 2009 00:00:00", "UTCG")
    fm.Time.TimeSpan.Set("45", "min")
    # Configure the burn parameters
    fm.Thrust.Specification = "ByComponent"
    fm.Thrust.ThrustX.Set(0, "N")
    fm.Thrust.ThrustY.Set(0, "N")
    fm.Thrust.ThrustZ.Set(2, "lbf")
    # Configure the mass loss
    fm.Mass.LossMethod = "BasedOnIsp"
    fm.Mass.Isp.Set(325.0,"sec")
    # Configure the burn uncertainty
    fm.Uncertainty.Type = "%MagnitudeAndPointing"
    fm.Uncertainty.PercentMagnitudeSigma.Set(3.0, '%')
    fm.Uncertainty.PointingSigma.Set(1.5, "deg")
    fm.Uncertainty.MagnitudeHalfLife.Set(1, "hr")
    fm.Uncertainty.PointingHalfLife.Set(1, "hr")
# Add in a second maneuver as a dummy maneuver just
# to prove that we can find the right maneuver
fmIter = fmSet.InsertNew("FiniteManConstThrust")
if fmIter.IsSafeToDereference():
    fm = fmIter.Dereference()
    # We'll set the name and accept the defaults for all the
    # other parameters.
    fm.Name = "FMTest2"
# Now try to find the first maneuver and report the
# thrust.
fmIter = fmSet.FindByName("FMTest1")
if fmIter.IsSafeToDereference():
    fm = fmIter.Dereference()
    print("Found maneuver " + str(fm.Name) + "\n" + "Thrust is " + str(fm.Thrust.ThrustZ.GetIn("lbf")) + " lbf")
# Now delete the second maneuver
fmIter = fmSet.FindByName("FMTest2")
if fmIter.IsSafeToDereference():
    fm = fmIter.Dereference()
    print("Found maneuver " + str(fm.Name))
    print("Thrust is " + str(fm.Thrust.ThrustZ.GetIn("lbf")) + " lbf" )
    fmSet.RemoveByName("FMTest2")

# Verify that the second maneuver is gone.
fmIter = fmSet.FindByName("FMTest2")
if not fmIter.IsSafeToDereference().value:
    print("Second maneuver was deleted")
#-------------------------------------------------------
# Impulsive maneuver example
#-------------------------------------------------------
# Clear out any existing instant maneuvers and add a new
# one in.
imSet = sat.ForceModel.InstantManeuvers
imSet.clear()
# Create a new maneuver to model an in-track Delta-V
imIter = imSet.InsertNew("InstantManDeltaV")
if imIter.IsSafeToDereference().value:
    im = imIter.Dereference()
    im.Name    = "IMTest1"
    im.Enabled = True
    im.Frame   = "Gaussian (RIC)"
    # Configure the burn time (assumes the actual burn is
    # 4 minutes long but is modeled as an impulsive burn)
    im.Epoch.Set("1 Jan 2009 01:23:45", "UTCG")
    im.TimeAfterStart.Set(2, "min")
    im.TimeBeforeEnd.Set(2, "min")
    # Configure the burn parameters
    im.DeltaV.Specification = "ByComponent"
    im.DeltaV.DeltaVX.Set(0.0, "m/sec")
    im.DeltaV.DeltaVY.Set(0.1, "m/sec")
    im.DeltaV.DeltaVZ.Set(0.0, "m/sec")
    # Configure the mass loss
    im.Mass.LossMethod = "Explicit"
    im.Mass.MassLoss.Set(1,"kg")
    # Configure the burn uncertainty
    im.Uncertainty.Type = "ByComponent"
    im.Uncertainty.XSigma.Set(0.01, "m/sec")
    im.Uncertainty.YSigma.Set(0.02, "m/sec")
    im.Uncertainty.ZSigma.Set(0.01, "m/sec")
# Add in a second maneuver as a dummy maneuver just
# to prove that we can find the right maneuver
imIter = imSet.InsertNew("InstantManDeltaV")
if imIter.IsSafeToDereference().value:
    im = imIter.Dereference()
    # We'll set the name and accept the defaults for all the
    # other parameters.
    im.Name = "IMTest2"
# Now try to find the first maneuver and report the Delta-V
imIter = imSet.FindByName("IMTest1")
if imIter.IsSafeToDereference().value:
    im = imIter.Dereference()
    print("Found maneuver " + str(im.Name) + "\n" + "Delta-V is " + str(im.DeltaV.DeltaVY.GetIn("m/sec")) + " m/sec")
# Now delete the second maneuver
imIter = imSet.FindByName("IMTest2")
if imIter.IsSafeToDereference().value:
   print("Found second maneuver")
   imSet.RemoveByName("IMTest2")

# Verify that it is gone.
imIter = imSet.FindByName("IMTest2")
if not imIter.IsSafeToDereference().value:
    print("Second maneuver was deleted")
# At this point the only maneuvers left on the satellite should be
# FMTest1 and IMTest1.
MATLAB
sat = odtk.invoke('Scenario').invoke('Item', 0).invoke('Satellite').invoke('Satellite1') ;

%-------------------------------------------------------
% Finite maneuver example
%-------------------------------------------------------

% Clear out any existing finite maneuvers and add a new
% one in.

fmSet = sat.invoke('ForceModel').invoke('FiniteManeuvers');
fmSet.invoke('clear');

% Create a new maneuver to model a cross-track delta-I

fmIter = fmSet.invoke('InsertNew', 'FiniteManConstThrust');

if (fmIter.invoke('IsSafeToDereference').invoke('Value'))

   fm = fmIter.invoke('Dereference');

   fm.set('Name', 'FMTest1');
   fm.set('Enabled', true);
   fm.set('Frame', 'Gaussian (RIC)');
   fm.set('Estimate', 'MagnitudeAndPointing');

   % Configure the burn time

   fm.invoke('Time').set('StopMode', 'TimeSpan');
   fm.invoke('Time').invoke('StartTime').invoke('Set', '1 Jun 2009 00:00:00', 'UTCG');
   fm.invoke('Time').invoke('TimeSpan').invoke('Set', '45', 'min');

   % Configure the burn parameters

   fm.invoke('Thrust').set('Specification', 'ByComponent');
   fm.invoke('Thrust').invoke('ThrustX').invoke('Set', 0, 'N');
   fm.invoke('Thrust').invoke('ThrustY').invoke('Set', 0, 'N');
   fm.invoke('Thrust').invoke('ThrustZ').invoke('Set', 2, 'lbf');

   % Configure the mass loss

   fm.invoke('Mass').set('LossMethod', 'BasedOnIsp');
   fm.invoke('Mass').invoke('Isp').invoke('Set', 325.0,'sec');

   % Configure the burn uncertainty

   fm.invoke('Uncertainty').set('Type', '%MagnitudeAndPointing');
   fm.invoke('Uncertainty').invoke('PercentMagnitudeSigma').invoke('Set', 3.0, '%');
   fm.invoke('Uncertainty').invoke('PointingSigma').invoke('Set', 1.5, 'deg');
   fm.invoke('Uncertainty').invoke('MagnitudeHalfLife').invoke('Set', 1, 'hr');
   fm.invoke('Uncertainty').invoke('PointingHalfLife').invoke('Set', 1, 'hr');

end

% Add in a second maneuver as a dummy maneuver just
% to prove that we can find the right maneuver

fmIter = fmSet.invoke('InsertNew', 'FiniteManConstThrust');

if fmIter.invoke('IsSafeToDereference').invoke('Value')

   fm = fmIter.invoke('Dereference');

   % We'll set the name and accept the defaults for all the
   % other parameters.

   fm.set('Name', 'FMTest2');

end

% Now try to find the first maneuver and report the
% thrust.

fmIter = fmSet.invoke('FindByName', 'FMTest1');
if fmIter.invoke('IsSafeToDereference').invoke('Value')
    fm = fmIter.invoke('Dereference');
    fprintf('Found maneuver %s\nThrust is %f lbf\n', fm.invoke('Name').invoke('Value'), fm.invoke('Thrust').invoke('ThrustZ').invoke('GetIn', 'lbf').invoke('Value'));
end

% Now delete the second maneuver

fmIter = fmSet.invoke('FindByName', 'FMTest2');

if fmIter.invoke('IsSafeToDereference').invoke('Value')
   fprintf('Found second maneuver\n');
   fmSet.invoke('RemoveByName', 'FMTest2');
end


% Verify that the second maneuver is gone.invoke(

fmIter = fmSet.invoke('FindByName', 'FMTest2');
if not(fmIter.invoke('IsSafeToDereference').invoke('Value'))
    fprintf('Second maneuver was deleted\n');
end

%-------------------------------------------------------
% Impulsive maneuver example
%-------------------------------------------------------

% Clear out any existing instant maneuvers and add a new
% one in.invoke(

imSet = sat.invoke('ForceModel').invoke('InstantManeuvers');
imSet.invoke('clear');

% Create a new maneuver to model an in-track Delta-V

imIter = imSet.invoke('InsertNew', 'InstantManDeltaV');

if imIter.invoke('IsSafeToDereference').invoke('Value')

   im = imIter.invoke('Dereference');

   im.set('Name',   'IMTest1');
   im.set('Enabled', true);
   im.set('Frame',  'Gaussian (RIC)');

   % Configure the burn time (assumes the actual burn is
   % 4 minutes long but is modeled as an impulsive burn)

   im.invoke('Epoch').invoke('Set', '1 Jan 2009 01:23:45', 'UTCG');
   im.invoke('TimeAfterStart').invoke('Set', 2, 'min');
   im.invoke('TimeBeforeEnd').invoke('Set', 2, 'min');

   % Configure the burn parameters

   im.invoke('DeltaV').set('Specification', 'ByComponent');
   im.invoke('DeltaV').invoke('DeltaVX').invoke('Set', 0.0, 'm/sec');
   im.invoke('DeltaV').invoke('DeltaVY').invoke('Set', 0.1, 'm/sec');
   im.invoke('DeltaV').invoke('DeltaVZ').invoke('Set', 0.0, 'm/sec');

   % Configure the mass loss

   im.invoke('Mass').set('LossMethod', 'Explicit');
   im.invoke('Mass').invoke('MassLoss').invoke('Set', 1,'kg');

   % Configure the burn uncertainty

   im.invoke('Uncertainty').set('Type', 'ByComponent');
   im.invoke('Uncertainty').invoke('XSigma').invoke('Set', 0.01, 'm/sec');
   im.invoke('Uncertainty').invoke('YSigma').invoke('Set', 0.02, 'm/sec');
   im.invoke('Uncertainty').invoke('ZSigma').invoke('Set', 0.01, 'm/sec');

end

% Add in a second maneuver as a dummy maneuver just
% to prove that we can find the right maneuver

imIter = imSet.invoke('InsertNew', 'InstantManDeltaV');

if imIter.invoke('IsSafeToDereference').invoke('Value')
   im = imIter.invoke('Dereference');

   % We'll set the name and accept the defaults for all the
   % other parameters.

   im.set('Name', 'IMTest2');

end

% Now try to find the first maneuver and report the Delta-V

imIter = imSet.invoke('FindByName', 'IMTest1');
if imIter.invoke('IsSafeToDereference').invoke('Value')

    im = imIter.invoke('Dereference');

    fprintf('Found maneuver %s\nDelta-V is %f m/sec\n', im.invoke('Name').invoke('Value'), im.invoke('DeltaV').invoke('DeltaVY').invoke('GetIn', 'm/sec').invoke('Value'));

end

% Now delete the second maneuver

imIter = imSet.invoke('FindByName', 'IMTest2');

if imIter.invoke('IsSafeToDereference').invoke('Value')
   fprintf('Found second maneuver\n');
   imSet.invoke('RemoveByName', 'IMTest2');
end

% Verify that it is gone

imIter = imSet.invoke('FindByName', 'IMTest2');
if not(imIter.invoke('IsSafeToDereference').invoke('Value'))
    fprintf('Second maneuver was deleted\n');
end

% At this point the only maneuvers left on the satellite should be
% FMTest1 and IMTest1.

Cross-Platform API

Python
# -------------------------------------------------------
# Finite maneuver example
# -------------------------------------------------------

# Clear out any existing finite maneuvers and add a new
# one in.

finite_maneuvers = satellite.ForceModel.FiniteManeuvers
finite_maneuvers.clear()

# Create a new maneuver to model a cross-track delta-I
fm_iter = finite_maneuvers.InsertNew('FiniteManConstThrust')
if fm_iter.IsSafeToDereference():
    fm = fm_iter.Dereference()

    fm.Name = 'FMTest1'
    fm.Enabled = True
    fm.Frame = 'Gaussian (RIC)'
    fm.Estimate = 'MagnitudeAndPointing'

    # Configure the burn time
    fm.Time.StopMode = 'TimeSpan'
    fm.Time.StartTime.Set('1 Jun 2009 00:00:00', 'UTCG')
    fm.Time.TimeSpan.Set('45', 'min')

    # Configure the burn parameters
    fm.Thrust.Specification = 'ByComponent'
    fm.Thrust.ThrustX.Set(0, 'N')
    fm.Thrust.ThrustY.Set(0, 'N')
    fm.Thrust.ThrustZ.Set(2, 'lbf')

    # Configure the mass loss
    fm.Mass.LossMethod = 'BasedOnIsp'
    fm.Mass.Isp.Set(325.0, 'sec')

    # Configure the burn uncertainty
    fm.Uncertainty.Type = '%MagnitudeAndPointing'
    fm.Uncertainty.PercentMagnitudeSigma.Set(3.0, '%')
    fm.Uncertainty.PointingSigma.Set(1.5, 'deg')
    fm.Uncertainty.MagnitudeHalfLife.Set(1, 'hr')
    fm.Uncertainty.PointingHalfLife.Set(1, 'hr')

# Add in a second maneuver as a dummy maneuver just
# to prove that we can find the right maneuver
fm_iter = finite_maneuvers.InsertNew('FiniteManConstThrust')

if fm_iter.IsSafeToDereference():
    fm = fm_iter.Dereference()

    # We'll set the name and accept the defaults for all the
    # other parameters.
    fm.Name = 'FMTest2'

# Now try to find the first maneuver and report the
# thrust.

fm_iter = finite_maneuvers.FindByName('FMTest1')
if fm_iter.IsSafeToDereference():
    fm = fm_iter.Dereference()

    print(f'Found maneuver {str(fm.Name.eval())}\nThrust is {fm.Thrust.ThrustZ.GetIn("lbf")} lbf')

# Now delete the second maneuver

fm_iter = finite_maneuvers.FindByName('FMTest2')

if fm_iter.IsSafeToDereference():
    fm = fm_iter.Dereference()

    print(f'Found maneuver {fm.Name.eval()}\nThrust is {fm.Thrust.ThrustZ.GetIn("lbf")} lbf')

    finite_maneuvers.RemoveByName('FMTest2')

# Verify that the second maneuver is gone.

fm_iter = finite_maneuvers.FindByName('FMTest2')
if not fm_iter.IsSafeToDereference():
    print('Second maneuver was deleted')

# -------------------------------------------------------
# Impulsive maneuver example
# -------------------------------------------------------

# Clear out any existing instant maneuvers and add a new
# one in.

instant_maneuvers = satellite.ForceModel.InstantManeuvers
instant_maneuvers.clear()

# Create a new maneuver to model an in-track Delta-V

im_iter = instant_maneuvers.InsertNew('InstantManDeltaV')

if im_iter.IsSafeToDereference():
    im = im_iter.Dereference()

    im.Name = 'IMTest1'
    im.Enabled = True
    im.Frame = 'Gaussian (RIC)'

    # Configure the burn time (assumes the actual burn is
    # 4 minutes long but is modeled as an impulsive burn)

    im.Epoch.Set('1 Jan 2009 01:23:45', 'UTCG')
    im.TimeAfterStart.Set(2, 'min')
    im.TimeBeforeEnd.Set(2, 'min')

    # Configure the burn parameters

    im.DeltaV.Specification = 'ByComponent'
    im.DeltaV.DeltaVX.Set(0.0, 'm/sec')
    im.DeltaV.DeltaVY.Set(0.1, 'm/sec')
    im.DeltaV.DeltaVZ.Set(0.0, 'm/sec')

    # Configure the mass loss

    im.Mass.LossMethod = 'Explicit'
    im.Mass.MassLoss.Set(1, 'kg')

    # Configure the burn uncertainty

    im.Uncertainty.Type = 'ByComponent'
    im.Uncertainty.XSigma.Set(0.01, 'm/sec')
    im.Uncertainty.YSigma.Set(0.02, 'm/sec')
    im.Uncertainty.ZSigma.Set(0.01, 'm/sec')

# Add in a second maneuver as a dummy maneuver just
# to prove that we can find the right maneuver

im_iter = instant_maneuvers.InsertNew('InstantManDeltaV')

if im_iter.IsSafeToDereference():
    im = im_iter.Dereference()

    # We'll set the name and accept the defaults for all the
    # other parameters.

    im.Name = 'IMTest2'

# Now try to find the first maneuver and report the Delta-V

im_iter = instant_maneuvers.FindByName('IMTest1')
if im_iter.IsSafeToDereference():
    im = im_iter.Dereference()
    print(f'Found maneuver {im.Name.eval()}\nDelta-V is {im.DeltaV.DeltaVY.GetIn("m/sec")}m/sec')

# Now delete the second maneuver

im_iter = instant_maneuvers.FindByName('IMTest2')

if im_iter.IsSafeToDereference():
    print('Found second maneuver')

    instant_maneuvers.RemoveByName('IMTest2')

# Verify that it is gone.

im_iter = instant_maneuvers.FindByName('IMTest2')
if not im_iter.IsSafeToDereference():
    print('Second maneuver was deleted')
                
MATLAB
% -------------------------------------------------------
% Finite maneuver example
% -------------------------------------------------------

% Clear out any existing finite maneuvers and add a new
% one in.

finiteManeuvers = satellite.ForceModel.FiniteManeuvers;
finiteManeuvers.clear();

% Create a new maneuver to model a cross-track delta-I
fmIter = finiteManeuvers.InsertNew("FiniteManConstThrust");
if fmIter.IsSafeToDereference()
    fm = fmIter.Dereference();

    fm.Name = "FMTest1";
    fm.Enabled = true;
    fm.Frame = "Gaussian (RIC)";
    fm.Estimate = "MagnitudeAndPointing";

    % Configure the burn time
    fm.Time.StopMode = "TimeSpan";
    fm.Time.StartTime.Set("1 Jun 2009 00:00:00", "UTCG");
    fm.Time.TimeSpan.Set("45", "min");

    % Configure the burn parameters
    fm.Thrust.Specification = "ByComponent";
    fm.Thrust.ThrustX.Set(0, "N");
    fm.Thrust.ThrustY.Set(0, "N");
    fm.Thrust.ThrustZ.Set(2, "lbf");

    % Configure the mass loss
    fm.Mass.LossMethod = "BasedOnIsp";
    fm.Mass.Isp.Set(325.0, "sec");

    % Configure the burn uncertainty
    fm.Uncertainty.Type = "%MagnitudeAndPointing";
    fm.Uncertainty.PercentMagnitudeSigma.Set(3.0, "%");
    fm.Uncertainty.PointingSigma.Set(1.5, "deg");
    fm.Uncertainty.MagnitudeHalfLife.Set(1, "hr");
    fm.Uncertainty.PointingHalfLife.Set(1, "hr");
end

% Add in a second maneuver as a dummy maneuver just
% to prove that we can find the right maneuver
fmIter = finiteManeuvers.InsertNew("FiniteManConstThrust");

if fmIter.IsSafeToDereference()
    fm = fmIter.Dereference();

    % We'll set the name and accept the defaults for all the
    % other parameters.
    fm.Name = "FMTest2";
end

% Now try to find the first maneuver and report the
% thrust.

fmIter = finiteManeuvers.FindByName("FMTest1");
if fmIter.IsSafeToDereference()
    fm = fmIter.Dereference();

    fprintf("Found maneuver %s\nThrust is %f lbf\n", fm.Name, fm.Thrust.ThrustZ.GetIn("lbf"));
end

% Now delete the second maneuver

fmIter = finiteManeuvers.FindByName("FMTest2");
if fmIter.IsSafeToDereference()
    fm = fmIter.Dereference();

    fprintf("Found maneuver %s\nThrust is %f lbf\n", fm.Name, fm.Thrust.ThrustZ.GetIn("lbf"));

    finiteManeuvers.RemoveByName("FMTest2");
end

% Verify that the second maneuver is gone.

fmIter = finiteManeuvers.FindByName("FMTest2");
if ~fmIter.IsSafeToDereference()
    fprintf("Second maneuver was deleted\n");
end

% -------------------------------------------------------
% Impulsive maneuver example
% -------------------------------------------------------

% Clear out any existing instant maneuvers and add a new
% one in.

instantManeuvers = satellite.ForceModel.InstantManeuvers;
instantManeuvers.clear();

% Create a new maneuver to model an in-track Delta-V

imIter = instantManeuvers.InsertNew("InstantManDeltaV");

if imIter.IsSafeToDereference()
    im = imIter.Dereference();

    im.Name = "IMTest1";
    im.Enabled = true;
    im.Frame = "Gaussian (RIC)";

    % Configure the burn time (assumes the actual burn is
    % 4 minutes long but is modeled as an impulsive burn)

    im.Epoch.Set("1 Jan 2009 01:23:45", "UTCG");
    im.TimeAfterStart.Set(2, "min");
    im.TimeBeforeEnd.Set(2, "min");

    % Configure the burn parameters

    im.DeltaV.Specification = "ByComponent";
    im.DeltaV.DeltaVX.Set(0.0, "m/sec");
    im.DeltaV.DeltaVY.Set(0.1, "m/sec");
    im.DeltaV.DeltaVZ.Set(0.0, "m/sec");

    % Configure the mass loss

    im.Mass.LossMethod = "Explicit";
    im.Mass.MassLoss.Set(1, "kg");

    % Configure the burn uncertainty

    im.Uncertainty.Type = "ByComponent";
    im.Uncertainty.XSigma.Set(0.01, "m/sec");
    im.Uncertainty.YSigma.Set(0.02, "m/sec");
    im.Uncertainty.ZSigma.Set(0.01, "m/sec");
end

% Add in a second maneuver as a dummy maneuver just
% to prove that we can find the right maneuver

imIter = instantManeuvers.InsertNew("InstantManDeltaV");

if imIter.IsSafeToDereference()
    im = imIter.Dereference();

    % We'll set the name and accept the defaults for all the
    % other parameters.

    im.Name = "IMTest2";
end

% Now try to find the first maneuver and report the Delta-V

imIter = instantManeuvers.FindByName("IMTest1");
if imIter.IsSafeToDereference()
    im = imIter.Dereference();
    fprintf("Found maneuver %s\nDelta-V is %f m/sec\n", im.Name, im.DeltaV.DeltaVY.GetIn("m/sec"));
end

% Now delete the second maneuver

imIter = instantManeuvers.FindByName("IMTest2");

if imIter.IsSafeToDereference()
    fprintf("Found second maneuver\n");

    instantManeuvers.RemoveByName("IMTest2");
end

% Verify that it is gone.

imIter = instantManeuvers.FindByName("IMTest2");
if ~imIter.IsSafeToDereference()
    fprintf("Second maneuver was deleted\n");
end
                
C++
// ------------------------------------------------------ -
// Finite maneuver example
// ------------------------------------------------------ -

// Clear out any existing finite maneuvers and add a new
// one in.

const agi::odtk::AttrProxy finiteManeuvers = satellite("ForceModel")("FiniteManeuvers");
finiteManeuvers("clear").Invoke();

// Create a new maneuver to model a cross - track delta - I
const agi::odtk::AttrProxy fmIter = finiteManeuvers("InsertNew").InvokeAttrProxy("FiniteManConstThrust");
if (fmIter("IsSafeToDereference").InvokeBool())
{
    const auto fm = fmIter("Dereference").InvokeAttrProxy();

    fm("Name").Assign("FMTest1");
    fm("Enabled").Assign(true);
    fm("Frame").Assign("Gaussian(RIC)");
    fm("Estimate").Assign("MagnitudeAndPointing");

    // Configure the burn time
    fm("Time")("StopMode").Assign("TimeSpan");
    fm("Time")("StartTime")("Set").Invoke("1 Jun 2009 00:00 : 00", "UTCG");
    fm("Time")("TimeSpan")("Set").Invoke("45", "min");

    // Configure the burn parameters
    fm("Thrust")("Specification").Assign("ByComponent");
    fm("Thrust")("ThrustX")("Set").Invoke(0, "N");
    fm("Thrust")("ThrustY")("Set").Invoke(0, "N");
    fm("Thrust")("ThrustZ")("Set").Invoke(2, "lbf");

    // Configure the mass loss
    fm("Mass")("LossMethod").Assign("BasedOnIsp");
    fm("Mass")("Isp")("Set").Invoke(325.0, "sec");

    // Configure the burn uncertainty
    fm("Uncertainty")("Type").Assign("%MagnitudeAndPointing");
    fm("Uncertainty")("PercentMagnitudeSigma")("Set").Invoke(3.0, "%");
    fm("Uncertainty")("PointingSigma")("Set").Invoke(1.5, "deg");
    fm("Uncertainty")("MagnitudeHalfLife")("Set").Invoke(1, "hr");
    fm("Uncertainty")("PointingHalfLife")("Set").Invoke(1, "hr");
}

// Add in a second maneuver as a dummy maneuver just
// to prove that we can find the right maneuver
const auto fmIter2 = finiteManeuvers("InsertNew").InvokeAttrProxy("FiniteManConstThrust");

if (fmIter2("IsSafeToDereference").InvokeBool())
{
    const agi::odtk::AttrProxy fm = fmIter2("Dereference").InvokeAttrProxy();

    // We'll set the name and accept the defaults for all the
    // other parameters.
    fm("Name").Assign("FMTest2");
}

// Now try to find the first maneuver and report the
// thrust.

const agi::odtk::AttrProxy fmIter3 = finiteManeuvers("FindByName").InvokeAttrProxy("FMTest1");
if (fmIter3("IsSafeToDereference").InvokeBool())
{
    const agi::odtk::AttrProxy fm = fmIter3("Dereference").InvokeAttrProxy();

    std::cout << "Found maneuver " << fm("Name").AsString() << "\nThrust is " << fm("Thrust")("ThrustZ")("GetIn").InvokeDouble("lbf") << " lbf\n";
}

// Now delete the second maneuver

const agi::odtk::AttrProxy fmIter4 = finiteManeuvers("FindByName").InvokeAttrProxy("FMTest2");
if (fmIter4("IsSafeToDereference").InvokeBool())
{
    const auto fm = fmIter4("Dereference").InvokeAttrProxy();

    std::cout << "Found maneuver " << fm("Name").AsString() << "\nThrust is " << fm("Thrust")("ThrustZ")("GetIn").InvokeDouble("lbf") << " lbf\n";

    finiteManeuvers("RemoveByName").Invoke("FMTest2");
}

// Verify that the second maneuver is gone.

const agi::odtk::AttrProxy fmIter5 = finiteManeuvers("FindByName").InvokeAttrProxy("FMTest2");
if (!fmIter5("IsSafeToDereference").InvokeBool())
{
    std::cout << "Second maneuver was deleted\n";
}

// ------------------------------------------------------
// Impulsive maneuver example
// ------------------------------------------------------

// Clear out any existing instant maneuvers and add a new
// one in.

const agi::odtk::AttrProxy instantManeuvers = satellite("ForceModel")("InstantManeuvers");
instantManeuvers("clear").Invoke();

// Create a new maneuver to model an in - track delta - V

const agi::odtk::AttrProxy imIter = instantManeuvers("InsertNew").InvokeAttrProxy("InstantManDeltaV");

if (imIter("IsSafeToDereference").InvokeBool())
{
    const auto im = imIter("Dereference").InvokeAttrProxy();

    im("Name").Assign("IMTest1");
    im("Enabled").Assign(true);
    im("Frame").Assign("Gaussian (RIC)");

    // Configure the burn time(assumes the actual burn is
    // 4 minutes long but is modeled as an impulsive burn)

    im("Epoch")("Set").Invoke("1 Jan 2009 01:23:45", "UTCG");
    im("TimeAfterStart")("Set").Invoke(2, "min");
    im("TimeBeforeEnd")("Set").Invoke(2, "min");

    // Configure the burn parameters

    im("DeltaV")("Specification").Assign("ByComponent");
    im("DeltaV")("DeltaVX")("Set").Invoke(0.0, "m/sec");
    im("DeltaV")("DeltaVY")("Set").Invoke(0.1, "m/sec");
    im("DeltaV")("DeltaVZ")("Set").Invoke(0.0, "m/sec");

    // Configure the mass loss

    im("Mass")("LossMethod").Assign("Explicit");
    im("Mass")("MassLoss")("Set").Invoke(1, "kg");

    // Configure the burn uncertainty

    im("Uncertainty")("Type").Assign("ByComponent");
    im("Uncertainty")("XSigma")("Set").Invoke(0.01, "m/sec");
    im("Uncertainty")("YSigma")("Set").Invoke(0.02, "m/sec");
    im("Uncertainty")("ZSigma")("Set").Invoke(0.01, "m/sec");
}

// Add in a second maneuver as a dummy maneuver just
// to prove that we can find the right maneuver

const agi::odtk::AttrProxy imIter2 = instantManeuvers("InsertNew").InvokeAttrProxy("InstantManDeltaV");

if (imIter2("IsSafeToDereference").InvokeBool())
{
    const agi::odtk::AttrProxy im = imIter2("Dereference").InvokeAttrProxy();

    // We'll set the name and accept the defaults for all the
    // other parameters.

    im("Name").Assign("IMTest2");
}

// Now try to find the first maneuver and report the delta - V

const agi::odtk::AttrProxy imIter3 = instantManeuvers("FindByName").InvokeAttrProxy("IMTest1");
if (imIter3("IsSafeToDereference").InvokeBool())
{
    const auto im = imIter3("Dereference").InvokeAttrProxy();
    std::cout << "Found maneuver " << im("Name").AsString() << "\nDelta-V is " << im("DeltaV")("DeltaVY")("GetIn").InvokeDouble("m/sec") << "m/sec\n";
}

// Now delete the second maneuver

const auto imIter4 = instantManeuvers("FindByName").InvokeAttrProxy("IMTest2");
if (imIter4("IsSafeToDereference").InvokeBool())
{
    std::cout << "Found second maneuver\n";

    instantManeuvers("RemoveByName").Invoke("IMTest2");
}

// Verify that it is gone.

const agi::odtk::AttrProxy imIter5 = instantManeuvers("FindByName").InvokeAttrProxy("IMTest2");
if (!imIter5("IsSafeToDereference").InvokeBool())
{
    std::cout << "Second maneuver was deleted\n";
}
                
Add Rectified Sinusoid1D Model

Scripting is similiar to the Finite Manuevers, but below is an example of VBS script code that adds a RevRectifiedSinusoid1D Model in the Radial Direction:

COM

VBScript
Set efSet = sat.ForceModel.EmpiricalForces
efSet.clear()
set efIter = efSet.InsertNew("RevRectifiedSinusoid1D")
if efIter.IsSafeToDereference() then
   set ef = efIter.Dereference()

   ef.Name      = "EFRadial"
   ef.Enabled   = true
   ef.Estimate  = false
   ef.Frame     = "Gaussian (RIC)"
   ef.Direction = "Radial"
   ef.A0Constant.Type = "Vasicek"
   ef.A0Constant.LongTerm.Constant.Set         0,"m*sec^-2"
   ef.A0Constant.LongTerm.Sigma.Set            1e-7,"m*sec^-2"
   ef.A0Constant.ShortTerm.InitialEstimate.Set 0,"m*sec^-2"
   ef.A0Constant.ShortTerm.Sigma.Set           1e-7,"m*sec^-2"
   ef.A0Constant.ShortTerm.HalfLife.Set       200,"min"
   ef.A1SinCoef.Type = "GaussMarkov"
   ef.A1SinCoef.Constant.Set           0,"m*sec^-2"
   ef.A1SinCoef.Sigma.Set             1e-5,"m*sec^-2"
   ef.A1SinCoef.InitialEstimate.Set     0,"m*sec^-2"
   ef.A1SinCoef.HalfLife.Set  360,"min"

   ef.A2CosCoef.Type = "GaussMarkov"
   ef.A2CosCoef.Constant.Set           0,"m*sec^-2"
   ef.A2CosCoef.Sigma.Set             1e-5,"m*sec^-2"
   ef.A2CosCoef.InitialEstimate.Set     0,"m*sec^-2"
   ef.A2CosCoef.HalfLife.Set  360,"min"
End if

Multiple representations: Facility.Position

The Facility.Position is a multiple representation object. Changes must be applied to the entire scope at once to ensure the proper coordinate transformation. To do that, first get position elements in one of the available representations: ToCartesian(), ToGeodetic(), ToGeocentric(), ToCylindrical(), and ToSpherical(). Then modify individual elements of the temp variable and then assign them back at once:

COM

VBScript
set pos = scen.TrackingSystem(0).Facility(0).Position.ToGeodetic()
pos.Lat.Set 10, "deg"
pos.Lon.Set 20, "deg"
pos.Alt.Set 100, "m"
scen.TrackingSystem(0).Facility(0).Position.Assign pos
JScript
var pos = scen.TrackingSystem(0).Facility(0).Position.ToGeodetic();
pos.Lat.Set(10, "deg");
pos.Lon.Set(20, "deg");
pos.Alt.Set(100, "m");
scen.TrackingSystem(0).Facility(0).Position.Assign(pos);
Perl
my $pos = $scen->TrackingSystem(0)->Facility(0)->Position->ToGeodetic();
$pos->Lat->Set(10, "deg");
$pos->Lon->Set(20, "deg");
$pos->Alt->Set(100, "m");
$scen->TrackingSystem(0)->Facility(0)->Position->Assign($pos);
Python
pos = scen.TrackingSystem(0).Facility(0).Position.ToGeodetic()
pos.Lat.Set(10, "deg")
pos.Lon.Set(20, "deg")
pos.Alt.Set(100, "m")
scen.TrackingSystem(0).Facility(0).Position.Assign(pos)
MATLAB
pos = scen.invoke('TrackingSystem').invoke('Item', 0).invoke('Facility').invoke('Item', 0).invoke('Position').invoke('ToGeodetic');

pos.invoke('Lat').invoke('Set', 10, 'deg');
pos.invoke('Lon').invoke('Set', 20, 'deg');
pos.invoke('Alt').invoke('Set', 100, 'm');

scen.invoke('TrackingSystem').invoke('Item', 0).invoke('Facility').invoke('Item', 0).invoke('Position').invoke('Assign', pos);

Cross-Platform API

Python
def print_geodetic_pos(p):
print(f'Lat : {p.Lat.GetIn("deg")} deg, Lon: {p.Lon.GetIn("deg")} deg, Alt: {p.Alt.GetIn("m")} m')


pos = facility.Position.ToGeodetic()
print_geodetic_pos(pos)

pos.Lat.Set(10, 'deg')
pos.Lon.Set(20, 'deg')
pos.Alt.Set(100, 'm')

facility.Position.Assign(pos)
pos = facility.Position.ToGeodetic()
print_geodetic_pos(pos)
                
MATLAB
pos = facility.Position.ToGeodetic();
printGeodeticPos(pos);

pos.Lat.Set(10, 'deg');
pos.Lon.Set(20, 'deg');
pos.Alt.Set(100, 'm');

facility.Position.Assign(pos);
pos = facility.Position.ToGeodetic();
printGeodeticPos(pos);
                
C++
const auto pos = facility("Position")("ToGeodetic").InvokeAttrProxy();
PrintGeodeticPos(pos);

pos("Lat")("Set").Invoke(10, "deg");
pos("Lon")("Set").Invoke(20, "deg");
pos("Alt")("Set").Invoke(100, "m");

facility("Position")("Assign").Invoke(pos);
const auto updatedPos = facility("Position")("ToGeodetic").InvokeAttrProxy();
PrintGeodeticPos(updatedPos);
                

Multiple representations: Satellite.OrbitState

Similarly Satellite.OrbitState's individual members defining the orbit state vector must be changed in a temp variable and then assigned back as a group:

COM

VBScript
set kep = scen.Satellite(0).OrbitState.ToKeplerian()
' Raise altitude by 10 km
newSize = kep.SemiMajorAxis.GetIn("km")
kep.SemiMajorAxis.Set newSize + 10, "km"
' Set the rest of the orbital elements
kep.Epoch.Set "1 Jul 2009 00:00:00", "UTCG"
kep.Eccentricity = 0.00123
kep.TrueArgOfLatitude.Set "33.3", "deg"
kep.Inclination.Set "67.8", "deg"
kep.RAAN.Set "321.123", "deg"
kep.ArgOfPerigee.Set "3.141592654", "rad"
scen.Satellite(0).OrbitState.Assign kep
JScript
var kep = scen.Satellite(0).OrbitState.ToKeplerian();
// Raise altitude by 10 km
var newSize = kep.SemiMajorAxis.GetIn("km");
kep.SemiMajorAxis.Set(newSize + 10, "km");
// Set the rest of the orbital elements
kep.Epoch.Set("1 Jul 2009 00:00:00", "UTCG");
kep.Eccentricity = 0.00123;
kep.TrueArgOfLatitude.Set("33.3", "deg");
kep.Inclination.Set("67.8", "deg");
kep.RAAN.Set("321.123", "deg");
kep.ArgOfPerigee.Set("3.141592654", "rad");
scen.Satellite(0).OrbitState.Assign(kep);
Perl
my $kep = $scen->Satellite(0)->OrbitState->ToKeplerian();
# Raise altitude by 10 km
my $newSize = $kep->SemiMajorAxis->GetIn("km")->{Value};
$kep->SemiMajorAxis->Set($newSize + 10, "km");
# Set the rest of the orbital elements
$kep->Epoch->Set("1 Jul 2009 00:00:00", "UTCG");
$kep->Eccentricity->{Value} = 0.00123;
$kep->TrueArgOfLatitude->Set(33.3, "deg");
$kep->Inclination->Set(67.8, "deg");
$kep->RAAN->Set(321.123, "deg");
$kep->ArgOfPerigee->Set(3.141592654, "rad");
$scen->Satellite(0)->OrbitState->Assign($kep);
Python
kep = scen.Satellite(0).OrbitState.ToKeplerian()
# Raise altitude by 10 km
newSize = kep.SemiMajorAxis.GetIn("km")
kep.SemiMajorAxis.Set(int(newSize) + 10, "km")        #newSize must be casted to an integer to be able to add 10
# Set the rest of the orbital elements
kep.Epoch.Set("1 Jul 2009 00:00:00", "UTCG")
kep.Eccentricity = 0.00123
kep.TrueArgOfLatitude.Set("33.3", "deg")
kep.Inclination.Set("67.8", "deg")
kep.RAAN.Set("321.123", "deg")
kep.ArgOfPerigee.Set("3.141592654", "rad")
scen.Satellite(0).OrbitState.Assign(kep)
MATLAB
kep = scen.invoke('Satellite').invoke('Item', 0).invoke('OrbitState').invoke('ToKeplerian');

% Raise altitude by 10 km

newSize = kep.invoke('SemiMajorAxis').invoke('GetIn', 'km').invoke('Value');
kep.invoke('SemiMajorAxis').invoke('Set', newSize + 10, 'km');

% Set the rest of the orbital elements

kep.invoke('Epoch').invoke('Set', '1 Jul 2009 00:00:00', 'UTCG');
kep.set('Eccentricity', 0.00123);
kep.invoke('TrueArgOfLatitude').invoke('Set', '33.3', 'deg');
kep.invoke('Inclination').invoke('Set', '67.8', 'deg');
kep.invoke('RAAN').invoke('Set', '321.123', 'deg');
kep.invoke('ArgOfPerigee').invoke('Set', '3.141592654', 'rad');

scen.invoke('Satellite').invoke('Item', 0).invoke('OrbitState').invoke('Assign', kep);

Cross-Platform API

Python
def print_keplerian_orbit_state(orbit_state):
    print(f'Epoch : {orbit_state.Epoch.Format("UTCG")} UTCG, Eccentricity: {orbit_state.Eccentricity.eval()}, '
        f'TrueArgOfLatitude: {orbit_state.TrueArgOfLatitude.GetIn("deg")} deg, '
        f'Inclination: {orbit_state.Inclination.GetIn("deg")} deg, '
        f'RAAN: {orbit_state.RAAN.GetIn("deg")} deg, ArgOfPerigee: {orbit_state.ArgOfPerigee.GetIn("rad")} rad')


kep = satellite.OrbitState.ToKeplerian()
print_keplerian_orbit_state(kep)
# Raise altitude by 10 km

newSize = kep.SemiMajorAxis.GetIn('km')
kep.SemiMajorAxis.Set(newSize + 10, 'km')

# Set the rest of the orbital elements

kep.Epoch.Set('1 Jul 2009 00:00:00', 'UTCG')
kep.Eccentricity = 0.00123
kep.TrueArgOfLatitude.Set('33.3', 'deg')
kep.Inclination.Set('67.8', 'deg')
kep.RAAN.Set('321.123', 'deg')
kep.ArgOfPerigee.Set('3.141592654', 'rad')

kep = satellite.OrbitState.Assign(kep)
print_keplerian_orbit_state(satellite.OrbitState.ToKeplerian())
                
MATLAB
kep = satellite.OrbitState.ToKeplerian();
printKeplerianOrbitState(kep);
% Raise altitude by 10 km

newSize = kep.SemiMajorAxis.GetIn("km");
kep.SemiMajorAxis.Set(newSize + 10, "km");

% Set the rest of the orbital elements

kep.Epoch.Set("1 Jul 2009 00:00:00", "UTCG");
kep.Eccentricity = 0.00123;
kep.TrueArgOfLatitude.Set("33.3", "deg");
kep.Inclination.Set("67.8", "deg");
kep.RAAN.Set("321.123", "deg");
kep.ArgOfPerigee.Set("3.141592654", "rad");

kep = satellite.OrbitState.Assign(kep);
printKeplerianOrbitState(satellite.OrbitState.ToKeplerian());
                
C++
const agi::odtk::AttrProxy kep = satellite("OrbitState")("ToKeplerian").InvokeAttrProxy();
PrintKeplerianOrbitState(kep);
// Raise altitude by 10 km

const auto newSize = kep("SemiMajorAxis")("GetIn").InvokeDouble("km");
kep("SemiMajorAxis")("Set").Invoke(newSize + 10, "km");

// Set the rest of the orbital elements

kep("Epoch")("Set").Invoke("1 Jul 2009 00:00:00", "UTCG");
kep("Eccentricity").Assign(0.00123);
kep("TrueArgOfLatitude")("Set").Invoke("33.3", "deg");
kep("Inclination")("Set").Invoke("67.8", "deg");
kep("RAAN")("Set").Invoke("321.123", "deg");
kep("ArgOfPerigee")("Set").Invoke("3.141592654", "rad");

satellite("OrbitState")("Assign").Invoke(kep);
PrintKeplerianOrbitState(satellite("OrbitState")("ToKeplerian").InvokeAttrProxy());
                

Type LINKTOOBJ with "not specified" choice

The LINKTOOBJ type is a pointer to a specific group of objects, which sometimes can offer a "not specified" choice. Examples are the GNSSReceiver.DefaultAntenna, Transponder.DefaultAntenna, and Facility.ReferenceEmitter attributes.

COM

VBScript
set gpsr = scen.Satellite(0).GNSSReceiver(0)
for each cc in gpsr.DefaultAntenna.Choices
  if varType(cc) = vbString then
      msgbox cc
  else
      msgbox cc.name
  end if
next
gpsr.DefaultAntenna = "not specified"
msgbox "Antenna 1:" & gpsr.DefaultAntenna.ID
gpsr.DefaultAntenna = gpsr.Antenna(0)
msgbox "Antenna 2:" & gpsr.DefaultAntenna.ID
Python
gpsr = scen.Satellite(0).GNSSReceiver(0)
for cc in gpsr.DefaultAntenna.Choices:
  if type(cc) == str:
      print(cc)
  else:
      print(cc.name)
gpsr.DefaultAntenna = "not specified"
print("Antenna 1:" + str(gpsr.DefaultAntenna.ID))
gpsr.DefaultAntenna = gpsr.Antenna(0)
print("Antenna 2:" + str(gpsr.DefaultAntenna.ID))

Cross-Platform API

Python
gpsr = odtk.application.createObj(satellite, 'GNSSReceiver', 'GNSSReceiver1')
antenna = odtk.application.createObj(gpsr, 'Antenna', 'Antenna1')
for choice in gpsr.DefaultAntenna.Choices:
    choiceVal = choice.eval()
    if type(choiceVal) == str:
        print(choiceVal)
    else:
        print(choiceVal.name.eval())

gpsr.DefaultAntenna = 'not specified'
print("Antenna 1: " + str(gpsr.DefaultAntenna.ID.eval()))
gpsr.DefaultAntenna = gpsr.Antenna[0]
print("Antenna 2: " + str(gpsr.DefaultAntenna.ID.eval()))
                
MATLAB
gpsr = odtk.application.createObj(satellite, "GNSSReceiver", 'GNSSReceiver1');
antenna = odtk.application.createObj(gpsr, "Antenna", "Antenna1");
for i = 0: gpsr.DefaultAntenna.Choices.Count-1
    choice = gpsr.DefaultAntenna.Choices{i};
    if isa(choice, 'string')
        fprintf("%s\n", choice);
    else
        fprintf("%s\n", choice.name);
    end
end

gpsr.DefaultAntenna = "not specified";
fprintf("Antenna 1: %s\n", gpsr.DefaultAntenna.ID);
gpsr.DefaultAntenna = gpsr.Antenna{0};
fprintf("Antenna 2: %s\n", gpsr.DefaultAntenna.ID);
                
C++
const agi::odtk::AttrProxy gpsr = odtk("application")("createObj").InvokeAttrProxy(satellite, "GNSSReceiver", "GNSSReceiver1");
const agi::odtk::AttrProxy antenna = odtk("application")("createObj").InvokeAttrProxy(gpsr, "Antenna", "Antenna1");
for (int i = 0; i < gpsr("DefaultAntenna")("Choices")("Count").AsInt(); i++)
{
    // Invoke 'GetValue' to get a Variant since we don't know the type of choice (either string or AttrProxy)
    const auto choice = gpsr("DefaultAntenna")("Choices")[i].GetValue();
    // Use the 'holds' helper method to check for the type
    if (agi::odtk::holds<std::string(choice))
    {
        // Use the 'as' helper method to convert the Variant
        std::cout << agi::odtk::as<std::string>(choice) << "\n";
    }
    else
    {
        // Use the 'as' helper method to convert the Variant, then get then name
        std::cout << agi::odtk::as<agi::odtk::AttrProxy>(choice)("name").AsString() << "\n";
    }
}

gpsr("DefaultAntenna").Assign("not specified");
std::cout << "Antenna 1: " << gpsr("DefaultAntenna")("ID").AsString() << "\n";
gpsr("DefaultAntenna").Assign(gpsr("Antenna")[0]);
std::cout << "Antenna 2: " << gpsr("DefaultAntenna")("ID").AsString() << "\n";
                

Product Builder: Creating Reports and Graphs

The Product Builder provides the capability to generate and export reports and graphs as well as save and load product lists for later use. Use the ScriptingTool "Props" function to explore ODTK.ProductBuilder's interface in more details.

The methods GenerateAllProducts, GenerateProduct, LoadDataProductList, and SaveDataProductList and their arguments are explained in the Help under Integrating with ODTK | Scripting | Functional Attributes Used in Scripting.

When creating reports and graphs from a script, there are two common approaches that are used. The first is to manually build up a data product list. The script then loads the data product list and edits the properties of each data product as need be. The other approach is to use a new data product list and build a complete data product on the fly. The advantage of the former approach is that the script is using the same data product list that an analyst would.

Using an Existing Data Product List

The script example below was used to process measurements for the TDRS constellation and some of its user satellites. It performs a series of 10 1-day filter runs. After each run it generates various data products using an existing data product list called TDRS6 and dumps them to disk. The data product list was built manually ahead of time by the analyst.

COM

VBScript
option explicit
dim unused, odApp, ODTK, sc, f, s, i, diffile
dim product, topdir, outputdir, rundir
dim fso, sat
' Define how long each run should be in hours
dim durHours
durHours = 24
' Define how many runs to perform
dim numRuns
numRuns = 10
topdir = "C:\Temp\TDRS\"
' Define where the outputs will go
outputdir = topdir & "Outputs\"
Set FSO = CreateObject("Scripting.FileSystemObject")
'-----------------------------------------------------------------
' Grab ODTK COM object
'-----------------------------------------------------------------
set odApp = GetObject(, "ODTK.Application")
If Err.Number <> 0 Then
    MsgBox("ODTK not running")
End If
set ODTK = odApp.Personality
set sc = ODTK.Scenario(0)
set f = sc.Filter(0)
set s = sc.Smoother(0)
f.ProcessControl.StopMode = "TimeSpan"
set unused =  f.ProcessControl.TimeSpan.Set(durHours, "hr")

for i = 1 to numRuns
    runDir = outputdir & "run " & i & "\"
    if not fso.FolderExists(rundir) then
        fso.createfolder(rundir)
    end if

    '-----------------------------------------------------------------
    ' Run the filter. If it's not the first run, then we will be in
    ' restart mode.
    '-----------------------------------------------------------------
    if (i = 1) then
        f.ProcessControl.StartMode = "Initial"
    else
        f.ProcessControl.StartMode = "AutoRestart"
    end if

    f.Output.STKEphemeris.OutputDirectory = runDir

    f.Go

    '-----------------------------------------------------------------
    ' Run the smoother
    '-----------------------------------------------------------------
    s.Output.STKEphemeris.OutputDirectory = runDir

    s.Go

    '-----------------------------------------------------------------
    ' Difference the runs
    '-----------------------------------------------------------------
    diffile = f.Output.DataArchive.Filename
    diffile = replace(diffile, "filrun", "difrun")
    ' Using empty dates as the start and stop implies that all available
    ' information should be used.

    ODTK.CreateDifference diffile, s.Output.DataArchive.Filename, f.Output.DataArchive.Filename, true, "", "", false
    '-----------------------------------------------------------------
    ' Generate reports and graphs
    '-----------------------------------------------------------------
    ODTK.ProductBuilder.LoadDataProductList(topdir & "\TDRS6.dpl")
    ' Loop through each of the satellites that the filter processed.

    for each sat in f.SatelliteList

        ' Create TDRS specific products
        if left(sat, 4) = "TDRS" then

            GenSatProduct sat, "Range Residuals"
            GenSatProduct sat, "BRTS Range Residuals"
            GenSatProduct sat, "SRP estimate"
        else

            ' Create non TDRS products

            GenSatProduct sat, "Doppler Residuals"
            GenSatProduct sat, "4L Range Residuals"

        end if

        GenSatProduct sat, "Filter Position Uncertainty"
        GenSatProduct sat, "Smoother Position Uncertainty"
        GenSatProduct sat, "Position Consistency"

    next

    GenSatProduct "", "Instant Mnvr Summary"
    GenSatProduct "", "BRTS Transponder Bias"
    GenSatProduct "", "Relay Transponder Bias"


    ' Reload the data product list to reset all the settings we used earlier.
    ' don't want to confuse the user if they want to create some products manually.
    ODTK.ProductBuilder.LoadDataProductList(topdir & "\TDRS6.dpl")
    ' Close any report or graph windows that are up
    closeOutputWindows

next
'-----------------------------------------------------------------
' Routine for generating specific products with optional
' satellite filter.  Sat is the name of a specific satellite and
' prod_name is the name of the product in the data product list.
'-----------------------------------------------------------------
sub GenSatProduct(sat, prod_name)
    dim extension, product

    ' Go find the requested product

    for each product in ODTK.ProductBuilder.DataProducts

        if (product.Name = prod_name) then
            ' Set the input filters. This is where we limit
            ' by the specific satellite

            product.Inputs.SatelliteList.clear()
            if (sat <> "") then
                product.Inputs.SatelliteList.push_back(sat)
            end if

            ' Configure where the product will go.
            product.Outputs.Display = false
            product.Outputs.Export.Enabled = true
            product.Outputs.Export.DestinationType = "File"
            if (product.Type = "Graph") then
                product.Outputs.Export.Format = "PNG"
                extension = "png"
            else
                product.Outputs.Export.Format = "PDF"
                extension = "pdf"
            end if
            ' Build an output file path
            if sat <> "" then
                product.Outputs.Export.FileName = rundir & sat & "_" & prod_name & "." & extension
            else
                product.Outputs.Export.FileName = rundir             & prod_name & "." & extension
            end if

            ' Create product and save it to disk.
            set unused = ODTK.ProductBuilder.GenerateProduct(prod_name)
            set unused = nothing

            exit for

        end if
    next
end sub
sub closeOutputWindows
    dim w

    for each w in odapp.windows
        if left(w.Caption,12) = "Graph Viewer"  or left(w.Caption,13) = "Report Viewer" then
            w.Close
        end if
    next
end sub
JScript
var unused, odApp, ODTK, sc, f, s, i, diffile;
var product, topdir, outputdir, rundir;
var fso, sat;
// Define how long each run should be in hours
var durHours;
durHours = 24;
// Define how many runs to perform
var numRuns;
numRuns = 10;
topdir = "C:\\Temp\\TDRS\\";
// Define where the outputs will go
outputdir = topdir + "Outputs\\";
fso = new ActiveXObject("Scripting.FileSystemObject");
//-----------------------------------------------------------------
// Grab ODTK COM object
//-----------------------------------------------------------------
odApp = GetObject("", "ODTK.Application");
ODTK = odApp.Personality;
sc = ODTK.Scenario(0);
f = sc.Filter(0);
s = sc.Smoother(0);
f.ProcessControl.StopMode = "TimeSpan";
unused =  f.ProcessControl.TimeSpan.Set(durHours, "hr");

for(var i = 1; i < numRuns; i++)
{
    runDir = new String(outputdir + "run " + i + "\\");
    if(fso.FolderExists(runDir) == false)
    {
        fso.CreateFolder(runDir);
    }

    //-----------------------------------------------------------------
    // Run the filter. If it's not the first run, then we will be in
    // restart mode.
    //-----------------------------------------------------------------
    if(i == 1)
    {
        f.ProcessControl.StartMode = "Initial";
    }
    else
    {
        f.ProcessControl.StartMode = "AutoRestart";
    }

    f.Output.STKEphemeris.OutputDirectory = runDir.toString();

    f.Go();

    //-----------------------------------------------------------------
    // Run the smoother
    //-----------------------------------------------------------------
    s.Output.STKEphemeris.OutputDirectory = runDir.toString();

    s.Go();

    //-----------------------------------------------------------------
    //Difference the runs
    //-----------------------------------------------------------------
    diffile = new String(f.Output.DataArchive.Filename);
    diffile = diffile.replace(/filrun/gi, "difrun");
    // Using empty dates as the start and stop implies that all available
    // information should be used.

    ODTK.CreateDifference(diffile, s.Output.DataArchive.Filename, f.Output.DataArchive.Filename, true, "", "", false);
    //-----------------------------------------------------------------
    // Generate reports and graphs
    //-----------------------------------------------------------------
    ODTK.ProductBuilder.LoadDataProductList(topdir + "\\TDRS6.dpl");
    // Loop through each of the satellites that the filter processed.

    for (var k = 0; k < f.SatelliteList.Count; k++)
    {

        // Create TDRS specific products
        if (SatelliteList(k).substr(0,4) == "TDRS" )
        {

            GenSatProduct(SatelliteList(k), "Range Residuals");
            GenSatProduct(SatelliteList(k), "BRTS Range Residuals");
            GenSatProduc(SatelliteList(k), "SRP estimate");
        }
        else
        {

            // Create non TDRS products

            GenSatProduct(SatelliteList(k), "Doppler Residuals");
            GenSatProduct(SatelliteList(k), "4L Range Residuals");
        }

        GenSatProduct(SatelliteList(k), "Filter Position Uncertainty");
        GenSatProduct(SatelliteList(k), "Smoother Position Uncertainty");
        GenSatProduct(SatelliteList(k), "Position Consistency");

    }

    GenSatProduct("", "Instant Mnvr Summary");
    GenSatProduct("", "BRTS Transponder Bias");
    GenSatProduct("", "Relay Transponder Bias");


    // Reload the data product list to reset all the settings we used earlier.
    // don't want to confuse the user if they want to create some products manually.
    ODTK.ProductBuilder.LoadDataProductList(topdir + "\\TDRS6.dpl");
    // Close any report or graph windows that are up
    closeOutputWindows();
}
//-----------------------------------------------------------------
// Routine for generating specific products with optional
// satellite filter.  Sat is the name of a specific satellite and
// prod_name is the name of the product in the data product list.
//-----------------------------------------------------------------
function GenSatProduct(sat, prod_name)
{
    var extension;

    // Go find the requested product

    for(var i = 0; i < ODTK.ProductBuilder.DataProducts.Count; i++)
    {
        if (ODTK.ProductBuilder.DataProducts(i).Name == prod_name)
        {
            // Set the input filters. This is where we limit
            // by the specific satellite

            ODTK.ProductBuilder.DataProducts(i).Inputs.SatelliteList.clear();
            if (sat != "")
            {
                ODTK.ProductBuilder.DataProducts(i).Inputs.SatelliteList.push_back(sat);
            }

            // Configure where the product will go.
            ODTK.ProductBuilder.DataProducts(i).Outputs.Display = false;
            ODTK.ProductBuilder.DataProducts(i).Outputs.Export.Enabled = true;
            ODTK.ProductBuilder.DataProducts(i).Outputs.Export.DestinationType = "File";
            if (ODTK.ProductBuilder.DataProducts(i).Type == "Graph")
            {
                ODTK.ProductBuilder.DataProducts(i).Outputs.Export.Format = "PNG";
                extension = "png";
            }
            else
            {
                ODTK.ProductBuilder.DataProducts(i).Outputs.Export.Format = "PDF";
                extension = "pdf";
            }
            // Build an output file path
            if (sat != "")
            {
                ODTK.ProductBuilder.DataProducts(i).Outputs.Export.FileName = rundir + sat + "_" + prod_name + "." + extension;
            }
            else
            {
                ODTK.ProductBuilder.DataProducts(i).Outputs.Export.FileName = rundir + prod_name + "." + extension;
            }

            // Create product and save it to disk.
            var unused = ODTK.ProductBuilder.GenerateProduct(prod_name);
            unused = nothing;
        }
    }
}
function closeOutputWindows()
{
    for(var i = 0; i < odApp.windows.Count; i++)
    {
        if ( odApp.windows(i).Caption.substr(0,12) == "Graph Viewer"  || odApp.windows(i).Caption.substr(0,13) == "Report Viewer")
        {
            w.Close();
        }
    }
}
Python
# os must be imported
#-----------------------------------------------------------------
# Routine for generating specific products with optional
# satellite filter.  Sat is the name of a specific satellite and
# prod_name is the name of the product in the data product list.
#-----------------------------------------------------------------
def GenSatProduct(sat, prod_name):
# Go find the requested product

    for product in ODTK.ProductBuilder.DataProducts:

        if (product.Name == prod_name):
            # Set the input filters. This is where we limit
            # by the specific satellite

            product.Inputs.SatelliteList.clear()
            if sat != "":
                product.Inputs.SatelliteList.push_back(sat)

            # Configure where the product will go.
            product.Outputs.Display = False
            product.Outputs.Export.Enabled = True
            product.Outputs.Export.DestinationType = "File"
            if product.Type == "Graph":
                product.Outputs.Export.Format = "PNG"
                extension = "png"
            else:
                product.Outputs.Export.Format = "PDF"
                extension = "pdf"
            # Build an output file path
            if sat != "":
                product.Outputs.Export.FileName = rundir + sat + "_" + prod_name + "." + extension
            else:
                product.Outputs.Export.FileName = rundir + prod_name + "." + extension

            # Create product and save it to disk.
            ODTK.ProductBuilder.GenerateProduct(prod_name)
# Grabs amount of characters from left side of string
def left(string, amount):
    return string[:amount]

def closeOutputWindows():
    for w in odApp.windows:
        if left(w.Caption,12) == "Graph Viewer"  or left(w.Caption,13) == "Report Viewer":
            w.Close()
# Define how long each run should be in hours
durHours = 24
# Define how many runs to perform
numRuns = 10
topdir = "C:\\Temp\\TDRS\\"
# Define where the outputs will go
outputdir = topdir + "Outputs\\"
fso = w32c.Dispatch("Scripting.FileSystemObject")
#-----------------------------------------------------------------
# Grab ODTK COM object
#-----------------------------------------------------------------
odApp = w32c.GetActiveObject("ODTK.Application")
ODTK = odApp.Personality
sc = ODTK.Scenario(0)
f = sc.Filter(0)
s = sc.Smoother(0)
f.ProcessControl.StopMode = "TimeSpan"
f.ProcessControl.TimeSpan.Set(durHours, "hr")

for i in range(1,numRuns):
    runDir = outputdir + "run " + str(i) + "\\"
    if not os.path.exists(runDir):
        os.makedirs(runDir)

    #-----------------------------------------------------------------
    # Run the filter. If it's not the first run, then we will be in
    # restart mode.
    #-----------------------------------------------------------------
    if i == 1:
        f.ProcessControl.StartMode = "Initial"
    else:
        f.ProcessControl.StartMode = "AutoRestart"

    f.Output.STKEphemeris.OutputDirectory = runDir

    f.Go()

    #-----------------------------------------------------------------
    # Run the smoother
    #-----------------------------------------------------------------
    s.Output.STKEphemeris.OutputDirectory = runDir

    s.Go()

    #-----------------------------------------------------------------
    # Difference the runs
    #-----------------------------------------------------------------
    diffile = str(f.Output.DataArchive.Filename)
    diffile = diffile.replace("filrun", "difrun")
    # Using empty dates as the start and stop implies that all available
    # information should be used.

    ODTK.CreateDifference(diffile, s.Output.DataArchive.Filename, f.Output.DataArchive.Filename, True, "", "", False)
    #-----------------------------------------------------------------
    # Generate reports and graphs
    #-----------------------------------------------------------------
    ODTK.ProductBuilder.LoadDataProductList(topdir + "\\TDRS6.dpl")
    # Loop through each of the satellites that the filter processed.

    for sat in f.SatelliteList:

        # Create TDRS specific products
        if left(sat, 4) == "TDRS":

            GenSatProduct(sat, "Range Residuals")
            GenSatProduct(sat, "BRTS Range Residuals")
            GenSatProduct(sat, "SRP estimate")
        else:

            # Create non TDRS products

            GenSatProduct(sat, "Doppler Residuals")
            GenSatProduct(sat, "4L Range Residuals")

        GenSatProduct(sat, "Filter Position Uncertainty")
        GenSatProduct(sat, "Smoother Position Uncertainty")
        GenSatProduct(sat, "Position Consistency")

    GenSatProduct("", "Instant Mnvr Summary")
    GenSatProduct("", "BRTS Transponder Bias")
    GenSatProduct("", "Relay Transponder Bias")


    # Reload the data product list to reset all the settings we used earlier.
    # don't want to confuse the user if they want to create some products manually.
    ODTK.ProductBuilder.LoadDataProductList(topdir + "\\TDRS6.dpl")
    # Close any report or graph windows that are up
    closeOutputWindows()

Cross-Platform

Python
# Using an Existing Data Product List

# The script example below was used to process measurements for the TDRS constellation and some of its user
# satellites. It performs a series of 10 1-day filter runs. After each run it generates various data products using
# an existing data product list called TDRS6 and dumps them to disk. The data product list was built manually ahead
# of time by the analyst.

# -----------------------------------------------------------------
# Routine for generating specific products with optional
# satellite filter.  Sat is the name of a specific satellite and
# prod_name is the name of the product in the data product list.
# -----------------------------------------------------------------

def gen_sat_product(sat_name, prod_name, run_dir_path):
    # Go find the requested product

    for product in odtk.ProductBuilder.DataProducts:

        if product.Name.eval() == prod_name:

            # Set the input filters. This is where we limit
            # by the specific satellite

            product.Inputs.SatelliteList.clear()
            if sat_name != "":
                product.Inputs.SatelliteList.push_back(sat_name)

            # Configure where the product will go.

            product.Outputs.Display = False
            product.Outputs.Export.Enabled = True
            product.Outputs.Export.DestinationType = 'File'

            if product.Type.eval() == 'Graph':
                product.Outputs.Export.Format = 'PNG'
                extension = 'png'
            else:
                product.Outputs.Export.Format = 'PDF'
                extension = 'pdf'

            # Build an output file path

            if sat_name != '':
                product.Outputs.Export.FileName = f'{run_dir_path}{sat_name}_{prod_name}.{extension}'
            else:
                product.Outputs.Export.FileName = f'{run_dir_path}{prod_name}.{extension}'

            # Create product and save it to disk.

            odtk.ProductBuilder.GenerateProduct(prod_name)
            print(f'Generated {prod_name} for {sat_name}.')

            break


# Load the scenario
if odtk.children.count > 0:
    # close scenario
    odtk.application.deleteObject('', odtk.scenario[0])
    print('Scenario closed.')
scenario_file_path = os.path.abspath(os.path.join(this_dir_path, '..', 'test_resources', 'FDF_TDRS 6.1', 'FDF-OPS.sco'))
odtk.LoadObject('', scenario_file_path)
scenario = odtk.scenario[0]

# Define how long each run should be in hours

duration_hours = 24

# Define how many runs to perform

num_runs = 2

# Define where the outputs will go

output_dir = os.path.join(this_dir_path, 'Outputs')

f = scenario.Filter[0]
s = scenario.Smoother[0]

f.ProcessControl.StopMode = 'TimeSpan'
f.ProcessControl.TimeSpan.Set(duration_hours, 'hr')

data_product_list_path = os.path.join(this_dir_path, '..', 'test_resources', 'FDF_TDRS 6.1', 'FDF-OPS.dpl')
for i in range(1, num_runs+1):

    run_dir = os.path.join(output_dir, f'run {i}', '')

    if not os.path.exists(run_dir):
        os.makedirs(run_dir)

    # -----------------------------------------------------------------
    # Run the filter. If it's not the first run, then we will be in
    # restart mode.
    # -----------------------------------------------------------------

    if i == 1:
        f.ProcessControl.StartMode = 'Initial'
    else:
        f.ProcessControl.StartMode = 'AutoRestart'

    f.Output.STKEphemeris.OutputDirectory = run_dir

    if not f.Go():
        print(f'Filter run {i} failed.')
        exit()

    # -----------------------------------------------------------------
    # Run the smoother
    # -----------------------------------------------------------------

    s.Output.STKEphemeris.OutputDirectory = run_dir

    if not s.Go():
        print(f'Simulator run {i} failed.')
        exit()

    # -----------------------------------------------------------------
    # Difference the runs
    # -----------------------------------------------------------------

    diff_file = f.Output.DataArchive.Filename.value.eval()
    diff_file = diff_file.replace('filrun', 'difrun')

    # Using empty dates as the start and stop implies that all available
    # information should be used.

    if not odtk.CreateDifference(diff_file, s.Output.DataArchive.Filename.value.eval(),
                                f.Output.DataArchive.Filename.value.eval(), True, '', '', False):
        print(f'CreateDifference run {i} failed.')
        exit()

    # -----------------------------------------------------------------
    # Generate reports and graphs
    # -----------------------------------------------------------------

    odtk.ProductBuilder.LoadDataProductList(data_product_list_path)

    # Loop through each of the satellites that the filter processed.

    for sat in f.SatelliteList:

        sat_name = sat.name.eval()
        print(f'Generating products for {sat_name}...')
        # Create TDRS specific products

        if sat_name[:4] == 'TDRS':

            gen_sat_product(sat_name, 'Range Residuals', run_dir)
            gen_sat_product(sat_name, 'BRTS Range Residuals', run_dir)
            gen_sat_product(sat_name, 'SRP estimate', run_dir)

        else:

            # Create non TDRS products

            gen_sat_product(sat_name, 'Doppler Residuals', run_dir)
            gen_sat_product(sat_name, '4L Range Residuals', run_dir)

        gen_sat_product(sat_name, 'Filter Position Uncertainty', run_dir)
        gen_sat_product(sat_name, 'Smoother Position Uncertainty', run_dir)
        gen_sat_product(sat_name, 'Position Consistency', run_dir)

        print(f'Products have been generated for {sat_name}.')

    gen_sat_product('', 'Instant Mnvr Summary', run_dir)
    gen_sat_product('', 'BRTS Transponder Bias', run_dir)
    gen_sat_product('', 'Relay Transponder Bias', run_dir)

    # Reload the data product list to reset all the settings we used earlier.
    # don't want to confuse the user if they want to create some products manually.

    odtk.ProductBuilder.LoadDataProductList(data_product_list_path)
MATLAB
% Using an Existing Data Product List

% The script example below was used to process measurements for the TDRS constellation and some of its user
% satellites. It performs a series of 10 1-day filter runs. After each run it generates various data products using
% an existing data product list called TDRS6 and dumps them to disk. The data product list was built manually ahead
% of time by the analyst.

% Load the scenario
if odtk.children.count > 0
    % close scenario
    odtk.application.deleteObject("", odtk.scenario{0});
    fprintf("Scenario closed.\n");
end
scenarioFilePath = [thisFolderPath, filesep, '..', filesep,  'test_resources', filesep, 'FDF_TDRS 6.1', filesep, 'FDF-OPS.sco'];
odtk.LoadObject("", scenarioFilePath);
scenario = odtk.scenario{0};

% Define how long each run should be in hours

durationHours = 24;

% Define how many runs to perform

numRuns = 2;

% Define where the outputs will go

outputDir = [thisFolderPath, filesep, 'Outputs'];

f = scenario.Filter{0};
s = scenario.Smoother{0};

f.ProcessControl.StopMode = "TimeSpan";
f.ProcessControl.TimeSpan.Set(durationHours, "hr");

dataProductListPath = [thisFolderPath, filesep, '..', filesep,  'test_resources', filesep, 'FDF_TDRS 6.1', filesep, 'FDF-OPS.dpl'];
for i = 1: numRuns

    runDir = [outputDir, filesep, 'run ', int2str(i), filesep];

    if exist(runDir, "dir") ~= 7   % 7 = directory
        mkdir(runDir);
    end

    % -----------------------------------------------------------------
    % Run the filter. If it's not the first run, then we will be in
    % restart mode.
    % -----------------------------------------------------------------

    if i == 1
        f.ProcessControl.StartMode = "Initial";
    else
        f.ProcessControl.StartMode = "AutoRestart";
    end

    f.Output.STKEphemeris.OutputDirectory = runDir;

    if ~f.Go()
        fprintf("Filter run %i failed.\n", i);
        exit();
    end

    % -----------------------------------------------------------------
    % Run the smoother
    % -----------------------------------------------------------------

    s.Output.STKEphemeris.OutputDirectory = runDir;

    if ~s.Go()
        fprintf("Simulator run %i failed.\n", i);
        exit();
    end

    % -----------------------------------------------------------------
    % Difference the runs
    % -----------------------------------------------------------------

    filterOutputFile = f.Output.DataArchive.Filename.value;
    diffFile = replace(filterOutputFile, "filrun", "difrun");

    % Using empty dates as the start and stop implies that all available
    % information should be used.

    if ~odtk.CreateDifference(diffFile, s.Output.DataArchive.Filename.value, ...
            filterOutputFile, true, "", "", false)
        fprintf("CreateDifference run % failed.\n", i);
        exit();
    end

    % -----------------------------------------------------------------
    % Generate reports and graphs
    % -----------------------------------------------------------------

    odtk.ProductBuilder.LoadDataProductList(dataProductListPath);

    % Loop through each of the satellites that the filter processed.
    for j = 0: f.SatelliteList.Count-1
        satelliteName = f.SatelliteList{j}.name;

        fprintf("Generating products for %s...\n", satelliteName);
        % Create TDRS specific products

        if startsWith(satelliteName, "TDRS")
            genSatProduct(odtk, satelliteName, "Range Residuals", runDir);
            genSatProduct(odtk, satelliteName, "BRTS Range Residuals", runDir);
            genSatProduct(odtk, satelliteName, "SRP estimate", runDir);
        else
            % Create non TDRS products
            genSatProduct(odtk, satelliteName, "Doppler Residuals", runDir);
            genSatProduct(odtk, satelliteName, "4L Range Residuals", runDir);
        end

        genSatProduct(odtk, satelliteName, "Filter Position Uncertainty", runDir);
        genSatProduct(odtk, satelliteName, "Smoother Position Uncertainty", runDir);
        genSatProduct(odtk, satelliteName, "Position Consistency", runDir);

        fprintf("Products have been generated for %s.\n", satelliteName);
    end

    genSatProduct(odtk, "", "Instant Mnvr Summary", runDir);
    genSatProduct(odtk, "", "BRTS Transponder Bias", runDir);
    genSatProduct(odtk, "", "Relay Transponder Bias", runDir);

    % Reload the data product list to reset all the settings we used earlier.
    % don't want to confuse the user if they want to create some products manually.

    odtk.ProductBuilder.LoadDataProductList(dataProductListPath);
end

% -----------------------------------------------------------------
% Routine for generating specific products with optional
% satellite filter.  Sat is the name of a specific satellite and
% prod_name is the name of the product in the data product list.
% -----------------------------------------------------------------

function genSatProduct(odtk, satName, prodName, runDirPath)
    % Go find the requested product

    products = odtk.ProductBuilder.DataProducts;
    for i = 0: products.Count-1
        product = products{i};

        if product.Name == prodName

            % Set the input filters. This is where we limit
            % by the specific satellite

            product.Inputs.SatelliteList.clear();
            if satName ~= ""
                product.Inputs.SatelliteList.push_back(satName);
            end

            % Configure where the product will go.

            product.Outputs.Display = false;
            product.Outputs.Export.Enabled = true;
            product.Outputs.Export.DestinationType = "File";

            if product.Type == "Graph"
                product.Outputs.Export.Format = "PNG";
                extension = "png";
            else
                product.Outputs.Export.Format = "PDF";
                extension = "pdf";
            end

            % Build an output file path

            if satName ~= ""
                product.Outputs.Export.FileName = runDirPath + satName + " " + prodName + "." + extension;
            else
                product.Outputs.Export.FileName = runDirPath + prodName + "." + extension;
            end

            % Create product and save it to disk.

            odtk.ProductBuilder.GenerateProduct(prodName);
            fprintf("Generated %s for %s.\n", prodName, satName);

            break;
        end
    end
end

                
C++
// Using an Existing Data Product List

// The script example below was used to process measurements for the TDRS constellation and some of its user
// satellites.It performs a series of 10 1 - day filter runs.After each run it generates various data products using
// an existing data product list called TDRS6 and dumps them to disk.The data product list was built manually ahead
// of time by the analyst.

// Load the scenario
if (odtk("Children")("Count").AsInt() > 0)
{
    // close scenario
    odtk("application")("deleteObject").Invoke("", odtk("scenario")[0]);
    std::cout << "Scenario closed.\n";
}
const auto scenario_file_path = resourcesFolderPath + s_pathSeparator + "FDF_TDRS 6.1" + s_pathSeparator + "FDF-OPS.sco";
odtk("LoadObject").Invoke("", scenario_file_path);

// Define how long each run should be in hours

const auto durationHours = 24;

// Define how many runs to perform

const auto numRuns = 2;

//Define where the outputs will go

const auto outputDir = thisFolderPath + s_pathSeparator + "Outputs";
if (!EnsureDirExists(outputDir))
{
    return;
}

const agi::odtk::AttrProxy scenario = odtk("scenario")[0];
const auto f = scenario("Filter")[0].AsAttrProxy();
const auto s = scenario("Smoother")[0].AsAttrProxy();

f("ProcessControl")("StopMode").Assign("TimeSpan");
f("ProcessControl")("TimeSpan")("Set").Invoke(durationHours, "hr");

const auto dataProductListPath = resourcesFolderPath + s_pathSeparator + "FDF_TDRS 6.1" + s_pathSeparator +
    "FDF-OPS.dpl";

for (int i = 1; i <= numRuns; i++)
{
    const auto runDirPath = outputDir + s_pathSeparator + "run " + std::to_string(i) + s_pathSeparator;

    if (!EnsureDirExists(runDirPath))
    {
        return;
    }

    // Run the filter.If it's not the first run, then we will be in restart mode.

    if (i == 1)
    {
        f("ProcessControl")("StartMode").Assign("Initial");
    }
    else
    {
        f("ProcessControl")("StartMode").Assign("AutoRestart");
    }

    f("Output")("STKEphemeris")("OutputDirectory").Assign(runDirPath);

    if (!f("Go").InvokeBool())
    {
        std::cout << "Filter run " << i << " failed.\n";
        return;
    }

    // Run the smoother

    s("Output")("STKEphemeris")("OutputDirectory").Assign(runDirPath);

    if (!s("Go").InvokeBool())
    {
        std::cout << "Simulator run " << i << " failed.\n";
        return;
    }

    // Difference the runs

    std::string diffFile = f("Output")("DataArchive")("Filename")("value").AsString();
    const std::string filRunString = "filrun";
    diffFile = diffFile.replace(diffFile.find(filRunString), filRunString.length(), "difrun");

    // Using empty dates as the start and stop implies that all available
    // information should be used.

    if (!odtk("CreateDifference").InvokeBool(
        diffFile, s("Output")("DataArchive")("Filename")("value").AsString(),
        f("Output")("DataArchive")("Filename")("value").AsString(), true, "", "", false))
    {
        std::cout << "CreateDifference run " << i << " failed.\n";
        return;
    }

    // Generate reports and graphs

    odtk("ProductBuilder")("LoadDataProductList").Invoke(dataProductListPath);

    // Loop through each of the satellites that the filter processed.
    for (int j = 0; j < f("SatelliteList")("Count").AsInt(); j++)
    {
        const auto satName = f("SatelliteList")[j]("Name").AsString();

        std::cout << "Generating products for " << satName << "...\n";

        // Create TDRS specific products
        if (satName.substr(0, 4) == "TDRS")
        {
            GetSatProduct(odtk, satName, "Range Residuals", runDirPath);
            GetSatProduct(odtk, satName, "BRTS Range Residuals", runDirPath);
            GetSatProduct(odtk, satName, "SRP estimate", runDirPath);
        }
        else
        {
            // Create non TDRS products
            GetSatProduct(odtk, satName, "Doppler Residuals", runDirPath);
            GetSatProduct(odtk, satName, "4L Range Residuals", runDirPath);
        }

        GetSatProduct(odtk, satName, "Filter Position Uncertainty", runDirPath);
        GetSatProduct(odtk, satName, "Smoother Position Uncertainty", runDirPath);
        GetSatProduct(odtk, satName, "Position Consistency", runDirPath);

        std::cout << "Products have been generated for " << satName << ".\n";
    }

    GetSatProduct(odtk, "", "Instant Mnvr Summary", runDirPath);
    GetSatProduct(odtk, "", "BRTS Transponder Bias", runDirPath);
    GetSatProduct(odtk, "", "Relay Transponder Bias", runDirPath);

    // Reload the data product list to reset all the settings we used earlier.
    // don't want to confuse the user if they want to create some products manually.

    odtk("ProductBuilder")("LoadDataProductList").Invoke(dataProductListPath);
}
}

std::string InternalScriptingGuide::GetCurrentWorkingDir()
{
#ifdef _WIN32
    char filePath[MAX_PATH];
    char* currentPath = _getcwd(filePath, sizeof filePath);
#else
    char filePath[PATH_MAX];
    char* currentPath = getcwd(filePath, sizeof filePath);
#endif
    return std::string(currentPath);
}

void InternalScriptingGuide::GetSatProduct(const agi::odtk::AttrProxy& odtk, const std::string& satName,
    const std::string& prodName, const std::string& runDirPath)
{
    // Routine for generating specific products with optional
    // satellite filter. satName is the name of a specific satellite and
    // prodName is the name of the product in the data product list.

    // Go find the requested product
    const agi::odtk::AttrProxy products = odtk("ProductBuilder")("DataProducts");
    for (int i = 0; i < products("Count").AsInt(); i++)
    {
        const auto product = products[i].AsAttrProxy();

        if (product("Name").AsString() == prodName)
        {
            // Set the input filters.This is where we limit
            // by the specific satellite

            product("Inputs")("SatelliteList")("Clear").Invoke();
            if (satName != "")
            {
                product("Inputs")("SatelliteList")("push_back").Invoke(satName);
            }

            // Configure where the product will go.

            product("Outputs")("Display").Assign(false);
            product("Outputs")("Export")("Enabled").Assign(true);
            product("Outputs")("Export")("DestinationType").Assign("File");

            std::string extension;
            if (product("Type").AsString() == "Graph")
            {
                product("Outputs")("Export")("Format").Assign("PNG");
                extension = "png";
            }
            else
            {
                product("Outputs")("Export")("Format").Assign("PDF");
                extension = "pdf";
            }

            // Build an output file path

            if (satName != "")
            {
                product("Outputs")("Export")("FileName").Assign(runDirPath + satName + "_" + prodName + "." + extension);
            }
            else
            {
                product("Outputs")("Export")("FileName").Assign(runDirPath + prodName + "." + extension);
            }

            // Create product and save it to disk.

            odtk("ProductBuilder")("GenerateProduct").Invoke(prodName);
            std::cout << "Generated " << prodName << " for " << satName << "\n";

            break;
            }
        }
    }

    bool InternalScriptingGuide::EnsureDirExists(const std::string& dirPath)
    {
        int errorCode = 0;
    #ifdef _WIN32
        errorCode = _mkdir(dirPath.c_str());
        if (errorCode != 0 && errno == EEXIST)
        {
            return true;
        }
        #else
            mode_t mode = 0733;
            errorCode = mkdir(dirPath.c_str(), mode);
        #endif
            if (errorCode != 0)
            {
                std::cout << "An error occurred while creating directory " << dirPath << ". Error code: " << errorCode << "\n";
            }
            return errorCode == 0;
        }

    const char InternalScriptingGuide::s_pathSeparator =
    #ifdef _WIN32
    '\\';
    #else
    '/';
    #endif
                

Building and Using a Data Product List

The script example below assumes there is no existing data product list. So it builds a data product each time it is called to produce the desired output.

COM

VBScript
set scen = ODTK.Scenario(0)
set unused = ODTK.ProductBuilder.DataProducts.Clear()
ArchiveFile = ODTK.Scenario(0).Filter(0).Output.DataArchive.Filename
RunReport ArchiveFile, "Residuals.gph", ""
RunReport ArchiveFile, "Residual Summary.rpt", "PDF"
' Generic function to build and create a product.
Function RunReport(ArchiveFile, ReportName, ExportFormat)

    ' Find the requested style

    style = ODTK.InstallHome & "/ODTK/AppData/Styles/Static/" & ReportName

    ' Create a new data product at the end of the list

    set newElm = ODTK.ProductBuilder.DataProducts.NewElem()
    set unused = ODTK.ProductBuilder.DataProducts.push_back(newElm)
    index = ODTK.ProductBuilder.DataProducts.size - 1
    set Product = ODTK.ProductBuilder.DataProducts(index)

    ' Configure the the data product

    set newSrc = Product.Inputs.DataSources.NewElem()
    set unused = Product.Inputs.DataSources.push_back(newSrc)

    Product.Name = "Satellite 1 " & ReportName
    Product.Inputs.DataSources(0).Filename = CStr(ArchiveFile)
    Product.Outputs.Style = Style
    Product.Outputs.Display = true

    ' Configure the export if requested

    if ExportFormat <> "" then
        ExpFile = ODTK.UserHome & "\" & Product.Name & "." & ExportFormat
        msgbox ExpFile
        Product.Outputs.Export.Enabled = true
        Product.Outputs.Export.Format = ExportFormat
        Product.Outputs.Export.FileName = CStr(ExpFile)
    end if

    ' Create the product

    ODTK.ProductBuilder.GenerateProduct(Product.Name)

End Function
JScript
var Shell = new ActiveXObject("WScript.Shell");
var scen = ODTK.Scenario(0);
var unused = ODTK.ProductBuilder.DataProducts.Clear();
var ArchiveFile = ODTK.Scenario(0).Filter(0).Output.DataArchive.Filename;
RunReport(ArchiveFile, "Residuals.gph", "");
RunReport(ArchiveFile, "Residual Summary.rpt", "PDF");
// Generic function to build and create a product.
function RunReport(ArchiveFile, ReportName, ExportFormat)
{
    // Find the requested style

    var Style = ODTK.InstallHome + "\\ODTK\\AppData\\Styles\\Static\\" + ReportName;

    // Create a new data product at the end of the list

    var newElm = ODTK.ProductBuilder.DataProducts.NewElem();
    var unused = ODTK.ProductBuilder.DataProducts.push_back(newElm);
    var index = ODTK.ProductBuilder.DataProducts.size - 1;
    var Product = ODTK.ProductBuilder.DataProducts(index);

    // Configure the the data product

    var newSrc = Product.Inputs.DataSources.NewElem();
    unused = Product.Inputs.DataSources.push_back(newSrc);

    Product.Name = "Satellite 1 " + ReportName;
    Product.Inputs.DataSources(0).Filename = String(ArchiveFile);
    Product.Outputs.Style = Style;
    Product.Outputs.Display = true;

    // Configure the export if requested

    if (ExportFormat != "")
    {
        ExpFile = ODTK.UserHome + "\\" + Product.Name + "." + ExportFormat;
        Shell.Popup(ExpFile);
        Product.Outputs.Export.Enabled = true;
        Product.Outputs.Export.Format = ExportFormat;
        Product.Outputs.Export.FileName = String(ExpFile);
    }

    // Create the product

    ODTK.ProductBuilder.GenerateProduct(Product.Name);

}
Python
# Generic function to build and create a product.
def RunReport(ArchiveFile, ReportName, ExportFormat):

    # Find the requested style

    style = str(ODTK.InstallHome) + "\\ODTK\\AppData\\Styles\\Static\\" + ReportName

    # Create a new data product at the end of the list

    newElm = ODTK.ProductBuilder.DataProducts.NewElem()
    unused = ODTK.ProductBuilder.DataProducts.push_back(newElm)
    index = int(ODTK.ProductBuilder.DataProducts.size) - 1
    Product = ODTK.ProductBuilder.DataProducts(index)

    # Configure the the data product

    newSrc = Product.Inputs.DataSources.NewElem()
    unused = Product.Inputs.DataSources.push_back(newSrc)

    Product.Name = "Satellite 1 " + ReportName
    Product.Inputs.DataSources(0).Filename = str(ArchiveFile)
    Product.Outputs.Style = style
    Product.Outputs.Display = True

    # Configure the export if requested

    if ExportFormat != "":
        ExpFile = str(ODTK.UserHome) + "\\" + str(Product.Name) + "." + ExportFormat
        print(ExpFile)
        Product.Outputs.Export.Enabled = True
        Product.Outputs.Export.Format = ExportFormat
        Product.Outputs.Export.FileName = str(ExpFile)

    # Create the product

    ODTK.ProductBuilder.GenerateProduct(Product.Name)

scen = ODTK.Scenario(0)
unused = ODTK.ProductBuilder.DataProducts.Clear()
ArchiveFile = ODTK.Scenario(0).Filter(0).Output.DataArchive.Filename
RunReport(ArchiveFile, "Residuals.gph", "")
RunReport(ArchiveFile, "Residual Summary.rpt", "PDF")

Cross-Platform API

Python
    # Generic function to build and create a product.
    def run_report(input_file_name, style_path, product_name, export_file_path):
    # Create a new data product at the end of the list

    new_elem = odtk.ProductBuilder.DataProducts.NewElem()
    odtk.ProductBuilder.DataProducts.push_back(new_elem)
    index = odtk.ProductBuilder.DataProducts.size.eval() - 1
    product = odtk.ProductBuilder.DataProducts[index]

    # Configure the the data product

    new_src = product.Inputs.DataSources.NewElem()
    product.Inputs.DataSources.push_back(new_src)

    product.Name.Assign(product_name)
    product.Inputs.DataSources[0].Filename = input_file_name
    product.Outputs.Style = style_path
    product.Outputs.Display = True

    product.Outputs.Export.Enabled = True
    product.Outputs.Export.Format = "CommaSeparated"
    product.Outputs.Export.FileName = export_file_path

    # Create the product

    if not odtk.ProductBuilder.GenerateProduct(product_name):
        raise Exception('GenerateProduct failed. Please check the log for more details.')

    print(f'{input_file_name} exported to {export_file_path}')


    odtk.ProductBuilder.DataProducts.Clear()

    archive_file_name = scenario.Filter[0].Output.DataArchive.Filename.value.eval()
    print(f'Archive file: {archive_file_name}')
    style_file_path = os.path.join(this_dir_path, "..", "SharedResources", "measHist.exp")
    output_file_path = os.path.join(this_dir_path, "measHist.txt")
    run_report(archive_file_name, style_file_path, "measHist", output_file_path)

                
MATLAB
    % The script example below assumes there is no existing data product list. So it builds a data product each time it
    % is called to produce the desired output.

    odtk.ProductBuilder.DataProducts.Clear();

    archiveFileName = scenario.Filter{0}.Output.DataArchive.Filename.value;
    fprintf("Archive file: %s\n", archiveFileName);
    styleFilePath = [thisFolderPath, filesep, '..', filesep, 'SharedResources', filesep, 'measHist.exp'];
    outputFilePath = [thisFolderPath, filesep, 'measHist.txt'];
    runReport(odtk, archiveFileName, styleFilePath, "measHist", outputFilePath);


    % Setting a custom location for the ODTK log file

    % By default ODTK will create its log in a user temp directory and delete it upon application exit.
    % However, you may override this by using the following commands:

    appendMode = true;
    logfilePath = [thisFolderPath, filesep, 'log.txt'];
    odtk.Application.SetLogFile(logfilePath, appendMode);

    logLevelDebug = 0;
    logLevelInfo = 1;
    logLevelForceInfo = 2;
    logLevelWarning = 3;
    logLevelError = 4;

    odtk.Application.LogMsg(logLevelInfo, "LogFile = " + odtk.Application.LogFile);
    odtk.Application.LogMsg(logLevelWarning, "This is a warning message.");
    odtk.Application.LogMsg(logLevelError, "This is an error message.");

    % functions

    function printKeplerianOrbitState(os)
        fprintf("Epoch : %s UTCG, Eccentricity: %f, " + ...
            "TrueArgOfLatitude: %f deg, Inclination: %f deg, " + ...
            "RAAN: %f deg, ArgOfPerigee: %f deg rad\n", ...
            os.Epoch.Format("UTCG"), ...
            os.Eccentricity, ...
            os.TrueArgOfLatitude.GetIn("deg"), ...
            os.Inclination.GetIn("deg"), ...
            os.RAAN.GetIn("deg"), ...
            os.ArgOfPerigee.GetIn("rad"));
    end

    function printGeodeticPos(p)
        fprintf("Lat : %f deg, Lon: %f deg, Alt: %f m\n", ...
            p.Lat.GetIn("deg"), ...
            p.Lon.GetIn("deg"), ...
            p.Alt.GetIn("m"));
    end

    % Generic function to build and create a product.
    function runReport(odtk, inputFileName, stylePath, productName, exportFilePath)
        % Create a new data product at the end of the list

        newElem = odtk.ProductBuilder.DataProducts.NewElem();
        odtk.ProductBuilder.DataProducts.push_back(newElem);
        index = odtk.ProductBuilder.DataProducts.size - 1;
        product = odtk.ProductBuilder.DataProducts{index};

        % Configure the the data product

        newSrc = product.Inputs.DataSources.NewElem();
        product.Inputs.DataSources.push_back(newSrc);

        product.Name.Assign(productName);
        product.Inputs.DataSources{0}.Filename = inputFileName;
        product.Outputs.Style = stylePath;
        product.Outputs.Display = true;

        product.Outputs.Export.Enabled = true;
        product.Outputs.Export.Format = "CommaSeparated";
        product.Outputs.Export.FileName = exportFilePath;

        % Create the product

        if ~odtk.ProductBuilder.GenerateProduct(productName)
            throw(MException('ScriptingGuide:unexpectedError', 'GenerateProduct failed. Please check the log for more details.'));
        end
        fprintf("%s exported to %s\n", inputFileName, exportFilePath);
    end
                
C++
// The script example below assumes there is no existing data product list.So it builds a data product each time it
// is called to produce the desired output.

odtk("ProductBuilder")("DataProducts")("Clear").Invoke();

const auto archiveFileName = scenario("Filter")[0]("Output")("DataArchive")("Filename")("value").AsString();
std::cout << "Archive file: " << archiveFileName << "\n";
const std::string styleFilePath = thisFolderPath + s_pathSeparator + ".." + s_pathSeparator + "SharedResources"
    + s_pathSeparator + "measHist.exp";
const std::string outputFilePath = thisFolderPath + s_pathSeparator + "measHist.txt";
RunReport(odtk, archiveFileName, styleFilePath, "measHist", outputFilePath);

std::string ScriptingGuide::GetThisFolderPath()
{
#ifdef _WIN32
    char filePath[MAX_PATH];
    char* currentPath = _getcwd(filePath, sizeof filePath);
#else
    char filePath[PATH_MAX];
    char* currentPath = getcwd(filePath, sizeof filePath);
#endif
    return std::string(currentPath);
}

const char* ScriptingGuide::BoolToString(const bool deleted)
{
    return (deleted ? "true" : "false");
}

void ScriptingGuide::PrintGeodeticPos(const agi::odtk::AttrProxy& pos)
{
    std::cout << "Lat : " << pos("Lat")("GetIn").InvokeDouble("deg")
        << " deg, Lon: " << pos("Lon")("GetIn").InvokeDouble("deg")
        << " deg, Alt: " << pos("Alt")("GetIn").InvokeDouble("m") << " m\n";
}

void ScriptingGuide::PrintKeplerianOrbitState(const agi::odtk::AttrProxy& kep)
{
    std::cout << "Epoch : " << kep("Epoch")("Format").InvokeString("UTCG")
        << " UTCG, Eccentricity: " << kep("Eccentricity").AsDouble()
        << ", TrueArgOfLatitude: " << kep("TrueArgOfLatitude")("GetIn").InvokeDouble("deg")
        << " deg, Inclination: " << kep("Inclination")("GetIn").InvokeDouble("deg")
        << " deg, RAAN: " << kep("RAAN")("GetIn").InvokeDouble("deg")
        << " deg, ArgOfPerigee: " << kep("ArgOfPerigee")("GetIn").InvokeDouble("rad") << " deg rad\n";
}

void ScriptingGuide::RunReport(const agi::odtk::AttrProxy& odtk, const std::string& inputFileName, const std::string& stylePath,
    const std::string& productName, const std::string& exportFilePath)
{
    // Create a new data product at the end of the list

    const agi::odtk::AttrProxy newElem = odtk("ProductBuilder")("DataProducts")("NewElem").InvokeAttrProxy();
    odtk("ProductBuilder")("DataProducts")("push_back").Invoke(newElem);
    const auto index = odtk("ProductBuilder")("DataProducts")("size").AsInt() - 1;
    const auto product = odtk("ProductBuilder")("DataProducts")[index].AsAttrProxy();

    // Configure the the data product

    const agi::odtk::AttrProxy newSrc = product("Inputs")("DataSources")("NewElem").InvokeAttrProxy();
    product("Inputs")("DataSources")("push_back").Invoke(newSrc);

    product("Name")("Assign").Invoke(productName);
    product("Inputs")("DataSources")[0]("Filename").Assign(inputFileName);
    product("Outputs")("Style").Assign(stylePath);
    product("Outputs")("Display").Assign(true);

    product("Outputs")("Export")("Enabled").Assign(true);
    product("Outputs")("Export")("Format").Assign("CommaSeparated");
    product("Outputs")("Export")("FileName").Assign(exportFilePath);

    //Create the product

    if (!odtk("ProductBuilder")("GenerateProduct").InvokeBool(productName))
    {
        throw std::runtime_error("GenerateProduct failed. Please check the log for more details.");
    }
    std::cout << inputFileName << " exported to " << exportFilePath << "\n";
}

const char ScriptingGuide::s_pathSeparator =
#ifdef _WIN32
'\\';
#else
'/';
#endif
                

Migrating from VBScript to Visual Basic .NET

If you are used to writing ODTK scripts in VBScript but now want to migrate to a Visual Basic .NET environment, do the following:

  1. Add .Value when retrieving String, Bool, Real, or Int values from ODTK.
  2. Explicitly specify object types As Object, As String, As Integer, etc...
  3. Properly capitalize .Value, .Choices, .Item, .Type and other reserved words.
  4. Specify the complete condition, including the test against True / False inside if…then statements.

The reasons for the above is that, while VBScript and VB6 could automatically convert objects to String, Boolean, Integer and Double values using the default property, VB.NET has deprecated the concept of the default property, and you have to use .Value explicitly. For more information, please, visit:

Convert VBA Code to Visual Basic When Migrating to Visual Studio 2005 Tools for Office.

Setting a custom location for the ODTK log file

By default ODTK will create its log in a user temp directory and delete it upon application exit. However, you may override this by using the following commands:

COM

VBScript
ForWriting   = 2    ' Create new or truncate existing file
ForAppending = 8    ' Create new or append to an existing file
MsgDebug     = 0
MsgInfo      = 1
MsgForceInfo = 2
MsgWarning   = 3
MsgError     = 4
set uiApp = WScript.CreateObject("ODTK.Automation")
uiApp.OpenLogFile "c:\temp\log1.txt", ForAppending
uiApp.LogMsg MsgWarning, "Warning: LogFile = " & uiApp.LogFile
uiApp.LoadPersonality "ODTK"
set ODTK = uiApp.Personality
uiApp.LogMsg MsgInfo, ODTK.NewDate(1,"JDate").Format("UTCG")
set ODTK = Nothing
set uiApp = Nothing
JScript
var ForWriting   = 2;    // Create new or truncate existing file
var ForAppending = 8;    // Create new or append to an existing file
var MsgDebug     = 0;
var MsgInfo      = 1;
var MsgForceInfo = 2;
var MsgWarning   = 3;
var MsgError     = 4;
var uiApp = WScript.CreateObject("ODTK.Automation");
uiApp.OpenLogFile("c:\\temp\\log1.txt", ForAppending);
uiApp.LogMsg(MsgWarning, "Warning: LogFile = " + uiApp.LogFile);
uiApp.LoadPersonality("ODTK");
var ODTK = uiApp.Personality;
uiApp.LogMsg(MsgInfo, ODTK.NewDate(1,"JDate").Format("UTCG"));
ODTK = null;
uiApp = null;
Python
ForWriting   = 2    # Create new or truncate existing file
ForAppending = 8    # Create new or append to an existing file
MsgDebug     = 0
MsgInfo      = 1
MsgForceInfo = 2
MsgWarning   = 3
MsgError     = 4
uiApp = w32c.Dispatch("ODTK.Automation")
uiApp.OpenLogFile("c:\\Temp\\log1.txt", ForAppending)
uiApp.LogMsg(MsgWarning, "Warning: LogFile = " + uiApp.LogFile)
uiApp.LoadPersonality("ODTK")
ODTK = uiApp.Personality
uiApp.LogMsg(MsgInfo, ODTK.NewDate(1,"JDate").Format("UTCG"))
ODTK = None

Cross-Platform API

Python
# Setting a custom location for the ODTK log file

# By default ODTK will create its log in a user temp directory and delete it upon application exit.
# However, you may override this by using the following commands:

appendMode = True
log_file_path = os.path.join(this_dir_path, "log.txt")
odtk.Application.SetLogFile(log_file_path, appendMode)

log_level_debug = 0
log_level_info = 1
log_level_force_info = 2
log_level_warning = 3
log_level_error = 4

odtk.Application.LogMsg(log_level_info, f"LogFile = {odtk.Application.LogFile.eval()}")
odtk.Application.LogMsg(log_level_warning, "This is a warning message.")
odtk.Application.LogMsg(log_level_error, "This is an error message.")

                
MATLAB
% Setting a custom location for the ODTK log file

% By default ODTK will create its log in a user temp directory and delete it upon application exit.
% However, you may override this by using the following commands:

appendMode = true;
logfilePath = [thisFolderPath, filesep, 'log.txt'];
odtk.Application.SetLogFile(logfilePath, appendMode);

logLevelDebug = 0;
logLevelInfo = 1;
logLevelForceInfo = 2;
logLevelWarning = 3;
logLevelError = 4;

odtk.Application.LogMsg(logLevelInfo, "LogFile = " + odtk.Application.LogFile);
odtk.Application.LogMsg(logLevelWarning, "This is a warning message.");
odtk.Application.LogMsg(logLevelError, "This is an error message.");

                
C++
// Setting a custom location for the ODTK log file

// By default ODTK will create its log in a user temp directory and delete it upon application exit.
// However, you may override this by using the following commands :

const auto appendMode = true;
const std::string logFilePath = thisFolderPath + s_pathSeparator + "log.txt";
odtk("Application")("SetLogFile").Invoke(logFilePath, appendMode);

const auto logLevelDebug = 0;
const auto logLevelInfo = 1;
const auto logLevelForceInfo = 2;
const auto logLevelWarning = 3;
const auto logLevelError = 4;

odtk("Application")("LogMsg").Invoke(logLevelInfo, "LogFile = " + odtk("Application")("LogFile").AsString());
odtk("Application")("LogMsg").Invoke(logLevelWarning, "This is a warning message.");
odtk("Application")("LogMsg").Invoke(logLevelError, "This is an error message.");

                

Using ODTK.WriteMessage() function

In addition to the application level uiApp.LogMsg() function common to all AGI products ODTK implements an additional ODTK.WriteMessage() function. This provides the ability to generate messages from ODTK specific event handler scripts described below as well as adding more debugging functionality for scripts.

COM

VBScript
ODTK.WriteMessage "Example error message...", "error"
ODTK.WriteMessage "Example warning message...", "warn"
ODTK.WriteMessage "Example forced message...", "force"
ODTK.WriteMessage "Example info message...", "info"
ODTK.WriteMessage "Example debug message...", "debug"
ODTK.WriteMessage "Yawn", "sleep 1000" ' Causes system sleep for 1 sec
JScript
ODTK.WriteMessage("Example error message...", "error");
ODTK.WriteMessage("Example warning message...", "warn");
ODTK.WriteMessage("Example forced message...", "force");
ODTK.WriteMessage("Example info message...", "info");
ODTK.WriteMessage("Example debug message...", "debug");
ODTK.WriteMessage("Yawn", "sleep 1000"); // Causes system sleep for 1 sec
Python
ODTK.WriteMessage("Example error message...", "error")
ODTK.WriteMessage("Example warning message...", "warn")
ODTK.WriteMessage("Example forced message...", "force")
ODTK.WriteMessage("Example info message...", "info")
ODTK.WriteMessage("Example debug message...", "debug")
ODTK.WriteMessage("Yawn", "sleep 1000") # Causes system sleep for 1 sec

Cross-Platform API

Python
# Using ODTK.WriteMessage() function

# WriteMessage works for desktop only; the Runtime accepts the command and returns true but does not write a message.

odtk.WriteMessage("Example error message...", "error")
odtk.WriteMessage("Example warning message...", "warn")
odtk.WriteMessage("Example forced message...", "force")
odtk.WriteMessage("Example info message...", "info")
odtk.WriteMessage("Example debug message...", "debug")
odtk.WriteMessage("Yawn", "sleep 1000")  # Causes system sleep for 1 sec
                
MATLAB
% Using ODTK.WriteMessage() function

% WriteMessage works for desktop only; the Runtime accepts the command and returns true but does not write a message.

odtk.WriteMessage("Example error message...", "error");
odtk.WriteMessage("Example warning message...", "warn");
odtk.WriteMessage("Example forced message...", "force");
odtk.WriteMessage("Example info message...", "info");
odtk.WriteMessage("Example debug message...", "debug");
odtk.WriteMessage("Yawn", "sleep 1000");  % Causes system sleep for 1 sec
                
C++
// Using ODTK.WriteMessage() function

// WriteMessage works for desktop only; the Runtime accepts the command and returns true but does not write a message.

odtk("WriteMessage").Invoke("Example error message...", "error");
odtk("WriteMessage").Invoke("Example warning message...", "warn");
odtk("WriteMessage").Invoke("Example forced message...", "force");
odtk("WriteMessage").Invoke("Example info message...", "info");
odtk("WriteMessage").Invoke("Example debug message...", "debug");
odtk("WriteMessage").Invoke("Yawn", "sleep 1000");  // Causes system sleep for 1 sec
                

Closing child windows

You can access any of the windows in ODTK using the windows method. This will return a collection of all the open windows. The example below automatically closes all graph windows by checking the contents of their title.

COM

VBScript
for each w in uiApp.windows
    if InStr(w.caption,"Graph Viewer") = 1  then
        w.Close
    end if
next
JScript
for(var i = 0; i < uiApp.windows.Count; i++)
{
   if(uiApp.windows(i).Caption.indexOf("Graph Viewer") == 0)
   {
        uiApp.windows(i).Close();
   }
}
Python
for w in uiApp.windows:
   if str.find(w.caption,"Graph Viewer") == 0:
     w.Close()

Custom Scripts for Event Handling

Event handlers for ODTK can be implemented in VBScript, Jscript, Python, and Perl. For example, Simulator.Events.OnComplete can be set to C:\Test\Test1.js file:

COM

VBScript
function Test1(msg,simObj)
{
    var odtk = simObj.Parent.Parent.Application;

    odtk.WriteMessage("Test1 for " + simObj.name + "\n" +
    "Message was: " + msg, "info");
}
JScript
function Test1(msg,simObj)
{
    ODTK = simObj.Parent.Parent.Application;

    ODTK.WriteMessage("Test1 for " + simObj.name + "\n" + "Message was: " + msg, "info");
}
Python
def Test1(msg,simObj):
    ODTK = simObj.Parent.Parent.Application

    ODTK.WriteMessage("Test1 for " + simObj.name + "\n" + "Message was: " + msg, "info")

The file extension determines which scripting engine is used and the file name itself determines which function inside the file is called to handle the event. The function receives two arguments: An error message for this event and the object originating this event.

Additional plugin point and scripting examples shipped with ODTK can be found at C:\Program Files\AGI\ODTK 6\ODTK\AppData\Scripts.

For additional help, please, refer to the ODTK Plugin Programming Guide located at C:\Program Files\AGI\ODTK 6\Help\ODTK\pdf\PluginProgrammingGuide.pdf.

Automate ODTK With C# and C++

In addition to invoking a full copy of ODTK application, you can now use a slimmed down version of the ODTK.Engine, but you still have the responsibility to initialize most of its environment yourself. You can find examples in C# and C++ here.

Using External Scripts to Perform Date Time and Unit Conversion

ODTK ships with a DataPicker Control that allows external scripts to perform Date Time and Unit conversions using the same rules and leap second awareness that is built into ODTK and STK. Here are examples of using it in Javascript, VB Script, and Perl.

COM

Javascript Example

var unitPickerObj = null;
function convertDateTime(inpStr,inpUnit,retUnit)
{
    if(unitPickerObj==null)
    {
        unitPickerObj = WScript.CreateObject("AgUiUnitPicker6.AgUiDatePickerCtrl");
        //Optionally set alternative LeapSecond.dat file if it differs from the default location (below)
        //unitPickerObj.LoadLeapSecondTable('C:/ProgramData/AGI/ODTK 6/DynamicEarthData/LeapSecond.dat');
        unitPickerObj.ReadOnly = false;
    }
    unitPickerObj.unit = inpUnit;
    unitPickerObj.returnUnit = inpUnit;
    unitPickerObj.value  = inpStr+"";
    unitPickerObj.returnUnit = retUnit;
    return unitPickerObj.value+"";
}
var x = convertDateTime("2012-05-16T11:12:13.456Z","ISO-YMD","JDate");
var y = parseFloat(x)+2.5;
var z = convertDateTime(y,"JDate","ISO-YMD");
WScript.Echo("z = " + z);
    

VB Script Example

set unitPickerObj = WScript.CreateObject("AgUiUnitPicker6.AgUiDatePickerCtrl")
unitPickerObj.ReadOnly = false
Function convertDateTime(inpStr,inpUnit,retUnit)
    unitPickerObj.unit = inpUnit
    unitPickerObj.returnUnit = inpUnit
    unitPickerObj.value  = CStr(inpStr)
    unitPickerObj.returnUnit = retUnit
    convertDateTime = CStr(unitPickerObj.value)
End function
x = convertDateTime("2012-05-16T11:12:13.456Z","ISO-YMD","JDate")
y = CDbl(x)+2.5
z = convertDateTime(y,"JDate","ISO-YMD")
WScript.Echo("z = " + z)

        

Perl Example

use Win32::OLE;
$unitPickerObj = Win32::OLE->new('AgUiUnitPicker6.AgUiDatePickerCtrl') or die "oops\n";
$unitPickerObj->{ReadOnly} = false;
sub convertDateTime
{
    my ($inpStr,$inpUnit,$retUnit) = @_;
    $unitPickerObj->{unit} = $inpUnit;
    $unitPickerObj->{returnUnit} = $inpUnit;
    $unitPickerObj->{value}  = $inpStr;
    $unitPickerObj->{returnUnit} = $retUnit;
    return $unitPickerObj->{value};
}
$x = convertDateTime("2012-05-16T11:12:13.456Z","ISO-YMD","JDate");
$y = $x+2.5;
$z = convertDateTime($y,"JDate","ISO-YMD");
print "z = $z";
        

ODTK Functional Attributes

Working with Attributes

Return types

Functions mainly return two types, CAgAttr or bool. The CAgAttr can either contain a string or an automation object, which means in VBScript it will have a return type of vbString(8) or vbObject(9). When functions return a bool, these are, in VBScript, of type vbBoolean(11). To check the return type for any function in VBScript, use the VarType function. For example:

result = ODTK.DeleteObj(ODTK.Scenario(0).Satellite(0))
Dim MyCheck

Functional Attributes

The attributes listed in the tables below, which are not exposed in the Object Properties window, are used in running and controlling various OD tasks.

The tables below are organized by scope, as follows:


MyCheck = VarType(result)
msgbox MyCheck

For more information, see the MSDN VBScript Language Reference.

Assigning return values in VBScript

When the return type is vbBoolean or vbString, one can simply assign the result to a variable, such as the above example using DeleteObj. However, if the return type is a vbObject, one must use the set command to assign the result to a variable, as in the CreateObj example below.

Attribute listings by Scope

The functional attributes are listed below, grouped by the scope under which they are defined. Each description provides a functional prototype indicating the types of the input and output arguments, and a sample VBS code exercising each function.

Each section of the Example VBS code shown in the following table was run in the Scripting Tool, which predefines "ODTK" as the personality and "sc" as the current scenario.

Application Scope Functions

It is recommended a scenario be loaded prior to running these functions from a script so that attributes affecting coordinate transformations (EOP, nutation) may be set explicitly, as opposed to the use of internal defaults if no scenario exists. Some functions will only run when a scenario is loaded, while other functions do not make that check themselves.

Attribute Description/Example
AccountID

Returns the account ID string, such as 26884.


Prototype: CAgAttr AccountID()


The returned object is a string containing the account ID.


Example VBS:

accountIDStr = ODTK.AccountID
                    
AppVersion

Returns the ODTK version number, e.g. "6.2.0" as a string.


Prototype: CAgAttr AppVersion


The returned object is a string containing the ODTK version./p>

Example VBS:

version = ODTK.AppVersion
                    
CheckForCrossCorr

Help function for the StateDiff html utility. Determines if a run file contains cross-correlations.


Prototype: bool CheckForCrossCorr()


The returned flag is true if the file contains cross-correlations.


Example VBS:

runFile = "C:\tmp\Scenario1.filrun"
ODTK.writemessage ODTK.CheckForCrossCorr(runFile), "force"
                    
Combine Filters

Used to compare and combine two independent filter estimates (nominally a "Backwards" Filter run with a "Forwards" Filter run.

Prototype:

bool CombineFilters(string outputCombinedFile,
string outputDifferencedFile,
string referenceFile,
string targetFile,
bool bLastMeasOnly,
string startTime,
string StopTime,
bool bSaveCrossCorrelations)
                    

where outputCombinedFile is the resultant combined Filter file (.filrun), and other parameters are same as "CreateDifference".

ConcatenateSP3Files

Concatenates two SP3 files together. Requires that the second file begin exactly 1 interval after the first file ends. If a PRN is not in both files the header will be expanded to include it, and the "P", "V", records will be set to zeros over the file time span where it is not present. This function does not perform coordinate transformations, so whether or not a scenario is loaded is irrelevant.


Prototype: CAgAttr ConcatenateSP3Files(
        string sInFile1,
        string sInFile2,
        string sOutFile)

Where:

  • sInFile1 is the first input filename
  • sInFile2 is the second input filename
  • sOutFile is the output filename

The returned object contains two members:

  • Messages, a status message string
  • Succeed, a Boolean indicating success

Example VBS:

set retVal = ODTK.ConcatenateSP3Files(inputFile1,inputFile2,outputfile)
ODTK.WriteMessage retVal.Messages, "debug"
ODTK.WriteMessage "Success? " & retVal.Succeed, "debug"
                    
CopyObject

Copies an object to the clipboard for use in further paste operations. See also the IsPasteAvailable and PasteObject functions.


Prototype: bool CopyObject(CAgAttrVariable object)


The returned Boolean indicates success.


Example VBS:

bSuccess = ODTK.CopyObject(sc.Satellite(0))
                    
Create

Obsolete. Creates an object using an object name to specify the parent object. Use CreateObj() instead.


Prototype: bool Create(string parentName, string className, string objectName)


Where:

  • parentName is the name of the parent object. Use an empty string when creating a scenario
  • className is the type of object to add
  • objectName is the desired name of the new object

Returns a Boolean indicating success.

Example VBS:

bSuccess = ODTK.Create("", "Scenario", "Scen1")
bSuccess = ODTK.Create("Scen1", "Satellite", "Sat1")
                    
CreateDifference

Called by the StateDiffTool to difference states from two different processes and produce a .difrun file for reporting and graphing. The differences are defined as target - reference, where orbits are differenced in an RIC frame.


Prototype: bool CreateDifference(string outputFile,
        string referenceFile,
        string targetFile,
        bool bLastMeasOnly,
        string startTime, string stopTime,
        bool bSaveCrossCorrelations)

Where:

  • outputFile is the resultant difference file (.difrun)
  • referenceFile is one input filename (.filrun, etc)
  • targetFile is the other input filename (.filrun, etc)
  • bLastMeasOnly limits output to one point per measurement time, vs outputting multiple differences at duplicate measurement times
  • startTime is a date/time string in UTCG; an empty string will use the file start time by default
  • stopTime is a date/time string in UTCG; an empty string will use the file stop time by default
  • bSaveCrossCorrelations will toggle the writing of the entire covariance matrix to the output file
  • Turning this off will reduce the size of the output file

If the start and stop times are input as empty strings, the entire file span will be used.


Returns a Boolean indicating success.


Example VBS:

ref = "c:\tmp\Scenario1.filrun"
tgt = "c:\tmp\Scenario1.simrun"
output = "c:\tmp\Scenario1.difrun"
t1 = "11 Jul 2010 00:30:00"<
t2 = "11 Jul 2010 01:25:00"
set retv = ODTK.CreateDifference(output, ref, tgt, true, t1, t2, false)
                    
CreateNavSolFile

Creates a GNSS Navigational Solution file from an ephemeris (*.e) file.


Prototype: CAgAttr CreateNavSolFile(string ephemFile, string outputFile, string options)

Where:

  • ephemFile is the satellite ephemeris file
  • outputFile will contain the NavSol data
  • options is an optional string containing a receiver ID and the time precision specification:
    • /recID = GNSS Receiver ID (default = 800)
    • /prec = time precision (default = 0.001 sec)

The returned object has the following members:

  • StartTime is a string showing the start time of file
  • StopTime is a string showing the stop time of file
  • Succeed is a Boolean indicating success

Example VBS:

eFile = "C:\tmp\mysat.e"
nFile = "c:\tmp\MySat.navsol
options = "/recID 133"
set result = odtk.createNavSolFile(eFile, nFile, options)
odtk.writemessage result.Succeed, "force"
odtk.writemessage result.startTime, "force"
odtk.writemessage result.stopTime, "force"
                
CreateObj

Creates an object as a child of a specified object.


Prototype: CAgAttr CreateObj(CAgAttr parent,


        string className, string objectName)

Where:

  • parent is the parent object
  • className is the type of object to add
  • objectName is the desired name of the new object

Returns the newly created object.


Example VBS:

Set scenObj = ODTK.CreateObj(ODTK, "Scenario", "Scen1") Set satObj1 = ODTK.CreateObj(scenObj, "Satellite", "Sat1")
                
CutObject

Copies an object to the clipboard for use in further paste operations while also deleting the object from the scenario. See also the function PasteObject.


Prototype: bool CutObject(CAgAttr object)


The input is an ODTK object. Returns true if the object was cut.


Example VBS:

bSuccess = ODTK.CutObject(sc.Sat1.ToGround)
                    
DeleteObject

Deletes an object from the scenario.


Prototype: bool DeleteObject(CAgAttr object)


The function takes an ODTK object as the input and returns a Boolean indicating success.


Example VBS:

bSuccess = ODTK.DeleteObject(sc.Satellite1)
                    
DumpFile

Function called by FileDumperTool to list (i.e. print) contents of a GNSS SP3 ephemeris file to a text file.


Prototype: bool DumpFile(string inputSP3, string outputTxt)


Where:

  • inputSP3 is the SP3 file filename
  • outputTxt is the desired output filename

This function always returns true.

Example VBS:

input = "c:\tmp\input.sp3"
output = "c:\tmp\sp3dump.txt"
bSuccess = ODTK.dumpFile(input, output)
                
ExportObj

Saves an object by specifying the actual object and a flag indicating whether or not to save children of the object.


Prototype: CAgAttr ExportObj(CAgAttr object, string filename,
        bool bSaveChildren)

Where:

  • object is the object to be saved
  • filename is the output file to be saved
  • bSaveChildren is a Boolean specifying whether or not to save the child objects as well

When applied to scenarios ExportObj will save the Scenario and any restart records to a new location but will keep all internal paths pointing to the old location.

Example VBS:

ODTK.ExportObj(scen, "C:\tmp\Scenario1copy1.sco", true)
                

Also see: SaveObj

ExportObservationIntervals

Creates interval files based on scenario's loaded observation measurement files, and is a helper function for the SaveObservationIntervals tool. The interval files can then be imported or linked to by the simulator for use in the custom tracking schedule. Note that if both the satName and trkName are input as empty strings, the resulting interval file will identify both objects from within the file. This may not work for three-, four- or five-legged measurements.


Prototype: CAgAttr ExportObservationIntervals(
        string outputFile, string satName,
        string trkName, double gap, double pad,
        string options)

Where:

  • outputFile is the desired interval filename (*.int)
  • satName will cause only those intervals relating to that satellite to be written, and as a result the satellite names will not show up in the interval file. An empty string will cause intervals for any satellite to show up, and the associated satellite name will be appended as additional data for each interval.
  • trkName causes the same behavior as satName except regarding facilities.
  • gap (seconds) is the minimum gap which defines a pass of data, which defines when one interval starts and the next ends. If this value is less than the measurement granularity, there will be one interval written per measurement, so make sure this value is large enough to be realistic. For instance, if you have measurements every minute and then a data gap of 40 minutes before the next set of measurements, setting gap to be anywhere from 2-30 minutes will be sufficient.
  • pad (seconds) can be used to expand the interval start and stop times.
  • options is a string which is not currently used.

Returns an object containing one member, Succeed, which is a Boolean indicating success.


Example VBS:

outFile = "C:\tmp\Meas.int"
sat = ""
trk = ""
gap = 1200.0
pad = 0.0
options = ""
set result = ODTK.ExportObservationIntervals(outFile, sat, trk, gap, pad, options)
odtk.WriteMessage result.Succeed, "debug"
                
ExtractEphemeris

A helper function called by the CreateEphFileTool html page. Extracts satellite ephemeris from a run file to an ephemeris (*.e) file.


Prototype: bool ExtractEphemeris(string referenceFile,
        string primarySat, string outputFile,
        bool inclCov, string covType, string coordFrame, string sOptions)
        bool includeCorr, string targetName,
        string startTime, string stopTime)

Where:

  • referenceFile is the run file to extract ephemeris from
  • primarySat is the name of the satellite object in the file
  • outputFile is the desired output ephemeris filename
  • inclCov controls whether or not covariance is output
  • covType controls whether velocity covariance is saved; choices are:
    • "Position 3x3 Covariance"
    • "Position Velocity 6x6 Covariance"
  • coordFrame defines the output coordinate frame, e.g. "ICRF", "Fixed", etc. Choices depend on the CB. See Satellite.EphemerisGeneration.CoordFrame. Note if the selected output coordinate frame is not the run file default CB frame then a scenario object must be loaded to define the CB orientation parameters necessary for the coordinate frame transformation.

Optional parameters are as follows and consist of a keyword followed by a value string

  • includeCorr says whether to include correlations in the relative covariance, e.g. /includeCorr "TRUE" to include
  • targetName is the name of another satellite, which causes the covariance to be calculated as relative to this satellite, e.g. /targetName "Sat2"
  • startTime is the start time in UTCG units; an empty string will use the file start time by default, e.g. /startTime "01 Jul 2012 00:00:00"
  • stopTime is the stop time in UTCG units; an empty string will use the file stop time by default, e.g. /stopTime "02 Jul 2012 00:00:00"

Returns a Boolean indicating success.


Example VBS to Extract filter ephemeris and output position/velocity and Position 3x3 covariance the Fixed frame

refFile = "C:\tmp\Scenario1.filrun"
sat = "Satellite3"
eFile = "c:\tmp\sat3.e"
covType = "Position 3x3 Covariance"
coordFrame = "Fixed"
bRes = odtk.ExtractEphemeris(refFile, sat, eFile, true, covType, coordFrame, "")
odtk.WriteMessage bRes, "debug"

                    

Example VBS to output relative covariance

refFile = "C:\tmp\Scenario1.filrun"
sat = "Satellite3"
eFile = "c:\tmp\sat3.e"
covType = "Position 3x3 Covariance"
coordFrame = "ICRF"
quote = """"
sInclCorr   = "/inclCorr " & quote & "TRUE" & quote
sTargetName = "/targetName " & quote & "Satellite1" & quote
sOptions    = sInclCorr & sTargetName
bRes = odtk.ExtractEphemeris(refFile, sat, eFile, true, covType, coordFrame, sOptions)
odtk.WriteMessage bRes, "debug"
            
ExtractGlobalDensityCorrections

Extracts global atmospheric density corrections from a run file to an ASCII file (*.gdc) formatted to be compatible with input of the contained corrections for use in the filter estimation process.


Prototype: bool ExtractGlobalDensityCorrections (
        string referenceFile, string outputFile,
        bool inclCov, string startTime, string stopTime)

Where:

  • referenceFile is the run file to extract global atmospheric density corrections from
  • outputFile is the desired output filename (*.gdc)
  • inclCov controls whether or not covariance is included in the output
  • startTime is the start time in UTCG units; an empty string will use the file start time by default, e.g. /startTime "01 Jul 2012 00:00:00"
  • stopTime is the stop time in UTCG units; an empty string will use the file stop time by default, e.g. /stopTime "02 Jul 2012 00:00:00"

Returns a Boolean indicating success.

Example VBS to extract global atmospheric density corrections without covariance information from a smoother output for the full time span

refFile = "C:\tmp\Scenario1.smtrun"
outputFile = "c:\tmp\DensityCorr.gdc"
odtk.ExtractGlobalDensityCorrections( refFile, outputFile, false, "", "")
ExtractStateHistory

Dumps the contents of a binary state history file (accessed as a .filrun, .simrun or .smtrun file) to a readable text file. This function is typically called by the StateFileDumperTool html utility.


Prototype: CAgAttr ExtractStateHistory(string inputs)


The inputs string is a list of arguments that contain options to the function. Options are specified by including a keyword followed by text in quotes.


The only required argument is the input filename:

  • /filename is the input filename, a .filrun, .smtrun or .simrun file

Optional parameters are as follows:

  • /output "filename" is the desired output file name, e.g.: /output "c:\myFile.txt"
  • /startTime "startTime" is the start UTC time string, e.g.: /startTime "03 Jan 2009 00:12:11.5"
  • /stopTime "stopTime" is the stop UTC time string, e.g.: /stopTime "03 Jan 2009 11:15:21.00"
  • /step "timeStep" is the step size between outputs in seconds, e.g.: /step "120"
  • /coordType "CoordType" defines the types of coordinates to report, either "Equinoctial", "Cartesian", "Keplerian" or "Spherical"
  • /coordSys "CoordSys" defines the coordinate system used to report orbital elements, either "ICRF", "J2000", "Fixed", "Inertial", "TrueOfDate", "MeanOfDate", "TEMEOfDate", or for multiple CBs within one file, this has the form CBname:CoordSys; as in "Earth:J2000;Moon:Inertial;Sun:ICRF"
  • /covType "CovType" defines what form the output covariance will take, with choices of "Cartesian", "Gaussian", "Frenet"
  • /covMethod "CovMethod" defines whether output covariance is rotated or projected, with options "Rotated" or "Projected"
  • /covOutput "CovOutput" defines whether output covariance is full covariance or sigma-correlation matrix, and is "Cov", "SigCor", or "Both"

The returned object contains three members:

  • Succeed: a Boolean indicating success
  • OutputFilename: a string showing the output filename
  • Messages: a string showing errors or other status

Notes:

  • If no output file is specified, one will be created using a .txt extension in the same directory as the input file.
  • If no start or stop time is specified, the entire file contents will be dumped.
  • If start time is specified without the stop time, only data at that single time will be dumped.

Example VBS:

The tricky part here is assembling a string with embedded quotes, which is done using three sequential quotes ("""):

input = "/filename " & """C:\tmp\Scenario1.filrun""" & " /output " &
"""c:\tmp\filrun.txt""" & " /startTime " & """11 Jul 2010 00:00:00.000""" & " /coordSys " & """Fixed"""
set retv = ODTK.ExtractStateHistory(input)
odtk.writemessage retv.Succeed,"force"
odtk.writemessage retv.OutputFile,"force"
odtk.writemessage retv.Messages,"force"
                    
GenerateDeltaRaDec

Generates a file containing relative optical measurements from the list of tracking data files assigned in the scenario Measurements.Files list. Relative optical measuremets are constructed when optical measurements exist to multiple satellites at the same time (or within a time tolerance) from the same optical sensor. All measurements which cannot be differenced, which includes all non-optical measurements and optical measurements without matching pairings, are written to the output tracking data file along with the delta-optical measurements.

Protoype: bool GenerateDeltaRADec (string outputMeasFile, double timeTolerance, bool modelTimeTagDifferences)

where:

  • outputMeasFile is the name of the output file (type: gobs).
  • timeTolerance is the allowed time difference between time tags in seconds for obs to be considered simultaneous.
  • modelTimeTagDifferences controls whether time tag differences are modeled during measurement processing.

The returned Boolean indicates success.

Example VBS

outputFile = "C\od_6.0\TrackingData\DeltaOptical.gobs"
timeTol = 0.01

ODTK.GenerateDeltaRADec outputFile, timeTol, true
GenerateDOWD

Generates a file of Differenced One Way Doppler (DOWD) measurements from the tracking data files currently assigned in the Scenario.Measurements.Files list. The specified output file should be of the *.gobs format. All input measurements are reflected in the output file.


DOWD measurements are constructed by differencing two simultaneous one way TDRS Doppler measurements (3L Doppler). All other measurements and single 3L Doppler measurements are simply copied to the output file. The generated output file can therefore replace all of the input files for subsequent processing. The method also takes a time tolerance, specified in seconds, as input wich allows for the differencing of 3L Doppler measurements with slightly offset time tags.


Prototype: bool GenerateDOWD (string outputDOWDFile, double timeTolerance)


The returned Boolean indicates success.

Example VBS:

timeTolerance = 0.0
dowdFile = "C:\tmp\MySatDOWD.gobs"
bSuccess = ODTK.GenerateDOWD(dowdFile, timeTolerance)
                
GenerateNavSolutions

Generates a file of GNSS navigation solutions from a RINEX file. A scenario must be loaded with a configured GNSS constellation. This function now has an addditional (last) argument which takes in a string with the name of GNSS Constellation ("GNSS," "GALILEO," "GLONASS," "BeiDou") that limits algorithm to use only obs originated from GNSS satellites that belong to said constellation.

Prototype: bool GenerateNavSolutions(string inputRinexFile,


        string outputNavSolFile)

The returned Boolean indicates success.

Example VBS:

rinexFile = "C:\stk\od_6.0\TrackingData\GpsConstTest.rnx"
navFile = "C:\tmp\Rcvr800.navsol"
bSuccess = ODTK.GenerateNavSolutions(rinexFile, navFile)
                
GeneratePAFFile

The PAF file is the GNSS Performance Assessment File. This function takes a .difrun file as input and outputs orbit and clocks errors for the GNSS satellites in the run file using data at requested intervals. The orbit errors are in the Earth Centered Earth Fixed frame in units of meters and meters/sec. The clock phase and frequency errors are also in units of meters and meters/sec. By default, data is sampled at 15 minute intervals. Only one data file is processed per run. Data can be written at any start time and for any length of time, as opposed to being limited to one day starting at midnight. This function is called by the GeneratePAFFile html utility.


To get GNSS orbit differences as compared to an SP3 file, first run the SP3_to_Simrun utility, and difference the ODTK run of interest (filrun, simrun, or smtrun) against the SP3.simrun file, and use that as the input to generate the PAF file.


Prototype: CAgAttr GeneratePAFFile(string inputFile,


        string outputFile, string options)

Where:

  • inputFile is a .difrun file
  • outputFile is the desired PAF file
  • options is a string of options, described belowv

Optional parameters are as follows:

  • /startTime "startTime" is the start GNSSG time string, e.g.: /startTime "03 Jan 2009 00:12:11.5"
  • /stopTime "stopTime" is the stop GNSSG time string, e.g.: /stopTime "03 Jan 2009 11:15:21.00"
  • /step "timeStep" is the step size between outputs in seconds, e.g.: /step "900"
  • /source "source" is the source string for the header, e.g.: /source "GOCGIS"
  • /class "className" is used to get Satellite objects vs. GNSSSatellite objects in ODTK, e.g.: /class "Satellite"

The returned object contains three members:

  • Succeed: a Boolean indicating success
  • OutputFilename: a string showing the output filename
  • Messages: a string showing errors or other status

Example VBS:

ifile = "C:\tmp\GNSSFinManSimpleTest.difrun"
ofile = "c:\tmp\test.paf"
Input = " /step " & """900""" & " /source " & """GOCGIS""" & " /class " & """GNSSSatellite"""
set retv = ODTK.GeneratePAFFile(ifile, ofile, input)
odtk.writemessage retv.Succeed,"force"
odtk.writemessage retv.OutputFile,"force"
odtk.writemessage retv.Messages,"force"
                
GeneratePSFFile The PSF file is a GNSS Prediction Support File. This function takes a .filrun or .smtrun file as input and calculates RMS for the values in the PSF file using data at requested intervals. By default, data is sampled at 15 minute intervals. Constellation averaging is not executed if there is less than 24 hours of data in the file. Only one data file is processed per run, so for a seven-day average a single run file containing seven days of data is required. This function is called by the GeneratePSFFile html utility.

Prototype: CAgAttr GeneratePSFFile(string inputFile,
        string outputFile, string options)

Where:

  • inputFile is a .filrun or .simrun file
  • outputFile is the desired PSF file
  • options is a string of options, described below

Optional parameters are as follows:

  • /startTime "startTime" is the start GNSSG time string, e.g.: /startTime "03 Jan 2009 00:12:11.5"
  • /stopTime "stopTime" is the stop GNSSG time string, e.g.: /stopTime "03 Jan 2009 11:15:21.00"
  • /step "timeStep" is the sampling interval in seconds, e.g.: /step "900"
  • /source "source" is the source string for the header, e.g.: /source "GOCGIS"

The returned object contains three members:

  • Succeed: a Boolean indicating success
  • OutputFilename: a string showing the output filename
  • Messages: a string showing errors or other status

Example VBS:

ifile = "C:\tmp\GNSSFinManSimpleTest.filrun"
ofile = "c:\tmp\test.psf"
Input = " /step " & """900"""

set retv = ODTK.GeneratePSFFile(ifile, ofile, input)
odtk.writemessage retv.Succeed,"force"
odtk.writemessage retv.OutputFile,"force"
odtk.writemessage retv.Messages,"force"
                
GenerateSP3fromStateHistory

Helper function for the StateFile_To_SP3 utility. Outputs the contents of a state history file to an SP3 file.


Prototype: CAgAttr GenerateSP3FromStateHistory(
        string inputs)

The inputs string is a list of arguments that contain options to the function. Options are specified by including a keyword followed by text in quotes.

The only required argument is the input filename:

  • /filename is the input filename, a .filrun, .smtrun or .simrun file

Optional parameters are as follows:

  • /output "filename" is the desired output file name, e.g.: /output "c:\myFile.sp3"
  • /startTime "startTime" is the start GNSSG time string, e.g.: /startTime "03 Jan 2009 00:00:00"
  • /stopTime "stopTime" is the stop GNSSG time string, e.g.: /stopTime "03 Jan 2009 11:15:00.00"
  • /step "timeStep" is the step size between outputs in seconds, e.g.: /step "120"

The returned object contains three members:

  • Succeed: a Boolean indicating success
  • OutputFilename: a string showing the output filename
  • Messages: a string showing errors or other status

Notes:

  • If no output file is specified, one will be created using a .sp3 extension in the same directory as the input file.
  • If no start or stop time is specified, the entire file contents will be dumped.
  • If start time is specified without the stop time, only data at that single time will be dumped.

Example VBS:

input = "/filename " & """C:\tmp\GNSSFinManTest.filrun"""

set retv = ODTK.GenerateSP3FromStateHistory(input)
odtk.writemessage retv.Succeed,"force"
odtk.writemessage retv.OutputFile,"force"
odtk.writemessage retv.Messages,"force"
                    
GenerateTLE

Helper function for the OD GenerateTLE utility. Generates a TLE file which results from a least-squares fit to the ephemeris from the input file.

Prototype: CAgAttr GenerateTLE(string ephemFile,
        string startTime, string stopEntry,
        double step, double convergence,
        int maxIterations, string idString,
        string TLEFile, string reportName)

Where:

  • ephemFile is the input ephemeris (*.e) filename
  • startTime is the TLE epoch in UTCG
  • stopEntry combines the stop method and value using the formula: "Method+Value".
  • step defines how often to sample the ephemeris; a value of 0 will use all the available points in the file
  • convergence is used when iterating for a solution
  • maxIterations is the maximum number of iterations
  • idString combines different identifier strings in the formula: "revNum+elemNum+SSCNum+classification+internationalDesignation"
  • TLEFile is the output file containing the TLE
  • reportName is an output file containing a summary report with residual information for each iteration

The stopEntry, which is a string of the form "Method+Value", has three choices for Method:

  • SPAN, where Value is the time span in minutes, e.g. "SPAN+120" will fit a 2-hour section of ephemeris
  • REVS, where Value is an integer number of orbits, e.g. "REVS+3" will fit over three orbit periods
  • TIME, where Value is the stop time string in UTCG

The idString combines four values that are defined within a TLE:

  • revNum, which defines the pass number at the TLE epoch
  • elemNum, an integer value set in the file
  • SSCNum, the 5-digit identifier string
  • classification, a string with "U" meaning unclassified
  • intlDesig, the international designation string

The returned object contains:

  • FitStartTime, a UTCG string
  • FitStopTime, a UTCG string
  • FinalRMS, a double showing final residual RMS
  • ErrorMsg, a string showing final status or errors
  • Succeed, a Boolean indicating success

Example VBS:

eFile = "c:\tmp\s3.e"
t1 = "11 Jul 2010 00:10:00.000"
t2s = "TIME+11 Jul 2010 06:00:00.000"
dt = 0
conv = .001
maxIt = 5
idString = "33+1+55432+U+ "
tleFile = "c:\tmp\s37.tle"
rptFile = "c:\tmp\s3_tle7.txt"
set retv = odtk.GenerateTLE(eFile, t1, t2s, dt, conv, maxIt, idString, tleFile, rptFile)
odtk.WriteMessage retv.Succeed, "force"
odtk.writeMessage retv.errorMsg, "force"
odtk.writeMessage retv.fitstarttime, "force"
odtk.writeMessage retv.fitstoptime, "force"
odtk.writeMessage retv.finalRMS, "force"
                
GetCBNames

Analyzes an input run file and determines which central bodies are referenced within that run file.


Prototype: CAgAttr GetCBNames(string inputRunFile)


The input run file is a .filrun, .smtrun, .simrun or .lsrun file.


The returned object as two members:

  • Succeed, a Boolean indicating if file was read
  • CBNames, a set of strings containing the central body names

Example VBS:

eFile = "c:\tmp\scenario1.filrun"
set retv = odtk.GetCBNames(eFile)>
odtk.WriteMessage retv.Succeed, "force"
odtk.writeMessage retv.CBNames.size, "force"
for each thing in retv.CBNames
    odtk.writeMessage thing, "force"
next
                    
GetCoordSysNames

Provides the valid coordinate system names for a central body, which is either 'Earth", "Moon" or "Sun".


Prototype: CAgAttr GetCoordSysNames(string cbName)


The returned object as two members:

  • Succeed, a Boolean indicating if file was read
  • CoordSystems, a set of strings containing the coordinate system names

Example VBS:

set retv = odtk.GetCoordSysNames("Sun")
odtk.WriteMessage retv.Succeed, "force"
odtk.writeMessage retv.CoordSystems.size, "force"
for each thing in retv.CoordSystems
    odtk.writeMessage thing, "force"
next
                    
GetEphemTimeSpan

Gets the start and stop time of the ephemeris (.e) file.


Prototype: CAgAttr GetEphemTimeSpan(string filename)


The filename is the input ephemeris (.e) file.


The function returns an object with four members:

  • StartTime: a string containing the start time in UTCG
  • StopTime: a string containing the stop time in UTCG
  • Cov6x6: a Boolean indicating if the file contains 6x6 (position/velocity) covariance
  • Succeed: a Boolean indicating if file was read

Example VBS:

set result = ODTK.GetEphemTimeSpan("c:\tmp\s3.e")
odtk.writeMessage result.Succeed, "debug"
odtk.writeMessage result.StartTime, "debug"
odtk.writeMessage result.StopTime, "debug"
odtk.writeMessage result.Cov6x6, "debug"
                    
GetSatCoordFrameChoices

A helper function called by the CreateEphFileTool html page. Identifies the coordinate frame choices for the satellite of interest.


Prototype: CAgAttr GetSatCoordFrameChoice (string referenceFile, string primarySat)


Where:

  • referenceFile is the run file to extract ephemeris from
  • primarySat is the name of the satellite object in the file

The returned object contains five members:

  • Succeed: a Boolean indicating success
  • CB: a string identifying the satellite CB
  • DefaultCoordFrame: a string identifying the default coordinate frame for this satellite CB
  • CoordFrameChoices: a list of strings identifiying the choices for coordinate frame selection
  • Messages: a string showing errors or other status

Example VBS:

refFile = "C:\tmp\Scenario1.filrun"
sat = "Sat3"
set retv = ODTK. GetSatCoordFrameChoices (refFile, sat)

odtk.writemessage retv.Succeed,"force"
odtk.writemessage retv.CB,"force"
odtk.writemessage retv.DefaultCoordFrame,"force"
odtk.writemessage retv.Messages,"force"
set frameChoices = retv.CoordFrameChoices
for each frame in frameChoices
odtk.writemessage frame,"force"
Next
                
GNSSDataSmoothing

Generates a GNSS accumulated-delta-range aided pseudorange smoothing observation file using the assigned tracking files in the Scenario object. Called by the GenerateGNSSSPRObs html utility.


Prototype: bool GNSSDataSmoothing(string outputFile, int nPoints,


double minSNR, double rng3DiffTest,
double phase3DiffTest)

Where:

  • outputFile will contain the new measurements. File extension must support the output measurement type
  • nPoints is the number of phase measurements to smooth
  • minSNR is the SNR threshold
  • rng3DiffTest is the pseudo-range 3rd-difference test value, where 0 implies there is no test
  • phase3DiffTest is the phase 3rd-difference test value, where 0 implies there is no test

The returned Boolean is false if the output file cannot be created. Any status or error messages are written to the message viewer.


Example VBS:

outFile = "C:\Tmp\GNSSSPRObs.gobs"
bRes = ODTK.GNSSDataSmoothing(outFile, 5, 0, 0, 0)
odtk.WriteMessage bRes, "force"
                
HostID

Returns the host id, such as 001fa435ab78.


Prototype: CAgAttr HostID()


The returned object contains a string with the host ID.


Example VBS:

ODTK.WriteMessage ODTK.HostID, "force"
                    
InitialStateTool

Helper function for the Initial State Tool HTML interface. This function does not modify the initial state of a satellite; it parses the input file and provides information about what updates are possible based on the input. To actually update the initial conditions, one needs an STK ephemeris file to pass to the satellite's ReferenceTrajectory.UpdateInitial-Conditions function. Another useful application of this function is provided by calling the GetEphemTimeSpan function which in turn calls this function.


Prototype: CAgAttr InitialStateTool(string source,


        string filename, string command,
        string options)

Where:

  • source is "EPH", "TLE" "CCSDS" or "VCM"
  • filename is an ephemeris file (*.e | *.oem), TLE file, CCSDS OPM file, or VCM file
  • options is used when source = "TLE" or "VCM"

When source = "TLE", command may be:

  • an empty string ("") which will be used to provide a list of choices
  • "GEN" which will generate ephemeris in the *.e format

When source = "TLE", the options string may contain:

  • /ssc - SSC number of desired TLE, required for ephemeris generation
  • /epoch - Epoch of desired TLE in YYDDD.DDDDDDDD format, optional. If omitted, first TLE with correct SSC number is used
  • /start - Start time for ephemeris generation in Gregorian format, optional. If omitted, TLE epoch is used
  • /duration - Time span for ephemeris generation in minutes, optional
  • /step - Step size for ephemeris generation in minutes, optional

When source = "VCM," the options string may contain:

  • /ssc - SSC number of desired VCM, required for ephemeris generation
  • /epoch - Epoch of desired VCM in UTCG, required for ephemeris generation

If source is "VCM," this function reads the physical data from the VCM file and converts the initial state in the VCM file to an STK ephemeris file, containing a single ephemeris point. This function then returns an object with these members:

  • DragCoeff - double containing the Drag coeff
  • SRPCoeff - double containing the SRP coeff
  • STKFile - an STK ephemeris file containing the VCM initial vector
  • Succeed: Boolean indicating success of operation

If source is "EPH", returns an object with these members:

  • StartTime: string containing start time in UTCG
  • StopTime: string containing stop time in UTCG
  • Cov6x6: Boolean indicating availability of full 6x6 covariance in ephemeris file
  • CentralBody: string containing name of CB in file
  • Succeed: Boolean indicating success of operation

If source is "TLE", returns an object with these members:

  • TLEOutput: string containing name of file containing either the TLE choices or the ephemeris generated for a specific SSC
  • Succeed: Boolean indicating success of operationv

If source is "CCSDS", this function reads the physical data from the OPM file and converts the initial state in the OPM file to an STK ephemeris file, containing a single ephemeris point. This function then returns an object with these members:

  • StartTime: string containing start time in UTCG
  • StopTime: string containing stop time in UTCG
  • Cov6x6: Boolean indicating availability of full 6x6 covariance in ephemeris file
  • CentralBody: string containing name of CB in file
  • Mass: double containing mass of satellite in kg
  • DragCoeff: double containing drag coeff
  • DragArea: double containing drag area in m^2
  • SRPCoeff: double containing SRP coeff
  • SRPArea: double containing SRP area in m^2
  • STKFile: an STK ephemeris file containing the OPM initial vector
  • Succeed: Boolean indicating success of operation

Example VBS:

efile = "c:\tmp\MySat.e"
set retv = ODTK.InitialStateTool("EPH", efile,"","")
odtk.writemessage retv.starttime, "debug"
odtk.writemessage retv.stoptime, "debug"
odtk.writemessage retv.cov6x6, "debug"
odtk.writemessage retv.succeed, "debug"
odtk.writemessage retv.CentralBody, "debug"
                
IsPasteAvailable

Returns flag indicating whether or not contents of clipboard can be pasted as a child of the specified parent object. Used in conjunction with the CopyObject and PasteObject commands.


Prototpye: bool IsPasteAvailable(CAgAttr parentObject)


Example VBS:

bCanPaste = ODTK.IsPasteAvailable(sc)
                    
LambertSolution

Computes the Lambert Solutions found given a pair of radial positions separated in time. Must be preceded by two calls to the helper function NewPositionVector.


Prototype: CAgAttr LambertSolution(CAgAttr date1,


        CAgAttr pos1, CAgAttr date2, CAgAttr pos2)

Where:

  • date1 is a date object which is the time of the first position
  • pos1 is the NewPositionVector object for the first position
  • date2 is a date object for the second position
  • pos2 is the NewPositionVector object for the second position

Returns an object with many members:

  • nSol: integer number of solutions found (0, 1, or 2)
  • Succeed: Boolean which is false if no solutions
  • ErrorMsg: string containing error message, or blank
  • v11 has the velocity components at time 1 for the first solution:
    • X: X velocity component (quantity)
    • Y: Y velocity component (quantity)
    • Z: Z velocity component (quantity)
  • v12 has the velocity components at time 2 for the first solution
    • X: X velocity component (quantity)
    • Y: Y velocity component (quantity)
    • Z: Z velocity component (quantity)
  • v21 has the velocity components at time 1 for the second solution:
    • X: X velocity component (quantity)
    • Y: Y velocity component (quantity)
    • Z: Z velocity component (quantity)v
  • v22 has the velocity components at time 2 for the second solution
    • X: X velocity component (quantity)
    • Y: Y velocity component (quantity)
    • Z: Z velocity component (quantity)

v11, v12, v21, v22 = (0, 0, 0) when no corresponding solution is found.

Example VBS:

t1 = "01 Jan 2005 00:00:00.000 UTCG"
t2 = "01 Jan 2005 00:00:10.000 UTCG"

x1 = -6078486.439
x2 =  4652611.666
x3 =  -987009.666

a1 = -6102754.834
a2 =  4634162.069
a3 =  -921914.919

set pos1 = ODTK.NewPositionVector(x1, x2, x3, "m")
set pos2 = ODTK.NewPositionVector(a1, a2, a3, "m")

set retv = ODTK.LambertSolution(t1, pos1, t2, pos2)

odtk.writeMessage retv.Succeed, "force"
odtk.writeMessage retv.nSol, "force"
odtk.writeMessage  retv.v11.X.GetIn("km*sec^-1"), "force"
odtk.writeMessage  retv.v11.Y.GetIn("km*sec^-1"), "force"
odtk.writeMessage  retv.v11.Z.GetIn("km*sec^-1"), "force"
                
LoadLeapSecondAndEOPFiles

Loads the specified leap second and EOP files. Used to update leap second information while ODTK is running. Typically both leap second and EOP information should be updated together once the EOP information reflects the existence of the leap second via a step discontinuity in the UTI-UTC data at the time of the leap second. If leap second information is updated (due to the announcement of a new leap second) prior to the new leap second being reflected in the EOP data, a discontinuity in the modeled rotation of the Earth will be introduced.


The explicit specification of either input file is optional. If an empty string is passed instead of a full file path for the leap second file, the existing leap second file in the <ODTK_ALL_USERS_DIR>\DynamicEarthData directory will be loaded. If an empty string is passed instead of a full file path for the EOP file, the existing EOP file as specified in the Scenario properties will be loaded. If a full file path for the EOP file is specified, that file will be loaded and the Scenario properties updated to reflect the new filename. ODTK does not currently keep track of the location of the most recently loaded leap second file.


Prototype: bool LoadLeapSecondAndEOPFiles(string LeapSecondFile, string EOPFile)


Where:


  • leapSecondFile is the name of the leap second file to load. Specify an empty string to have the file in <ODTK_ALL_USERS_DIR>\DynamicEarthData reloaded.
  • EOPFile is the name of the EOP file to load. Specify an empty string to have the file identified in the Scenario properties reloaded.

Returns a Boolean indicating success.


Example VBS to extract global atmosphere density corrections without covariance information from a smoother output for the full time span.


leapSecFile = "C:\MyEarthData\NewLeapSecond.dat"
eopFile = "C:\MyEarthData\NewEOP=v1.1.txt"
success = odtk.LoadLeapSecondAndEOPFiles(leapSecFile, eopFile)
LoadObj

Loads an object from a file. The loaded object becomes a child of the input parent object.


Prototype: CAgAttr LoadObject(CAgAttr objName, string filename)


Where:

  • objName is the parent of the object being loaded
  • filename is the file containing the object being loaded

Returns the object that was loaded.


Example VBS:

Add a transponder onto a satellite:

                        set newObj = ODTK.LoadObj(sc.Sat1,"C:\tmp\ToGround.tpd")
                
LoadObject

Obsolete. Loads an object from a file using object names. The loaded object becomes a child of the input named object.


Prototype: bool LoadObject(string objName, string filename)v


Where:

  • objName is the name of the parent object
  • filename is the file containing the object being loaded

Returns true if object was loaded.


Example VBS:

Add a transponder onto a satellite:
ODTK.LoadObject "Scen1.Sat1","C:\tmp\ToGround.tpd"
                
NewDate

Creates a new date from a string.


Prototype: CAgAttr NewDate(string date, string units)


Example VBS:


sc.Filter(0).ProcessControl.StartTime = ODTK.NewDate("1 Aug 2009 08:05:30.00", "UTCG")

set nd = ODTK.NewDate("08183.5", "YYDDD")
ODTK.WriteMessage nd.Format("GNSSG"), "debug"
                    
Valid Date Formats
NewPositionVector

Helper function that creates a three (3)-component input for use by the LambertSolution function. Requires an input of three numbers and a valid unit string of length.


Prototype: CAgAttr NewPositionVector(double x, double y,
        double z, string units)

The returned object has three members which are quantities which are supposed to be position but have velocity units (so ignore the resulting units):

  • x: X position component
  • y: Y position component
  • z: Z position component

Example VBS:

unitstring = "m"
x1 = -6078486.439
y1 = 4652611.666
z1 = -987009.666
set pos1 = ODTK.NewPositionVector(x1, y1, z1, unitstring)
ODTK.WriteMessage pos1.X, "debug"
                    
NewQuantity

Creates a new quantity object, which is a value with units.


Prototype: CAgAttr NewQuantity(double value, string units)


The returned object is a quantity object.


Example VBS:

sc.Satellite(0).PhysicalProperties.Mass = ODTK.NewQuantity(3567.15, "lb")

set newMass = odtk.NewQuantity("1000", "kg")
odtk.WriteMessage newMass.GetIn("lb"), "force"
                    
PasteObject

Pastes contents of clipboard as child of specified parent object. See also the IsPasteAvailable and CopyObject commands.


Prototype: bool PasteObject(CAgAttr parentObject)


Returns flag indicating success.


Example VBS:

bSuccess = ODTK.PasteObject(sc)
                    
RegistrationID

Returns the registration ID, such as "DISK_SERIAL_NUM=a4e217c5".


Prototype: CAgAttr RegistrationID()


The returned object is a string.


Example VBS:

registrationIDStr = ODTK.RegistrationID
                    
RunScript

Allows control of ODTK to be passed to external script, in the same manner that the Filter's OnNoMoreObs script is called, for example. The function is passed a message and the personality object. This script then has complete control over ODTK, with the ability to create and delete objects, generate reports, etc.


Prototype: bool RunScript(string scriptName)


Where scriptName (such as filename.vbs) is a file containing a function with the signature:


Function filename(msg, ODTK)


End Function


Note that the function name MUST match the filename less the extension or else the script will not run.


The RunScript function always returns a value of true.


Example VBS:

scriptName = "C:\tmp\MyScript.vbs"
ODTK.RunScript scriptName

Where MyScript.vbs contains the following code:

Function MyScript(msg, od)
    regID = od.RegistrationID
    od.writeMessage "RegID: " & regID, "force"
End Function
                    
SaveObj

Saves an object by specifying the actual object and a flag indicating whether or not to save children of the object.


Prototype: CAgAttr SaveObj(CAgAttr object, string filename,
        bool bSaveChildren)

Where:

  • object is the object to be saved
  • filename is the output file to be saved
  • bSaveChildren is a Boolean specifying whether or not to save the child objects as well

When applied to scenarios SaveObj will change all internal paths to point to the new location of the scenario


Example VBS:


ODTK.SaveObj(scen.Sat1, "C:\tmp\Sat1.sao", true)
                

Also see ExportObj/

SaveObject

Obsolete. Save an object by specifying the name of the object. Children of the object will automatically be saved. Use the SaveObj function instead.


Prototype: bool SaveObject(string objectName,
        string filename)

Where:

  • objectName is the attributed name of the object
  • filename is the output file to be saved

Example VBS:

bSuccess = ODTK.SaveObject("Scen1.Sat1", "C:\tmp\Sat1.sao")
                
SeparateSP3

Supports SeparateSP3 Utility.

This utility separates a SP3 file containing mixed constellations into multiple SP3 files each containing data for an individual constellation.

The output files are named <inputfile>_T.<ext>

Where <inputfile> = input filename excluding the extension.

T = G for GNSS, R for GLONASS, E for Galileo, J for QZSS, C for BeiDou
<ext> is the inputfile extension (sp3)

Prototype: CAgAttr SeparateSP3(const string& inputSP3FileName)

Inputs are:

inputSP3FileName = the input SP3 filename.

The returned object contains 3 properties:

    "Succeed" = (CAgAttrBool) true/false if successful

    "Messages" = (CAgAttrString) "Informational or Error messages" to be displayed in the "status line"

    "FileNames" = (CAgAttrList of CAgAttrStrings) identifying the output filenames

Example VBS:

dim inputSP3FileName
inputSP3FileName = "C:\Test\test.sp3"
set ret = mach10.Application.SeparateSP3(inputSP3FileName)
if ret.Succeed then
    set listFileNames     = rec.FileNames
else
    MsgBox restartRecord.Messages
end if
                    
SetAsDefault

Sets specified object as the default object to be used when another object of that type is created. Default objects are saved to the Defaults folder under the Config directory.


Prototype: CAgAttr SetAsDefault(CAgAttr object)


Returns the default object if successful or an error message if not.


Example VBS:

set result = ODTK.SetAsDefault (sc.Satellite(0))
                    
SortUTDF

Sorts a UTDF Measurement file into increasing time order. The output format will be in UTDF regardless of the extension provided.


Prototype: bool SortUTDF(string inputFile, string outputFile)


Where:

  • inputFile is the source of the UTDF data
  • outputFile is the new UTDF file

Example VBS:

bResult = ODTK.SortUTDF("c:\trkData.trk","c:\trkData_sorted.trk")
                
SP3ToSimrun

Helper function to SP3_To_Simrun utility. Converts the GNSS orbit and clock states in the given SP3 file to a .simrun file (simulation state history file). This enables use of the ODTK State Differencing and Reporting/Graphing tools for analysis. See also the GNSSSourceToSimrun function.


Prototype: bool SP3ToSimrun(string SP3File, string


       constellationName, string outputFile)

Where:

  • SP3File is the input SP3 file to be converted
  • constellationName is the name used to label objects in the simrun file, which should match whatever you intend to compare against.
  • outputFile is the file name for the new simrun file

Returns a Boolean indicating success.


Example VBS:

sp3Input = "C:\tmp\input.sp3"
outputFile = "c:\tmp\gpsSource.simrun"
bResult = ODTK.SP3toSimRun(sp3Input, "GNSS", outputFile)
                
WriteMessage

Writes text to Message Viewer window allowing scripts to write informational messages, warnings, etc. Each type of message (warning, error, informational, debug) will have a unique icon next to it in the message viewer.


Prototype: bool WriteMessage(string message, string status)


Where:

  • message is the string to be written
  • status is the category of the message and must be one of the following strings:
    • "debug" - a debug message<
    • "forceinfo" or just "force" - an informational message
    • "warning" - a warning message
    • "error" or "alarm" - an error message

Returns a Boolean which is true if a message is written.


Example VBS:

ODTK.WriteMessage "Hello World", "error"
odtk.writeMessage sc.Satellite(0).Name, "force"
                

Filter Scope Functions

Attribute Description
ChangeCBs

Supports ChangeCentralBodyTool Utility.


This function is called to transition CBs within the filter. This function will update the CB(s) in the satellite object(s) and transform the selected restart state/covariance to the new CB(s) reference inertial frame. A new restart file will be created.


Prototype: CAgAttr ChangeCBs(const string& satListString, const string& CBListString)


Inputs are:

  • "satListString" = single string listing the satellite names, names are separated by white space, e.g. "Satellite1 Satellite2".
  • "CBListString" = single string listing the satellite CB names, same order as satListString. Names are separated by white space, e. g. "Earth Moon".

The returned object contains 2 properties:

  • "Succeed" = (CAgAttrBool) true/false if successful
  • "Messages" = (CAgAttrString) "Informational or Error messages" to be displayed in the "status line"

Example VBS:

satListString = "Satellite1 Satelllite2"
CBListString = "Earth Moon"
set retv = ODTK.Scenario(0).Filter(0).ChangeCBs(satListString, CBListString)
ODTK.writemessage retv.Succeed,"force"
ODTK.writemessage retv.Messages,"force"
                    
GenerateGNSSDDObs

Helper function to GenerateGNSSDDObs utility. Generates GNSS Double Difference Measurements from the currently assigned tracking data files which must contain the raw measurements of either type CA Pseudo-range or P1 & P2 pseudo-range to generate double differenced pseudo-range or LA, L1 or L2 phase to generate double differenced phase. The SatelliteList and TrackerList for the current filter restrict the combinations of double differenced measurements to be generated. The calling sequence allows for the specification of one double differenced pseudo-range and one double differenced phase type to be generated. The generation of dual frequency double differenced observations cannot be combined with the generation of single frequency double differenced observations in a single call. The format of the specified output file must be able to support doubly-differenced measurements; no error is returned if the requested format is invalid, it will just create a file of zero size. The number of measurements written will be displayed in the message viewer.


Prototype: bool GenerateGNSSDDObs(string prMeasType, string phaseMeasType, bool orthogonalObs, bool retainExcess, string filename)


Where:

  • prMeasType is either "CADD", "PDFDD" or ""
  • phaseMeasType is either "LADD", "L1DD", "L2DD", "LDFDD" or ""
  • orthogonalObs is either true or false and controls if the generated observations are restricted to be a set which are not correlated
  • retainExcess is either true or false and controls if raw observations not used in the generation of double differenced observations are saved to the output file
  • filename is the desired output filename

Returns flag indicating if output file was generated.


Example VBS:

filename = "c:\tmp\cadd.gobs"
bResult = sc.Filter(0).GenerateGNSSDDObs("CADD", "LADD", true, true, filename)
                
GetRestartTimeStrings

Returns list of restart time strings with date units included.


Prototype: CAgAttr GetRestartTimeStrings()


Returned object is a list of strings.


Example VBS:

set list = ODTK.Scenario(0).Filter(0).GetRestartTimeStrings
                    

Example result:

"11 Jul 2008 16:00:00.000 UTCG"
                    
GetSatCBs

Supports ChangeCentralBodyTool Utility. Reads the selected Filter restart record and returns the names of satellites and their associated central bodies.


Prototype: CAgAttr GenerateSatCBs()


The returned object contains 4 properties:

  • "Succeed" = (CAgAttrBool) true/false if successful
  • "Messages" = (CAgAttrString) "Informational or Error messages" to be displayed in the "status line"
  • "SatList" = (CAgAttrList of CAgAttrStrings) = list of satellite names
  • "CBList" = CAgAttrList of CAgAttrStrings = list of satellite CB names.

Example VBS:

set retv = ODTK.Scenario(0).Filter(0).GetSatCBs()
ODTK.writemessage retv.Succeed,"force"
ODTK.writemessage retv.Messages,"force"
ODTK.writemessage retv.SatList,"force"
ODTK.writemessage retv.CBList,"force"
                    
GetStateContents

Returns a list of states (as a list of strings) which will be the filter state when it runs. Called by StateContent tool.


Prototype: CAgAttr GetStateContents()


Returns a list of strings.


Example VBS:

Set stateList = sc.Filter(0).GetStateContents
for each thing in stateList
    odtk.writemessage thing, "debug"
next
                    

Example result:

"sat1    Orbit Z Velocity"
                    
Go

Runs the filter process in either start or restart mode.


Prototype: bool Go()


Example VBS:

bResult = sc.Filter(0).Go
                    

Returns flag indicating if the filter ran and if the following ephemeris prediction propagated to the requested stop time. In order to distinguish between the filter run itself and the ephemeris prediction you can inspect the following Boolean attributes with detailed status/error information:

Filter.RunResults.NumMeasAccepted = <int>
Filter.RunResults.NumMeasRejected = <int>
Filter.RunResults.NumMeasProcessed = <int>
Filter.RunResults.SumRatioSquareAccepted = <double>
Filter.RunResults.SumRatioSquareRejected = <double>
Filter.RunResults.InitializeSuccess = <bool>
Filter.RunResults.RestartSuccess = <bool>
Filter.RunResults.SetupSuccess = <bool>
Filter.RunResults.RunSuccess = <bool>
Filter.RunResults.RunCanceled = <bool>
Filter.RunResults.PropagatorError = <bool>
Filter.RunResults.EphemerisPredictPropagatorError = <bool>
Filter.RunResults.PropagatorAltitudeError = <bool>
Filter.RunResults.PropagatorVelocityError = <bool>
Filter.RunResults.PropagatorStateVectorError = <bool>
Filter.RunResults.PropagatorErrorSatelliteName = <string>
Filter.RunResults.PropagatorErrorTime = <time>
                    
OutputPropagatorDefn

Outputs a satellite's propagator definition to a file to be read by STK for initializing a satellite's integrator settings. The state written to the file is based on the filter results, where the epoch in the file will be at the last filter stop time.


Prototype: bool OutputPropagatorDefn(string satName,
        string filename)

Where:

  • satName is the name of one of the satellites in a filter run
  • filename is the name of the output file

Example VBS:

bSuccess = sc.Filter(0).OutputPropagatorDefn("sat1", "C:\tmp\sat1.pg")
                
Pause

Pauses the filter process. The filter can be stepped forward with StepForward, restarted with Go or ended with Stop.


Prototype: bool Pause()


Always returns a value of true.


Example VBS:

bSuccess = sc.Filter(0).Pause
                    
SetEditedResiduals

Helper function for the graphical residual editing capability. Graphical residual editing now works properly in cases where multiple observations of the same type from the same sensor exist for the same satellite at identical times. Previously, when one observation of a particular type was selected for editing, all other observations of the same type from the same sensor to the same satellite would also be edited. Normally, instead of using this function you would add entries to the CustomDataEditing.Schedule. This function updates the ResidualEditing Schedule.


Prototype: bool SetEditedResiduals(string inputs, string date, integer ntype, dvalue)


Where:

  • inputs contains the following items separated by spaces:
    • emitter ID (-1 if not set)
    • strand
    • tracker
    • satellite
    • measurement type
  • date contains the date string with units
  • Ntype contains type of measurement
  • Dvalue contains measurement value

Returns a Boolean indicating whether or not an entry was valid.


Example VBS:

inputs = "-1 TrackingSystem1.Facility1 - * TrackingSystem1.Facility1 Satellite1 Range "
dString = "01 Jul 2008 13:44:00 UTCG"
nype = 1
double_value = 1420193.763369
bSuccess = sc.Filter(0).SetEditedResiduals(inputs, dString, ntype, double_value)
                
StepForward

Moves the filter process forward one step.


Prototype: bool StepForward()


Returns flag indicating if filter ran.


Example VBS:

bSuccess = sc.Filter(0).StepForward
                    
Stop

Stops the filter process.


Prototype: bool Stop()


Returns a Boolean which is always true.


Example VBS:

bSuccess = sc.Filter(0).Stop
                    
Transfer

Transfers the filter solution to the estimated objects. Writes a summary of actions to the message viewer.


Prototype: bool Transfer()


Returns a Boolean which is always true.


Example VBS:

bSuccess = sc.Filter(0).Transfer
                    
ViewRestartData

Supports ViewRestartData Utility.


This function is called to display the state content of the filter restart record associated with the input restart time.


Prototype: CAgAttr ViewRestart(const string& restartTimeString)


Inputs are:

  • "restartTimeString" = restart time string,
  • e.g. "02 Jul 2011 11:17:00.000 UTCG"
The returned object contains 7 properties:
  • "Succeed" = (CAgAttrBool) true/false if successful
  • "Messages" = (CAgAttrString) "Informational or Error messages" to be displayed in the "status line"
  • "StateNames" = (CAgAttrList of CAgAttrStrings) identifying the filter states
  • "StateUnits" = (CAgAttrList of CAgAttrStrings ) identifying the state display units
  • "StateEstimates" = (CAgAttrList of CAgAttrDoubles) giving state estimates
  • "StateSigmas" = (CAgAttrList of CAgAttrDoubles) giving state estimates error root-variances
  • "StateErrorCovariance" = (CAgAttrList of CAgAttrDoubles) giving a lower triangular representation of the state error covariance matrix

Example VBS:

dim restartTimeString
dim restartRecord
restartTimeString = "02 Jul 2011 11:17:00.000 UTCG"
set restartRecord = fil.ViewRestartData(restartTimeString)
if restartRecord.Succeed then
    set listStateNames     = restartRecord.StateNames
    set listStateUnits     = restartRecord.StateUnits
    set listStateEstimates = restartRecord.StateEstimates
    set listStateSigmas    = restartRecord.StateSigmas
else
    MsgBox restartRecord.Messages
end if
                

GNSSConstellation Scope Functions

Attribute Description
AddGNSSSatellites

Adds the GNSS Satellites in the GNSS Source file to the GNSS Constellation.


Prototype: bool AddGNSSSatellites()


Returns a Boolean which is true if no errors occurred.


Example VBS:

bSuccess = sc.GGNSS.AddGNSSSatellites
                    
GNSSSourceToSimrun

This function was used as the helper function to the GNSSSource_To_Simrun utility prior to ODTK 7. It has been replaced by GNSSSourceToSimrun7. It is still maintained to support any legacy user scripts.

Helper function for GNSSSource_To_Simrun utility. Converts the GNSS orbit and clock states given in the GNSS Constellation source file to a .simrun file (simulation state history file). This enables use of the ODTK State Differencing and Reporting/Graphing tools for analysis. Note that GNSS Source file may be in .sp3, .aux, .yuma, .sem, or .rinex format. Also, the OverrideStartTime flag in the GNSS constellation object must be set to false. See also the SP3ToSimrun function.


Prototype: bool GNSSSourceToSimrun(string outputFile,
        double dtMin)

Where:

  • outputFile is the file name for the new simrun file
  • dtMin is the data output granularity in minutes

Returns a Boolean indicating success.


Example VBS:

outputFile = "c:\tmp\gpsSource.simrun"
bResult = sc.GNSS.GNSSSourceToSimrun(outputFile, 30.0)
                
GNSSSourceToSimrun7

Helper function for the GNSS Source ToSimRun Utility

 

Converts the GNSS orbit and clock states given in the GNSS Constellation source file to a .simrun file (simulation state history file). This enables use of the ODTK State Differencing and Reporting/Graphing tools for analysis. Note that GNSS Source file may be in .sp3, .aux, .yuma, .sem, or .rinex format.

 

Prototype: bool GNSSSourceToSimrun(string outputFile,
        double dtMin)

Where:

  • outputFile is the file name for the new simrun file
  • startTime is the start time of the .simrun file. If the GNSS Source file is a SP3 file, then this time must be contained within the start/stop range of the SP3 file.
  • stopTime is the stop time of the .simrun file. If the GNSS Source file is a SP3 file, then this time must be contained within the start/stop range of the SP3 file.
  • dtMin is the data output granularity in minutes

Returns a Boolean indicating success.


Example VBS:

outputFile = "c:\tmp\gpsSource.simrun"
bResult = sc.GNSS.GNSSSourceToSimrun(outputFile, "02 Jun 2012 00:00:00 GNSSG", "03 Jun 2012 00:00:00 GNSSG", 15.0)
                    
GNSSUTCSteeringReport

Generates a report containing GNSS- UTC Time Steered Bias and Drift vs. Non-Steered Bias and Drift for purposes of analysis. It uses the GNSS steering parameters given in the GNSS constellation object, which may be defined when there are GNSSSatellite objects in the constellation.


Returns a Boolean which is true if the report was created.


Prototype: bool GNSSUTCSteeringReport(string startTime,
double duration, double timeStep,
string filename))

Where:

  • start time is the report start time, which includes units
  • duration is report duration in hours
  • timeStep in report granularity in minutes
  • filename is the report output filename

Example VBS:

start = "1 Jul 2008 12:00:00 GNSSG"
duration = 1
dt = 15
file = "C:\tmp\steering.txt"
bResult = sc.GNSS.GNSSUTCSteeringReport(start, duration, dt, file)
                
RemoveGNSSSatellites

Removes all GNSS Satellites from the GNSS Constellation.


Prototype: bool RemoveGNSSSatellites()


vAlways returns a value of true.

Example VBS:

bResult = sc.GNSS.RemoveGNSSSatellites
                
RemoveGNSSSatellitesWithMessage

Removes all GNSS Satellites from the GNSS Constellation with a message box to confirm the remove operation.


Prototype: bool RemoveGNSSSatellitesWithMessage()


Returns a value of false if the operation is cancelled by the user.


Example VBS:

bResult = sc.GNSS.RemoveGNSSSatellitesWithMessage
                    
ReplaceICRFWithJ2000

This function cycles through each GNSSSatellite object that is part of the GNSSConstellation and looks for references to the ICRF frame and changes them to the J2000 frame. For each satellite, it will transform the orbit from ICRF to J2000. It will also check the ephemeris generation CoordFrame and check each maneuver frame, changing frames from ICRF to J2000 (does not otherwise modify maneuver data). Any changes are indicated in the message viewer.


Calling this same function at the scenario level will in turn call this function for each satellite and GNSSSatellite object.


Prototype: bool ReplaceICRFWithJ2000()


Always returns a result of true.


Example VBS:

bResult = sc.GNSS.ReplaceICRFWithJ2000
                    
RetrieveCatalogData

Helper function for the ViewGroupDelayData utility. This utility compares the SV group delay (Tgd) values in the Catalog to those in in RINEX NAV message. This function itself retrieves the Tgd values from the Catalog for those SVs that are active at the given time.

Prototype: CAgAttr RetrieveCatalogData(

const string& sCatalogFilename, const int& week, const double& toa)

where:

    sCatalogFile = is the full name of the Catalog file

    week = GNSS week (from GNSS epoch 06 Jan 1980)

    toa = seconds of the GNSS week

The returned object contains these members:

  • Succeed: a boolean indicating success
  • GNSS: a character constellation identifier following RINEX convention (‘G’ = GNSS, ‘E’ = Galileo, ‘R’ = GLONASS, ‘C’ = BeiDou, ‘J’ = QZSS)
  • EpochTime: an output time string converting (week,toa)
  • PRNData: integer list of PRNs
  • SVNData: parallel integer list of SV numbers
  • TgdData: parallel double precision list of Group Delay data in seconds
  • Messages: a string showing errors or other status

Example VBS:

sCatalogFile = dir & "GNSSCatalog.txt"
week         = 1651
toa          = 2599200

set retv = ODTK.RetreveCatalogData(sCatlogFile, week, toa)
odtk.writemessage retv.Succeed,"force"
odtk.writemessage retv.GNSS,"force"
odtk.writemessage retv.EpochTime,"force"
odtk.writemessage retv.Messages,"force"
set listPRNData = retv.PRNData
set listSVNData = retv.SVNData
set listTgdData = retv.TgdData

kount = listPRNData.count

if kount > 0 Then
    for a = 0 to kount - 1
        set prnData = listPRNData(a)

        prnI = listPRNData(a)
        snum = listSVNData(a)
        tgdC = listTgdData(a)
    next
end if
                    

GNSSReceiver Scope Functions

Attribute Description
SiteSolution

Helper function for the OD GenerateSiteSolution utility. Generates a GNSS receiver position and clock solution from pseudo-range observations in RINEX format. This function now has an addditional (last) argument which takes in a string with the name of GNSS Constellation ("GNSS," "GALILEO," "GLONASS," "BeiDou") that limits algorithm to use only obs originated from GNSS satellites that belong to said constellation


Prototype: CAgAttr SiteSolution(string RinexFile, string SP3File,
        bool bSP3RepresentsAntennaPhaseCenter,
        string solutionEpoch, string observationStartTime,
        string observationStopTime)

Where:

  • RinexFile is a string containing the name of a RINEX data file
  • SP3File is a string containing the name of a SP3 file of GNSS satellite ephemeris
  • Sp3RepresentsAntennaPhaseCenter is a Boolean which is set to true if the ephemeris in the SP3 file is that of the GNSS satellite antenna phase center
  • SolutionEpoch is a time string in UTCG
  • ObservationStartTime is a time string in UTCG
  • ObservationStopTime is a time string in UTCG

Returns an object with the following members:

  • NumberOfObs - number of observations used in solution (int)
  • X - Earth fixed X coordinate of receiver location estimate (Quantity)
  • Y - Earth fixed Y coordinate of receiver location estimate (Quantity)
  • Z - Earth fixed Z coordinate of receiver location estimate (Quantity)
  • ClockPhase - Receiver clock offset from GNSS Time (Quantity)
  • ClockFrequency - Receiver clock offset rate in seconds/second (double)
  • ErrorMsg - contains an error message string if method fails, empty if no errors (string)
  • Succeed - indicates success or failure of method (bool)

Example VBS:

rinex = "c:\tmp\GpsSite.rnx"
sp3 = "c:\tmp\GpsSite.sp3"
epoch = "1 May 2006 00:05:00.000"
start = "1 May 2006 00:02:00.000"
stop = "1 May 2006 00:09:00.000"
set facRcvr = sc.TrackingSystem(0).Facility(0).GNSSReceiver(0)
set retVal = facRcvr.SiteSolution(rinex, sp3, true, epoch, start, stop)
odtk.WriteMessage "Solution X: " & retVal.X.GetIn("km"), "debug"
                    

InitialOrbitDetermination Scope Functions

Attribute Description
Go

Runs the IOD process.


Prototype: bool Go()


Returns a Boolean which is true if the IOD process runs.


Example VBS:

bSuccess = sc.Satellite(0).InitialOrbitDetermination(0).Go
                    
Transfer

Transfers the IOD solution to the parent satellite.


Prototype: bool Transfer()


Returns false if there is no solution to be transferred.


Example VBS:


bSuccess = sc.Satellite(0).InitialOrbitDetermination(0).Transfer
                    
SelectMeasurementsByTime

Two functions assist setting IOD input measurements programmatically:

  • HerrickGibbsIODObject.Method.SelectMeasurementsByTime("time1","time2","time3")
  • AnglesOnlyIODObject.Method.SelectMeasurementsByTime("time1","fac1","time2","fac2","time3","fac3")

Both functions return Boolean indicating if they were successfull in setting all three measurements at requested times.

By default, if no fractional seconds are provided, times are matched to the nearest 0.5 sec. If you specify additional digits up to 3, the matching precision is increased by the factor of ten:

Input -> Precision
13:05:08 -> 0.5 sec
13:05:08.1 - 0.05 sec
13:05:08.11 - 0.005 sec
13:05:08.111 - 0.0005 sec

Example VBS:

r1 = ODTK.Scenario(0).Sat1.IOD1HG.Method.SelectMeasurementsByTime("13 Aug 2012 13:00:00", "13 Aug 2012 13:02:00", "13 Aug 2012 13:06:00")
alert r1
r2 = ODTK.Scenario(0).Sat1.IOD2AO.Method.SelectMeasurementsByTime("13 Aug 2012 13:01:00","Fac1","13 Aug 2012 13:02:00", "Fac2", "13 Aug 2012 13:04:00", "Fac3")
alert r2
                    

LeastSquares Scope Functions

Attribute Description
GetStateContents

Previews what states will be used by a least squares process. For least squares processes with multiple stages this will reflect the states for the first stage. Called by StateContent tool.


Prototype: CAgAttr GetStateContents()


Returns a list of states (as a list of strings) applicable to the simulator.


Example VBS:

Set stateList = sc. Satellite("Sat1").LeastSquares("LS1").GetStateContents
                    
Go

Runs the Least Squares process.


Prototype: bool Go()


Returns a Boolean which is always true.


Example VBS:

bSuccess = sc.Satellite(0).LeastSquares(0).Go
                    

Returns flag indicating if the LeastSquares ran and if the following ephemeris prediction propagated to the requested stop time. In order to distinguish between the LeastSquares run itself and the ephemeris prediction you can inspect the following Boolean attributes with detailed status/error information:

LeastSquares.RunResults.NumMeasProcessed = <int>
LeastSquares.RunResults.NumMeasRejected = <int>
LeastSquares.RunResults.NumMeasSkipped = <int>
LeastSquares.RunResults.SetupSuccess = <bool>
LeastSquares.RunResults.RunSuccess = <bool>
LeastSquares.RunResults.RunCanceled = <bool>
LeastSquares.RunResults.MaxIterationsExausted = <bool>
LeastSquares.RunResults.PropagatorError = <bool>
LeastSquares.RunResults.EphemerisPredictPropagatorError = <bool>
LeastSquares.RunResults.PropagatorAltitudeError = <bool>
LeastSquares.RunResults.PropagatorVelocityError = <bool>
LeastSquares.RunResults.PropagatorStateVectorError = <bool>
LeastSquares.RunResults.PropagatorErrorSatelliteName = <string>
LeastSquares.RunResults.PropagatorErrorTime = <time>
LeastSquares.RunResults.FinalRMS
LeastSquares.RunResults.DivergenceDetected
                    
SetEditedResiduals

Helper function for the graphical residual editing capability. Graphical residual editing now works properly in cases where multiple observations of the same type from the same sensor exist for the same satellite at identical times. Previously, when one observation of a particular type was selected for editing, all other observations of the same type from the same sensor to the same satellite would also be edited. Normally, instead of using this function you would add entries to the CustomDataEditing.Schedule. This function updates the ResidualEditing Schedule.


Prototype: bool SetEditedResiduals(string inputs, string date, integer ntype, dvalue)


Where:

  • inputs contains the following items separated by spaces:
    • emitter ID (-1 if not set)
    • strand
    • tracker
    • satellite
    • measurement type
  • date contains the date string with units
  • Ntype contains type of measurement
  • Dvalue contains measurement value

Returns a Boolean indicating whether or not an entry was valid.


Example VBS:

inputs = "-1 TrackingSystem1.Facility1 - * TrackingSystem1.Facility1 Satellite1 Range "
dString = "01 Jul 2008 13:44:00 UTCG"
nype = 1
double_value = 1420193.763369
bSuccess = sc.Filter(0).SetEditedResiduals(inputs, dString, ntype, double_value)
Stop

Stops the currently running LS process.


Prototype: bool Stop()


Returns a Boolean which is always true.


Example VBS:

bSuccess = sc.Satellite(0).LeastSquares(0).Stop
                    
Transfer

Transfers the LS solution to the parent satellite.


Prototype: bool Transfer()


Returns false if there is no solution to be transferred.


Example VBS:

bSuccess = sc.Satellite(0).LeastSquares(0).Transfer
                    
IODLS

Helper function to GEO_IODLS utility. This utility performs GEO initial orbit determination (IOD) using a Least Squares (LS) search algorithm. A one-dimensional search is made in GEO Mean Longitude until LS convergence is achieved with an orbit estimate that falls within the GEO orbit class.


To use this utility/function the user needs a scenario containing the GEO satellite of interest, a Least Squares object attached to the GEO, and tracking system information. The scenario should be set up just as if the user were running a LS on the GEO (including setting up of the LS stage data). The only difference is that the white panel satellite initial orbit estimate is ignored and replaced by the initial estimates input in the calling list. Note however that the white panel satellite state epoch time is used as the epoch for the initial conditions.


Prototype: bool _IODLS(double longRange, double longStep, double Initiala, double Initiale, double Initialu, douible Initiali, double InitialO, double Initialw, string reportFilename)


Where:

  • longRange = +/- range for the mean longitude search. Note: if 10000 is entered for Initialu then the range of the longitude search will be computed based on tracker locations.
  • longStep = mean longitude search step. (Let L0 be initial mean longitude for the search. Then the search order will be L0, L0 + longStep, ,L0 - longStep, L0 + 2*longStep, ... until either n*longStep > longRange or convergence is achieved)
  • Initiala = initial semi-major axis estimate in km
  • Initiale = initial eccentricity estimate
  • Initialu = initial argument of latitude estimate in deg. If 10000 is entered then an initial argument of latitude estimate is computed based on tracker locations
  • Initiali = initial inclination estimate in deg
  • InitialO=initial node estimate in deg
  • Initialw=initial arg of perigee estimate in deg

Return flag indicates if LS convergence was obtained. If it was obtained the LS Output.OutputState will contain the solution.


Example VBS (to have IODLS compute a starting true argument of latitude based on tracker locations)

filename = "c:\tmp\iodls.txt"
bResult = sc.Satellite("GEOSatellite1").LeastSquares("LeastSquares1").IODLS(90, 10, 42164, 0.005, 10000, 0, 0, 0, filename)

Example VBS (user inputs initial true argument of latitude estimate)

filename = "c:\tmp\iodls.txt"
bResult = sc.Satellite("GEOSatellite1").LeastSquares("LeastSquares1").IODLS(90, 10, 42164, 0.005, 80, 0, 0, 0, filename)

Product Builder Scope Functions

Attribute Description
GenerateAllProducts

Generates reports from all Data Products in the Data Product list.


Prototype: bool GenerateAllProducts()


Returns a Boolean which is always true


Example VBS:

bResult = odtk.productbuilder.generateAllProducts
                    
GenerateProduct

Generates a report or graph using single Data Product name, where the name is specified in the list of Products in the static product builder.


Prototype: bool GenerateProduct(string productName)


Returns a Boolean which is false if product generation failed for a known reason.


Example VBS:

bResult = odtk.productbuilder.generateProduct("Range Residuals")
                    
LoadDataProductList

Loads a Data Product List from a saved file.


Prototype: bool LoadDataProductList (string filename)


Returns a Boolean which is true if the file loaded.


Example VBS:

f = "C:\od_6.0\Styles\AER.dpl"
bResult = odtk.productbuilder.LoadDataProductList(f)
                    
SaveDataProductList

Saves a Data Product List to a file.


Prototype: bool SaveDataProductList (string filename)


Returns a Boolean which is always true.


Example VBS:

f = "C:\od_6.0\Styles\AER_new.dpl"
bResult = odtk.productbuilder.SaveDataProductList(f)
                    

Satellite and GNSSSatellite Scope Functions

Attribute Description
Go

Generates ephemeris for the specified satellite over the time span given in the satellite's EphemerisGeneration attributes.


Prototype: bool Go()


Returns a Boolean indicating whether or not ephemeris generation was successful.


Example VBS:

bResult = sc.Satellite(0).Go
                    
InitialCovarianceIsPositiveDefinite

Returns a boolean indicating if the initial orbit error covariance, expressed in the OrbitUncertainty settings is positive definite.


Prototype: bool InitialCovarianceIsPositiveDefinite()


Returns a Boolean indicating if the initial orbit error covariance, expressed in the OrbitUncertainty settings is positive definite.


Example VBS:

bResult = sc.Satellite(0).OrbitUncertainty.InitialCovarianceIsPositiveDefinite()
                    
OEMToSTKEphemeris

Converts a CCSDS 502 OEM *.oem file to a STK Ephemeris *.e file.


Prototype: bool OEMToSTKEphemeris (sting inputFile, string outputFile)


Returns a Boolean indicating whether or not ephemeris conversion was successful.


Example VBS:

bResult = sc.Satellite(0). OEMToSTKEphemeris("C:\od\sat1.oem", "C:\od\sat1.e")
                    
OutputPropagatorDefn

Outputs propagator definition to a file to be read by STK for initializing a satellite's integrator settings.


Prototype: bool OutputPropagatorDefn(string outputFile)


Takes the output filename as an argument, and returns a Boolean indicating whether or not file was created.


Example VBS:

sc.GNSS.GNSSSatellite(0).OutputPropagatorDefn "C:\od\gps1.pg"
                    
PropEphem

Helper function for InitalStateTool utility. Propagates satellite state from current epoch to a new time. Can be used to generate an ephemeris file or move a satellite state to a new epoch. This function is accessed via the Satellite's EphemerisGeneration attribute scope.


Prototype: bool PropEphem(string filename, string stopTime, bool inclCov, bool updateState)


Where:

  • filename: optional output filename; if not specified, a temporary file is used
  • stopTime: end time of propagation span. Also the new epoch if updating the state
  • inclCov: indicates whether or not covariance is propagated
  • updateState: if true, resets the satellite's initial state and epoch (does not update the initial orbit uncertainty)

Returns a Boolean indicating success.


Example VBS:

Set sat = sc.Satellite(0)
bResult = sat.EphemerisGeneration.PropEphem("c:\temp\sat.e","1 Jul 2009 05:30:00 UTCG", false, true)
                    
ReplaceICRFWithJ2000

This function looks for references to the ICRF frame and changes them to the J2000 frame. For a satellite, it will transform the orbit from ICRF to J2000. It will also check the ephemeris generation CoordFrame and check each maneuver frame, changing frames from ICRF to J2000 (does not otherwise modify maneuver data). Any changes are indicated in the Message Viewer.


Calling this same function at the scenario level will in turn call this function for each satellite and GNSSSatellite object.


Prototype: bool ReplaceICRFWithJ2000()


Always returns a result of true.


Example VBS:

bResult = sc.Satellite(0).ReplaceICRFWithJ2000
                    
STKEphemerisToOEM

Converts a STK Ephemeris *.e file to a CCSDS 502 OEM *.oem file. The file will be converted using the Scenario.SatEphemeris.CCSDS and Satellite.CCSDS controls. Note that the output *.oem ephemeris will be in the central body default inertial frame regardless of the input *.e ephemeris coordinate frame.


Prototype: bool STKEphemerisToOEM (sting inputFile, string outputFile)


Returns a Boolean indicating whether or not ephemeris conversion was successful.


Example VBS:

bResult = sc.Satellite(0). STKEphemerisToOEM ("C:\od\sat1.e", "C:\od\sat1.oem")
                    
Stop

Causes the generation of satellite ephemeris to stop. The ephemeris file will contain the ephemeris generated until the Stop command was received.


Prototype: bool Stop()


Always returns a result of true.


Example VBS:

bResult = sc.Satellite(0).Stop
                    
UpdateCentralBody

This function changes a satellite's OrbitState central body. The possible choices are Earth, Moon and Sun. The satellite's initial state is converted based on the Cartesian elements to an orbit around the new central body. When the choice is Moon or Sun, it also exposes the satellite's DynamicReports attributes and updates the DynamicReports.CentralBody value. This function is accessed via the Satellite's ReferenceTrajectory attribute scope.


Prototype: bool UpdateCentralBody(string cbName)


Returns a result of true if central body was successfully changed.


Example VBS:

bResult = sc.Satellite(0).ReferenceTrajectory.UpdateCentralBody("Earth")
                    
UpdateInitialConditions

Computes a new set of initial conditions for a satellite based on the reference ephemeris defined in the given file. This function is accessed via the Satellite's ReferenceTrajectory attribute scope.


Prototype: bool UpdateInitialConditions(string filename, string newEpoch, string sUnused, bool bPerturb, bool bUpdateCov, bool bUnused)


Where:

  • filename: refers to an ephemeris (*.e | *.oem) file
  • newEpoch: desired epoch for sat1
  • sUnused is an unused string
  • bPerturb controls whether to randomly perturb the initial conditions
  • bUpdateCov controls whether to change the a priori covariance
  • bUnused is a reserved parameter and is not used

Returns a Boolean indicating success


Example VBS:

Set sat = sc.GNSS.GNSSSatellite(0)
bResult = sat.ReferenceTrajectory.UpdateInitialConditions( "c:\temp\sat.e","1 Jul 2009 05:30:00 UTCG", "", true, true, false)
                    

A new function was added for v6.5.2, Satellite.ReferenceTrajectory.UpdateInitialConditions2(), which allows a passing satellite epoch to be in any valid date time format.

Satellite Scope Functions

Attribute Description
DoesRefTrajHaveCov

Helper function for InitalStateTool utility. Returns true/false if the reference trajectory for the associated satellite object contains valid covariance data. The Satellite.EstimateOrbit flag must be set to false for this function to work properly.


Prototype: bool DoesRefTrajHaveCov()


Example VBS:

result = sc.Satellite(0).DoesRefTrajHaveCov
                    

Scenario Scope Functions

Attribute Description
ReloadEOP

Reloads the Earth Orientation Parameters data file.


Prototype: bool ReloadEOP()


Returns a Boolean indicating whether or not it read the file.


Example VBS:

bResult = sc.ReloadEOP
                    
ReloadFacilityAssociationsFile

Reloads the Facility Associations File specified by the FacilityAssociationsFile attribute.


Prototype: bool ReloadFacilityAssociationsFile()


Returns a Boolean indicating whether or not it read the file.


Example VBS:

bResult = ODTK.Scenario(0).ReloadFacilityAssociationsFile()
                    
ReloadFlux

Forces clearing of the flux data cache and subsequent reloading of the flux data.


Prototype: bool ReloadFlux()


Returns a Boolean indicating whether or not it read the file.


Example VBS:

bResult = sc.ReloadFlux
                    
ReplaceICRFWithJ2000

This function looks for references to the ICRF frame and changes them to the J2000 frame. For satellite and GNSSSatellite orbits, transforms the orbit from ICRF to J2000. It will also check the ephemeris generation CoordFrame and check each maneuver frame, changing frames from ICRF to J2000 (does not otherwise modify maneuver data). Any changes are indicated in the Message Viewer.


Prototype: bool ReplaceICRFWithJ2000()


Always returns a result of true.


Example VBS:

bResult = sc.ReplaceICRFWithJ2000
                    
RINEXClockToSimrun

Helper function to the RinexReceiverClock_to_simrun utility.

This utility creates a .simrun file containing Receiver Clock Data. Clock data from the given RINEX file is extracted for each receiver in the scenario. Data is extracted for that receiver if 1) the receiver contains the 4-character IGS mnemonic as part of its name and 2) a clock phase estimate is contained for each time point in the file. If the clock file does not contain clock phase rate values, frequencies in the .simrun file are set to zero.

Prototype: CAgAttr RINEXClockToSimrun (string inputFile, string outputFile)

The returned object contains two members:

  • Succeed: a Boolean indicating success
  • Messages: a string showing errors or other status

Example VBS:

ifile = "C:\tmp\igs6445.clk"
ofile = "c:\tmp\igs6445.simrun

set retv = ODTK. RINEXClockToSimrun (ifile, ofile, input)
odtk.writemessage retv.Succeed,"force"
odtk.writemessage retv.Messages,"force"
                    
SetEphCoordFrame

Updates the Scenario SatEphemeris.CoordFrame list, and also resets all output ephemeris coordinate frame settings in the Satellite, Simulator, Filter, VLS, Smoother objects for satellites whose initial conditions are reference to the given central body.


Prototype: bool SetEphCoordFrame(string cbName, string coordFrame)


Returns a Boolean false if either cbName or coordFrame are illegal choices.


Example VBS:

bResult = sc. SetEphCoordFrame("Earth", "Fixed")
                    
TimeSpan

This function gets the scenario start and stop times based on the scenario DefaultTimes.Processes settings.


Prototype: CAgAttr TimeSpan()


Returns an object containing two members, which are both Date objects: StartTime and StopTime.


Example VBS:

set ts = sc.TimeSpan
odtk.writemessage ts.StartTime.Format("UTCG"),"debug"
odtk.writemessage ts.StopTime.Format("UTCG"),"debug"
                    

Scenario.Measurements Scope Functions

The following methods are designed to support the verification and saving of observation files into another file and/or format.

Attribute Description
HaveMoreObs

Checks whether more measurements are available.


Prototype: bool HaveMoreObs()


Returns a Boolean; true if measurements are available, false if there are none.


Example VBS:

ODTK.WriteMessage sc.Measurements.HaveMoreObs, "debug"
                    
PreviewTrackingData

Previews tracking data from the input tracking data file(s). Writes summary information to the Message Viewer, showing both file-by-file and overall summaries of number of measurements and time span, as well as the names of trackers and satellites based on tracking IDs. If the tracking IDs from the files cannot be resolved to objects loaded in the scenario, then the tracking ID is shown.


Prototype: PreviewTrackingDataStructure PreviewTrackingData()


Returns PreviewTrackingDataStructure which contains the following members:

  • Succeed - Boolean true/false
  • TotalObsCount - Integer
  • StartTime - AgDate
  • StopTime - AgDate
  • TrackerSetStr - space delimited list of trackers
  • SatSetStr - space delimited list of satellites
  • FacSetStr - space delimited list of facilities
  • MeasFile - list of:
    • FileName - string
    • ObsCount - Integer
    • StartTime - AgDate
    • StopTime - AgDate

Example usage:


Open ScriptingTool, and execute this scriptlet:

set mlist = scen.Measurements.PreviewTrackingData()
                    

Then type 'mlist' in the lower input box and press the "Props" button. You will be able to explore the structure returned from the call to PreviewTrackingData()

Reset

Reset measurement files to the beginning. Should be done before saving observations.


Prototype: bool Reset()


Returns a Boolean which is always true.


Example VBS:

sc.Measurements.Reset
                    
SaveObs

Save measurements to a file. Accepts a filepath as input and, if the file can be created and the file format can accept the measurements, saves the measurements to that filepath.


Before calling SaveObs, use VerifySaveObsMeasTypes to determine if format is valid. Only those measurements which can be written to the specified format will be saved.


Prototype: bool SaveObs(string FileName)


Always returns a result of true.


Example VBS:

sc.Measurements.SaveObs "c:\tmp\savedMeasFile.gobs"
                    
SetValidation

Enables/disables measurement validation based on the input flag. Validation refers here to considering measurements which are applicable to a loaded scenario. For instance, if your scenario points to a tracking data file and not all of the measurements are related to the objects in your scenario, and you attempt to save it with validation on, only the measurements related to your scenario will be saved. If you turn off validation then all of the measurements will be saved. Turning validation off will make saving measurements faster.


The validation setting has no effect on the application of the scenario's Measurements.ViewAndSave.CustomDataEdting attributes. If a schedule is defined and enabled, it will be applied regardless of the validation being on or off.


Prototype: bool SetValidation(bool bValidate)


This function returns a Boolean which is always true.


Example VBS:

bResult = sc.Measurements.SetValidation(false)
                    
VerifySaveObsMeasTypes

Verify ability to save measurements to a specific file format, determining whether any are compatible with the filetype specified in the input parameter file path.


Prototype: CAgAttr VerifySaveObsMeasTypes(string FileName)


The function returns an object with three members:

  • VerifyOK - bool - returns true if verify is successful
  • ErrorMsg - string - returns an error message if unsuccessful
  • NumValidMeasTypes - int - returns a count of the number of valid measurement types found (0 if no valid types found)

Example VBS:

set result = sc.Measurements.VerifySaveObsMeasTypes("c:\tmp\savedMeasFile.rnx")
odtk.writemessage result.VerifyOK, "debug"
odtk.writemessage result.ErrorMsg, "debug"
odtk.writemessage result.NumValidMeasTypes, "debug"
                    

Simulator Scope Functions

Attribute Description
ClearIntervals

Function to clear simulation intervals for given satellite and/or tracker. Called by STKIntFileTool and LoadSimulationIntervals html pages.


Prototype: CAgAttr ClearIntervals(string satName, string trkName)


An empty input string ("") for satName or trkName is interpreted to mean any object.


Returns a Boolean indicating whether or not it performed any action.


Example VBS:

bFlag = sc.Simulator(0).CustomDataEditing.ClearIntervals("","BOSS-A")
                    
GetStateContents

Previews what states will be used by the simulator. Called by StateContent tool.


Prototype: CAgAttr GetStateContents()


Returns a list of states (as a list of strings) applicable to the simulator.


Example VBS:

Set stateList = sc.Simulator(0).GetStateContents
                    
Go

Runs the simulator.


Prototype: bool Go()


Returns Boolean which is true if there are no errors initiating the simulator.


Example VBS:

bSuccess = sc.Simulator(0).Go
                    
ImportIntervals

Function to import intervals from an STK Intervals File, which will add or append entries in the simulator's CustomTrackingIntervals Schedule. Called by STKIntFileTool and LoadSimulationIntervals html pages.


Prototype: CAgAttr ImportIntervals(string filename, double dt, string satName, string trkName)


The inputs are:

  • Filename: the filename containing the intervals
  • dt: the time step in seconds
  • satName: use specific satellite, or use "All Satellites", or use "" to get the satellite names from the interval file itself
  • trkName: use specific tracker, or use "All Trackers", or use "" to get the tracker names from the interval file itself

Returns a Boolean indicating success.


Example VBS:

f = "c:\tmp\StkIntervals.int"
bSuccess = sc.Simulator(0).CustomTrackingIntervals.ImportIntervals(f,15.0,"All Satellites","All Trackers")
                    
SimulateDeltaDOR

Generates simulated Differenced One-way Range (DOR) and Quasar Differenced One-Way Range (QuasarDOR) measurements based on a specified reference ephemeris to a generic observation format file (.gobs). The DOR and QuasarDOR measurements may then be read back into ODTK to create DeltaDOR measurements for use in estimation. The first specified tracking station must contain measurement statistics for DOR and QuasarDOR measurement types. The white noise settings for the DOR and QuasarDOR measurement types will be used in the generation of random variation to the computed measurement values based on the Simulator object setting for inclusion of white noise. Time correlated measurement biases based on the stochastic model definition are not generated or included in the reported measurement values. The number of measurements written will be displayed in the message viewer.


Observations are generated in sequences where a sequence contains an odd number of observations and takes the Q-S-Q-S-Q-S-Q where Q designates a QuasarDOR measurement and S designates a DOR measurement. One sequence is generated during a viewing opportunity.


The Facility1 object must contain the appropriate measurement statistics for the DOR and QuasarDOR measurement types for simulation to be successful. Facility1 must also contain DeltaDOR measurement statistics in order to process measurements.


Prototype: CAgAttr SimulateDeltaDOR (const string& startString, const string& stopString, int numDDOR, double slewTime, double interSeqTime, const string& facility1String, const string& facility2String, const string& satelliteString, int quasarID, double quasarDirTol, const string& refEphFileName, const string& observationFileName, const string& detailsFileName) bool addToScenarioMeasFilesList


Inputs are:


  • " startString " = time to start simulated observation generation
  • " stopString " = time to start simulated observation generation
  • "numDDOR" = desired number of DeltaDOR observations which can be generated from an observation sequence. For example, a Q-S-Q-S-Q-S-Q can be used to generated 3 DeltaDOR observations, one from each Q-S-Q combination
  • "slewTime" = time between spacecraft and quasar observations inside an observation sequence specified in seconds
  • "interSeqTime" = minimum time between observation sequences specified in seconds
  • "facility1String" = name of facility object containing the measurement statistics for the DOR and QuasarDOR measurements.
  • "facility2String" = name of the second facility object in the DOR baseline
  • "satelliteString" = name of the satellite
  • "quasarID" = integer id for a quasar to be used in the generation of the QuasarDOR measurements. Ids must be resolvable by the information in the file identified by the QuasarDatabaseFilename in the scenario properties. The quasar id can be specified as zero to have ODTK automatically select a quasar near the line of sight to the spacecraft for each observation sequence.
  • "quasarDirTol" = quasar direction tolerance specified in degrees. How far off the line of the sight to the spacecraft can a quasar be used in the generation of QuasarDOR measurements. Used when the quasarID is set to zero.
  • "refEphFileName" = name of ephemeris file in STK format (.e), which contains the trajectory of the satellite.
  • "observationFileName" = name of the output observation file, (.gobs) format, into which the generated DOR and QuasarDOR observations will be written.
  • "detailsFileName" = name of an optional text file to which details about the measurement generation, including the quasar ids, will be written. Can be omitted or specified as an empty string if file is not desired.
  • "addToScenarioMeasFileList" = optional boolean indicating if the generated measurement file should be added to the list of measurement files in the Scenario properties. Default is true.

The returned object contains seven (7) properties:


  • "Succeed" = (CAgAttrBool) true/false if successful
  • "Messages" = (CAgAttrString) "informational or error messages" to be displayed in the "status line"
  • "QuasarID" = (CAgAttrInt) id of quasar used in first observation sequence
  • "NumSequencesGenerated" = (CAgAttrInt) number of QDOR/DOR sequences generated
  • "NumObservationsGenerated" = (CAgAttrInt) number of QDOR + DOR observations generated
  • "NumTripletsGenerated" = (CAgAttrInt) number of Q-S-Q triplets generated. Each triple will be converted to one DeltaDOR measurement during estimation.

Example VBS:

Dim Sim
Sim result
set Sim = ODTK.Scenario(0).Simulator("Simulator_DOR_QDOR")
startDate = "18 Aug 2020 00:00:00.000"
stopDate = "20 Aug 2020 00:00:00.000"
numDDOR = 3
slewTime = 60.0
interSeqTime = 7000.0
satName = "MMO"
quasarID = 0
quasarDirTolerance = 10.0
ephFile = "C:\MarsSat_Truth.e"
detailsFile = "C:\MarsSat_DOR_Details.txt"
fac1Name = "DSS65"
fac2Name = "DSS34"
satName = "MarsSat"
obsFile = "C:\MarsSat_DOR_QDOR.gobs"
set result = Sim.SimulateDeltaDOR (startDate, stopDate, numDDOR, slewTime, interSeqTime, fac1Name, fac2Name, satName, quasarID, quasarDirTolerance, ephFile, obsFile, detailsFile)
msgbox result.succeed
msgbox result.messages
msgbox result.numsequencesgenerated
msgbox result.numtripletsgenerated
msgbox result.numobservationsgenerated
                    
Stop

Stops the execution of the simulator.


Prototype: bool Stop()


Always returns a result of true.


Example VBS:

bSuccess = sc.Simulator(0).Stop
                    

Smoother Scope Functions

Attribute Description
GetStateContents

Previews what states will be used by the smoother based on a specific rough file. Called by StateContent tool.


Prototype: CAgAttr GetStateContents(string roughFilename)


Returns a list of states (as a list of strings) applicable to the smoother.


Example VBS:

rFile = "c:\temp\SampleRoughFile.rough"
Set stateList = sc.Smoother(0).GetStateContents(rFile)
                    
Go

Runs the smoother.


Prototype: bool Go()


Returns a Boolean indicating whether or not smoother ran to completion.


Example VBS:

bSuccess = sc.Smoother(0).Go
                    

Returns flag indicating if the smoother ran and if the following ephemeris prediction propagated to the requested stop time. In order to distinguish between the smoother run itself and the ephemeris prediction you can inspect the following Boolean attributes with detailed status/error information:

Smoother.RunResults.SetupSuccess = <bool>
Smoother.RunResults.RunSuccess = <bool>
Smoother.RunResults.RunCanceled = <bool>
Smoother.RunResults.PropagatorError = <bool>
Smoother.RunResults.EphemerisPredictPropagatorError = <bool>
Smoother.RunResults.PropagatorAltitudeError = <bool>
Smoother.RunResults.PropagatorVelocityError = <bool>
Smoother.RunResults.PropagatorStateVectorError = <bool>
Smoother.RunResults.PropagatorErrorSatelliteName = <string>
Smoother.RunResults.PropagatorErrorTime = <time>
                    
Stop

Stops the execution of the smoother.


Prototype: bool Stop()


Always returns a result of true.


Example VBS:

bSuccess = sc.Smoother(0).Stop
                    

The function:

Satellite.UpdateInitialConditions(bool randomlyPerturb, string filename, string epoch, string startTime)

computes a new set of initial conditions for satellite based on the reference ephemeris defined in the given file. The epoch of the desired state and the startTime of the ephemeris are specified in UTC in the format "DD MMM YYYY HH:MM:SS.SSS". The randomlyPerturb flag indicates if the interpolated state should be subjected to a random perturbation based on the satellite orbit uncertainty values. This function is used in the initial state tool.

TrackingSystem Scope Functions

Attribute Description
BuildGNSSGroundReceiverSites

Helper function to the CreateReceiverSite utility.

This utility creates a set of Facility/GNSSReceiver/Antenna objects for each enabled RINEX observation file in the Scenario.Measurements.Files list. The RINEX approximate position, marker number, and antenna H/E/N offset are extracted and copied into the objects.

Prototype: bool BuildGNSSGroundReceiverSites ()

Example VBS:

dim rc
rc = ODTK.Scenario(0).TrackingSystem("TrackingSystem1").
BuildGNSSGroundReceiverSites()
                    
BuildGRSite

Attribute function attached to the TrackingSystem object.

For each RINEX obs file in the Scenario Measurement list, it will add the Facility/GNSSReceiver/Antenna object under the TrackingSystem object and provide:

  • RINEX header receiver approximate position as the facility object position
  • Marker number to GNSS Receiver tracking id
  • H/E/N offset as antenna offset

Note it will only be added if the Facility/GNSSReceiver/Antenna does not already exist.

Example:

Starting Scenario
 
Result
 

Sample Scripts

Several HTML files containing VBScripts that use OD attributes can be found in the following folder:

<InstallDir>\ODTK\AppData\LaunchPad\Utilities\

To run any of these scripts, simply load the corresponding HTML file into the ODTK HTML Viewer. To view some examples of the use of attributes in scripts, click on the following examples:

The examples shown here have a .txt extension so that they will display properly. The original .htm versions of these and other files appear in the folder identified above.

Set Smoother Attributes
This script illustrates the use of attributes in configuring and running the smoother object. Among other things, it uses two functional attributes for smoother processing, Go() and Stop().
Satellite Ephemeris Generation
This script creates a test scenario and satellite and generates a number of ephemeris files that can be used to define satellite orbits in STK.
Initial State Tool
Based on data obtained from a selected external ephemeris (*.e) file, this script generates the initial state for the selected satellite.
Generate Simulator Schedule
Select ground and space based trackers, mission ground stations and target satellites, and set various constraints to generate a simulator schedule that can be exported as an STK scenario.

The following JavaScript illustrates the use of numerous ODTK attributes.

CloneSapphire (JavaScript)
This program creates the Sapphire scenario via JavaScript and COM. It assumes that ODTK is installed and one or no instances of the program exist. It can use a GUI and allow user interaction or run behind the scenes.