Getting Started

The SatGen Scenario API provides a complete programmatic interface for creating, configuring, and running GNSS (Global Navigation Satellite System) signal simulations. It allows you to generate simulated satellite signals for testing GNSS receivers without requiring physical satellite visibility.

Prerequisites

Quick Start

using SatGen.ScenarioAPI;

// Create a scenario starting at a specific UTC time
using var scenario = new Scenario(DateTime.UtcNow, AttenuationDB: -3);

// Set a static position (latitude, longitude, altitude in metres, duration in seconds)
scenario.TrajectoryFromStaticPoint(51.5074, -0.1278, 100, 600);

// Stream GPS L1 in real time to a LabSat 4 over Ethernet
scenario.SetOutputToLabSat4Realtime("172.16.20.14",
    RealTimeOutputMode.UserTime,
    new[] { SignalType.GpsL1CA },
    Quantization.TwelveBit,
    new LabSat4RealtimeOutputOptions { SatCountLimitMode = SatCountLimitMode.Automatic });

// Run the simulation
scenario.StartSimulation();
scenario.MonitorSimulationProgress(TimeSpan.FromSeconds(1));

Typical Workflow

1
Create a Scenario
Instantiate a Scenario with a simulation start time and optional attenuation.
2
Configure Almanacs Optional
Optionally supply local almanac files per constellation via ManualAlmanacFile() — useful for reproducing a known scenario or working offline. By default the latest almanacs are downloaded automatically.
3
Configure Dynamics Optional
Set the vehicle dynamics profile (Car, RaceCar, Train, Pedestrian, or Custom). Only applies to route-style trajectories; imported trajectories carry their own motion data.
4
Define a Trajectory
Choose how the simulated receiver moves: static point, waypoint route, KML file, NMEA log, VBOX file, CSV, or script.
5
Configure Output
Set where the simulated signals are sent: LabSat file, LabSat Real-Time, or LabSat 4.
6
Schedule Timeline Events Optional
Optionally queue satellite changes via AddSatelliteTimelineChange() to be applied at fixed elapsed times during the run. Must be scheduled before StartSimulation().
7
Start & Monitor
Start the simulation, monitor progress with callbacks, and optionally adjust satellites or LabSat 4 channel attenuation mid-simulation.

Scenario Class

The primary entry point for the SatGen Scenario API. This class provides a complete programmatic interface for creating, configuring, and running GNSS (Global Navigation Satellite System) signal simulations.

A typical workflow involves:

  1. Create a new Scenario instance with a simulation start time
  2. Optionally configure dynamics using SetDynamics or SetCustomDynamics
  3. Define a trajectory (e.g. TrajectoryFromStaticPoint, TrajectoryFromRoute, TrajectoryFromKMLFile, etc.)
  4. Configure the output device and signals (e.g. SetOutputToLabSatFile, SetOutputToLabSatRealtime, etc.)
  5. Start the simulation with StartSimulation
  6. Monitor progress using MonitorSimulationProgress or by polling SimulationPercentComplete and IsRunning
  7. End the simulation with EndSimulation or wait for it to complete, then dispose the instance

This class implements IDisposable and should be disposed when no longer needed to release internal resources such as the simulation engine, almanac services, and output handlers.

public class Scenario : IDisposable

Constructor

public Scenario(DateTime startUTCDateTime, double attenuationDB = -3, double elevationMaskDeg = 5)
Creates a new SatGen scenario and initialises the simulation engine, dependency injection services, and almanac data. This constructor must be called before any other API methods. It sets up the internal services required for trajectory generation, signal simulation, and output handling.

The simulation start time is truncated to the nearest whole second, as SatGen requires simulations to begin on a second boundary.

ParameterDescription
startUTCDateTimeThe UTC date and time at which the simulation should begin. This determines the satellite constellation positions via the almanac data, so it should be set to a realistic date/time for accurate results. Sub-second precision is discarded.
attenuationDBThe global signal attenuation level in decibels (dB), used to add artificial noise to the simulated signal. Valid range is -15.0 to 0.0. A value of 0.0 disables attenuation entirely. Default is -3 dB, which provides a realistic noise floor for most testing scenarios.
elevationMaskDegThe elevation mask angle in degrees. Satellites below this elevation angle (relative to the horizon) will be excluded from the simulation. Valid range is -90 to 90 degrees. Default is 5 degrees, which filters out low-elevation satellites that typically have degraded signal quality.

Example:

// Basic usage:
var simulationDateTime = new DateTime(2026, 1, 1, 12, 0, 0);
using var scenario = new Scenario(simulationDateTime);

// Full usage with all parameters:
var simulationDateTime = new DateTime(2026, 1, 1, 12, 0, 0);
using var scenario = new Scenario(simulationDateTime, attenuationDB: -3, elevationMaskDeg: 5);

Properties

PropertyTypeDescription
BufferUnderrunCountintGets the number of buffer underruns that have occurred during the current real-time simulation. A buffer underrun happens when the host computer cannot generate simulated signal data fast enough to keep up with the real-time output rate. Each underrun may cause a brief gap in the output signal.

This property is only meaningful when the output is set to a LabSat Real-Time device. For file-based output, this will always return 0.

AutomaticSatCountLimitintGets the current automatic satellite count limit during a real-time simulation. When Automatic is enabled, this value represents the maximum number of satellites being simulated. It starts at the initial value (default 999 = unlimited) and is automatically reduced each time a buffer underrun occurs, shedding satellites to reduce CPU load.

This property reflects the live value during a running simulation, or the configured initial value when not running.

IsReadyboolGets a value indicating whether the simulation is currently in a preparing or ready state, waiting for input data before it can begin generating output.

This is particularly relevant for real-time simulations using an external input source (e.g. LabSat or RS232 serial), where the simulation enters a ready state while waiting for the first trajectory data to arrive. For SatGen-generated trajectories, this state is typically brief as the data is already available.

IsRunningboolGets a value indicating whether the simulation is currently running and actively generating output data.

This property becomes true after StartSimulation is called and the simulation engine has successfully begun processing. It returns to false when the simulation completes naturally, encounters an error, or is stopped via EndSimulation.

SimulationStartTimeDateTimeGets the accurate UTC start time of the simulation.

Before StartSimulation is called, this returns the start time supplied to the Scenario(DateTime, double, double) constructor (truncated to the nearest whole second). Once the simulation starts, this value reflects the actual UTC start time used by the simulation engine, which may differ from the originally supplied value — for example, real-time "CurrentTime" output mode rounds the start time up to the next minute boundary (plus an initialisation buffer).

OutputFilePathstringGets the full path of the output file that the simulation is writing to.

For file-based simulations (e.g. SetOutputToLabSatFile), this returns the absolute path of the first file that the engine writes the simulated signal data to, including the file extension chosen by the output device (e.g. .LS2, .LS3W, .LS3).

LabSat3 is a special case: it places its output in a subfolder named after the file stem and numbers each chunk, so a supplied path of C:\out\foo.ls3 produces an actual first file at C:\out\foo\foo_0000.LS3. This property returns that actual first-chunk path. Long simulations may produce additional chunks (_0001.LS3, _0002.LS3, ...) in the same subfolder.

For real-time simulations (e.g. SetOutputToLabSatRealtime, SetOutputToLabSat4Realtime) no file is written, so this returns an empty string.

SimulationSecondsFromStartdoubleGets the number of seconds that have been simulated since the simulation started. This value is the simulated time, not wall-clock time - for file-based output the simulation can advance faster than real time.

Updated periodically by the simulation engine; consumers can either poll this property or subscribe to SimulationStatusChanged to receive push-style updates.

SimulationPercentCompletedoubleGets the completion progress of the current simulation as a percentage from 0.0 to 100.0.

For file-based simulations with a known duration this represents the proportion of the trajectory that has been processed. On natural completion this reaches exactly 100.0. For real-time simulations the value may not reach 100.0 as the simulation runs indefinitely until stopped.

SimulationErrorstringGets the error message if an error has occurred during the simulation. Returns Empty if no error has occurred.

Common error conditions include: failure to initialise the simulation engine, inability to open the output port, LabSat device not found, or invalid output file path. Check this property when a simulation appears to have stopped unexpectedly.

InputConnectionStatusInputConnectionStatusGets the connection status of the external trajectory input source.

This is only relevant for real-time simulations that receive trajectory data from an external source:

  • Connected - The input source is connected and sending trajectory data
  • Disconnected - The input source has stopped sending data (connection lost)
  • None - No external input source is used (SatGen-generated trajectory)
For simulations using SatGen's built-in trajectory generation (static point, route, KML, etc.), this property will always be None.

CurrentStatusSimulationStatusGets the current lifecycle status of the simulation. Mirrors the most recent Status value carried by the SimulationStatusChanged event, so a consumer that subscribes to the event after the simulation has already started (or finished) can recover the current state.

Defaults to Running before the first update arrives - meaning "not yet started or in progress". Transitions to Completed on natural completion or to Failed on error, and stays there until the scenario is disposed.

Scenario

public void LoadSatGenFile(string satGenFilePath)
Loads a complete SatGen scenario from a .sgen file. The scenario file contains all settings needed for a simulation including the trajectory, satellite configuration, output settings, almanac settings, and signal selections.

This method is useful when you have a pre-configured scenario created in the SatGen desktop application that you want to replay programmatically. Because the scenario file already supplies a full configuration, calling any of the SetOutputTo* methods (and other scenario configuration calls) is optional. Any settings applied beforeLoadSatGenFile are overwritten by the file's contents, while any settings applied after the call layer on top of the loaded configuration.

ParameterDescription
satGenFilePathThe full absolute path to the SatGen scenario file (.sgen) to load. Example: @"C:\Scenarios\MyTest.sgen"
Throws FileLoadException: Thrown if the scenario file could not be loaded (e.g. file not found, corrupt, or invalid format).

Example:

scenario.LoadSatGenFile(@"C:\SatGen\Scenarios\example.sgen");

Almanacs

public void ManualAlmanacFile(ConstellationType constellation, string almanacFilePath)
Overrides the automatic almanac download for a specific constellation by pointing it to a local almanac file instead.

By default, the API automatically downloads the latest almanac data from the Racelogic almanac server for each constellation. Use this method when you need to use a specific almanac file, for example:

  • Reproducing a specific test scenario with known satellite positions
  • Testing in an environment without internet access
  • Using custom or modified almanac data

ParameterDescription
constellationThe GNSS constellation to set the manual almanac for (e.g. ConstellationType.GPS, ConstellationType.Galileo, etc.).
almanacFilePathThe full absolute path to the almanac file. The required file format depends on the constellation type (e.g. YUMA for GPS, XML for Galileo).

Example:

// Call once per constellation in use:
scenario.ManualAlmanacFile(ConstellationType.GPS, @"C:\Almanacs\gps.alm");

Dynamics

public void SetDynamics(Dynamics dynamics)
Sets the vehicle dynamics profile to one of the pre-defined SatGen options. The dynamics profile defines the maximum speed, acceleration, deceleration, and jerk limits that the simulated vehicle can achieve.

This affects how the trajectory is generated when using route-based trajectories. For imported trajectories (NMEA, VBOX, CSV), the dynamics profile does not modify the imported data.

ParameterDescription
dynamicsThe pre-defined dynamics profile to apply. Options include:
  • Car - Standard car driven at normal speeds
  • RaceCar - High-performance vehicle with aggressive acceleration/braking
  • Train - Railway vehicle with gradual acceleration/deceleration
  • Pedestrian - Walking speed with low acceleration limits

Example:

scenario.SetDynamics(Dynamics.Car);
public void SetCustomDynamics(CustomDynamicsOptions dynamicsParams)
Sets the vehicle dynamics profile to fully custom values, allowing precise control over all motion parameters. Use this when the pre-defined profiles (SetDynamics) do not match your test requirements.

All acceleration values are specified in g-force units and jerk values in g/s. These limits constrain how the simulated vehicle accelerates, decelerates, and corners when following a route trajectory.

ParameterDescription
dynamicsParamsA CustomDynamicsOptions instance containing all nine dynamics parameters: horizontal velocity (km/h), longitudinal acceleration/deceleration (g), lateral acceleration (g), vertical acceleration (g), and their corresponding jerk values (g/s).

Example:

scenario.SetCustomDynamics(new CustomDynamicsOptions(
    horizontalVelocity: 200,             // km/h
    longitudinalAcceleration: 0.5,        // g
    longitudinalDeceleration: 0.8,        // g
    lateralAcceleration: 0.4,             // g
    verticalAcceleration: 0.1,            // g
    longitudinalAccelerationJerk: 0.5,    // g/s
    longitudinalDecelerationJerk: 0.8,    // g/s
    lateralJerk: 0.3,                     // g/s
    verticalJerk: 0.1));                  // g/s

Trajectory

public void TrajectoryFromStaticPoint(double latitudeDecDegrees, double longitudeDecDegrees, double altitudeMetres, int durationInSeconds)
Creates a trajectory from a single fixed geographic position. The simulated GNSS receiver will remain stationary at this location for the specified duration. This is useful for:
  • Testing receiver cold/warm start behaviour at a known location
  • Evaluating receiver accuracy in a static environment
  • Validating signal acquisition and tracking performance
ParameterDescription
latitudeDecDegreesThe latitude of the static position in decimal degrees (e.g. 51.5074 for London). Valid range: -90.0 to 90.0.
longitudeDecDegreesThe longitude of the static position in decimal degrees (e.g. -0.1278 for London). Valid range: -180.0 to 180.0.
altitudeMetresThe altitude of the static position above the WGS84 ellipsoid in metres (e.g. 0.0 for sea level).
durationInSecondsThe total duration of the static simulation in seconds. Must be a positive integer.

Example:

scenario.TrajectoryFromStaticPoint(
    latitudeDecDegrees: 51.9831552,
    longitudeDecDegrees: -0.999424,
    altitudeMetres: 100,
    durationInSeconds: 600);
public void TrajectoryFromRoute(RoutingMode routingMode, IReadOnlyList<RouteWaypoint> routeWaypoints)
Creates a trajectory from a sequence of waypoints, with the route between them calculated using the specified routing mode. The simulation engine will generate a smooth, realistic vehicle trajectory that follows roads (if road routing is used) or straight lines between each waypoint, respecting the configured dynamics profile.

Each RouteWaypoint defines a geographic position along with optional speed and cornering parameters. The routing mode determines how the path between waypoints is calculated (e.g. road driving, straight line, rail, etc.).

ParameterDescription
routingModeThe method used to calculate the path between waypoints. Common values include road-based routing for driving simulations, or straight-line for direct point-to-point paths.
routeWaypointsAn ordered list of waypoints that define the route. At least two waypoints are required to create a moving trajectory. Each waypoint specifies a latitude, longitude, altitude, target speed, and apex distance limit.

Example:

// Basic usage:
var waypoints = new[]
{
    new RouteWaypoint(51.9831552, -0.999424, 100),
    new RouteWaypoint(51.9900000, -0.990000, 100),
};
scenario.TrajectoryFromRoute(RoutingMode.Road, waypoints);

// Full usage with all waypoint properties set:
var fullWaypoints = new[]
{
    new RouteWaypoint(51.9831552, -0.999424, 100)
    {
        TargetSpeedKilometersPerHour = 50,
        ApexDistanceLimitMetres = 5,
    },
    new RouteWaypoint(51.9900000, -0.990000, 100)
    {
        TargetSpeedKilometersPerHour = 80,
        ApexDistanceLimitMetres = 20,
    },
    new RouteWaypoint(51.9950000, -0.980000, 110)
    {
        TargetSpeedKilometersPerHour = 60,
        ApexDistanceLimitMetres = 10,
    },
};
scenario.TrajectoryFromRoute(RoutingMode.Road, fullWaypoints);
public void TrajectoryFromScript(string satgenFilePath, ScriptTrajectoryOptions? trajectoryOptions = null)
Creates a trajectory from a SatGen script embedded in a .sgen scenario file. Scripts allow complex, multi-segment trajectories to be defined programmatically using the SatGen scripting language, which supports commands for straight-line motion, turns, altitude changes, speed profiles, and more.

The script is extracted from the first script entry in the specified .sgen file and parsed to generate a complete trajectory. If the script contains errors, they are collected and thrown as an AggregateException.

ParameterDescription
satgenFilePathThe full absolute path to the SatGen file (.sgen) containing the script trajectory definition.
trajectoryOptionsOptional configuration for the script trajectory. If null, default options are used (10 Hz output data rate). Use this to override the output data rate for the generated trajectory.
Throws InvalidDataException: Thrown if the .sgen file cannot be deserialized into a valid SatGen scenario (e.g. corrupt file or invalid JSON).
Throws AggregateException: Thrown if the script contains one or more parsing errors. Each inner exception is a ScriptParseException whose Message includes the line number, and whose Line property exposes the line number directly.

Example:

// Basic usage:
scenario.TrajectoryFromScript(@"C:\SatGen\Scenarios\example.sgen");

// Full usage with all options set:
scenario.TrajectoryFromScript(
    @"C:\SatGen\Scenarios\example.sgen",
    new ScriptTrajectoryOptions
    {
        OutputDataRate = OutputDataRate._10Hz,
    });
public void TrajectoryFromKMLFile(string kmlFilePath, KMLTrajectoryOptions? trajectoryOptions = null)
Creates a trajectory from a KML (Keyhole Markup Language) file. KML files are commonly exported from Google Earth and other mapping applications, making this a convenient way to define test routes by drawing paths on a map.

The KML file should contain a LineString or path element defining the trajectory coordinates. The route can optionally be repeated multiple times and the height values can be interpreted as stop times.

ParameterDescription
kmlFilePathThe full absolute path to the KML file containing the route definition.
trajectoryOptionsOptional configuration for the KML trajectory. If null, default options are used (no repeat, height as altitude, 100 km/h target speed, 10m apex distance limit).

Example:

// Basic usage:
scenario.TrajectoryFromKMLFile(@"C:\Data\KML\route.kml");

// Full usage with all options set:
scenario.TrajectoryFromKMLFile(
    @"C:\Data\KML\route.kml",
    new KMLTrajectoryOptions
    {
        RepeatCount = 2,
        UseHeightAsStopTime = false,
        TargetSpeedKilometersPerHour = 80,
        ApexDistanceLimitMetres = 15,
    });
public void TrajectoryFromNMEAFile(string nmeaFilePath, NMEAFileTrajectoryOptions? trajectoryOptions = null)
Creates a trajectory from an NMEA log file. NMEA (National Marine Electronics Association) files contain position data logged from a real GNSS receiver, allowing you to replay real-world journeys as simulated signals.

Supported NMEA sentence types include GGA (position), RMC (position + velocity), and VTG (velocity/course). The gravitational model determines how altitude values from the NMEA data are interpreted.

ParameterDescription
nmeaFilePathThe full absolute path to the NMEA log file (.nmea or .txt).
trajectoryOptionsOptional configuration for the NMEA trajectory. If null, default options are used (WGS84 gravitational model, use RMC/VTG ground speed).

Example:

// Basic usage:
scenario.TrajectoryFromNMEAFile(@"C:\Data\NMEA\drive.nmea");

// Full usage with all options set:
scenario.TrajectoryFromNMEAFile(
    @"C:\Data\NMEA\drive.nmea",
    new NMEAFileTrajectoryOptions
    {
        GravitationalModel = GravitationalModel.WGS84,
        Options = NmeaTrajectoryOptions.UseRmcVtgGroundSpeed,
    });
public void TrajectoryFromVBOXFile(string vboxFilePath, GravitationalModel gravitationalModel = GravitationalModel.WGS84)
Creates a trajectory from a Racelogic VBOX data file. VBOX files contain high-precision position and velocity data logged from Racelogic VBOX data loggers, making this ideal for replaying real-world test drives with centimetre-level accuracy.
ParameterDescription
vboxFilePathThe full absolute path to the VBOX data file (.vbo).
gravitationalModelThe gravitational model (altitude datum) used to interpret altitude values from the VBOX file. Default is WGS84 (WGS84 ellipsoid height). Use EGM96 if the VBOX data contains geoid-referenced altitudes.

Example:

// Basic usage:
scenario.TrajectoryFromVBOXFile(@"C:\Data\VBOX\drive.vbo");

// Full usage with all parameters set:
scenario.TrajectoryFromVBOXFile(
    @"C:\Data\VBOX\drive.vbo",
    gravitationalModel: GravitationalModel.EGM96);
public void TrajectoryFromCSVFile(string csvFilePath, char delimiter = ',', bool isInRadians = false)
Creates a trajectory from a CSV (Comma-Separated Values) file containing position data. The CSV file should contain rows of position data with latitude, longitude, and altitude columns.

This is a flexible import format that can be used with data exported from various tools and systems. The coordinate format (degrees or radians) and field delimiter can be configured.

ParameterDescription
csvFilePathThe full absolute path to the CSV file containing trajectory position data.
delimiterThe character used to separate fields in the CSV file. Default is a comma (','). Use '\t' for tab-separated files or ';' for semicolon-separated files.
isInRadiansSet to true if the latitude and longitude values in the CSV file are in radians. Set to false (default) if they are in decimal degrees.

Example:

// Basic usage:
scenario.TrajectoryFromCSVFile(@"C:\Data\CSV\trajectory.csv");

// Full usage with all parameters set:
scenario.TrajectoryFromCSVFile(
    @"C:\Data\CSV\trajectory.csv",
    delimiter: ';',
    isInRadians: true);

Output

public void SetOutputToLabSatFile(string outputDirectory, string outputName, LabSatFileOutputMode outputMode, IReadOnlyList<SignalType> signals, Quantization quantization = Quantization.OneBit)
Configures the simulation to write output data to a file in the specified LabSat format. The generated file can then be played back on a physical LabSat device to replay the simulated GNSS signals.

The output format determines the file structure and is tied to the target LabSat hardware:

  • LabSat1 - Generates a .bin file for LabSat 1 devices
  • LabSat2 - Generates a .ls2 file for LabSat 2 devices
  • LabSat3 - Generates a .ls3 file for LabSat 3 devices
  • LabSat3WB - Generates a .LS3W file for LabSat 3 Wideband devices
  • LabSat4 - Generates a .LS4 file for LabSat 4 devices

ParameterDescription
outputDirectoryThe directory where the output should be written. May be absolute (e.g. @"C:\Output") or relative (resolved against the simulation's working directory). Note that some LabSat formats create a sub-directory here named after and place their output files inside it.
outputNameThe base name for the output (without an extension, and without a directory component). The extension appropriate to the selected is added automatically (.bin, .ls2, .ls3, .LS3W, or .LS4); any extension you include here will be stripped.
outputModeThe LabSat file format to use, which determines the target playback device.
signalsA list of GNSS signal types to include in the output (e.g. SignalType.GpsL1CA, SignalType.GalE1). The available signals depend on the selected output mode and quantization level.
quantizationThe bit depth for each signal sample. Higher quantization provides better signal quality but requires more bandwidth and storage. Default is OneBit.
Throws NotSupportedException: Thrown if the specified output mode is not supported.

Example:

var signals = new[] { SignalType.GpsL1CA, SignalType.GpsL2P };

// Basic usage:
scenario.SetOutputToLabSatFile(
    @"C:\SatGen\Output",
    "scenario",
    LabSatFileOutputMode.LabSat3,
    signals);

// Full usage with all parameters set:
scenario.SetOutputToLabSatFile(
    @"C:\SatGen\Output",
    "scenario",
    LabSatFileOutputMode.LabSat4,
    signals,
    Quantization.TwelveBit);
public void SetOutputToLabSatRealtime(RealTimeOutputMode outputMode, IReadOnlyList<SignalType> signals, Quantization quantization = Quantization.OneBit, LabSatRealtimeOutputOptions? options = null)
Configures the simulation to stream output data directly to a connected LabSat Real-Time device over USB. The device will broadcast the simulated GNSS signals in real-time, allowing a connected GNSS receiver to track the simulated satellites.

Quantization guidance:

  • Use 2-bit quantization for single-frequency output (e.g. GPS only, GPS+GAL, BDS only)
  • Use 1-bit quantization for dual-frequency output (e.g. GPS+GLO, GPS+BDS, GPS+GAL+GLO)

ParameterDescription
outputModeThe timing mode for the real-time output:
  • UserTime - Uses the scenario's configured start time
  • CurrentTime - Uses the current system clock time
  • NMEATime - Uses the scenario date combined with NMEA input time
signalsA list of GNSS signal types to include in the real-time output.
quantizationThe bit depth for each signal sample. Default is OneBit.
optionsOptional configuration for real-time output, including satellite count limiting. If null, defaults are used (automatic satellite count limiting enabled).

Example:

var signals = new[] { SignalType.GpsL1CA };

// Basic usage:
scenario.SetOutputToLabSatRealtime(
    RealTimeOutputMode.UserTime,
    signals);

// Full usage with all parameters and all option properties set:
scenario.SetOutputToLabSatRealtime(
    RealTimeOutputMode.UserTime,
    signals,
    Quantization.TwelveBit,
    new LabSatRealtimeOutputOptions
    {
        SatCountLimitMode = SatCountLimitMode.Automatic,
        AutoModeInitialSatsCount = 12,
    });
public void SetOutputToLabSat4Realtime(string labSat4IPAddress, RealTimeOutputMode outputMode, IReadOnlyList<SignalType> signals, Quantization quantization = Quantization.OneBit, LabSat4RealtimeOutputOptions? options = null)
Configures the simulation to stream output data directly to a LabSat 4 Real-Time device over Ethernet. The LabSat 4 RT connects via its IP address and supports higher bandwidth signal configurations than earlier LabSat RT models.
ParameterDescription
labSat4IPAddressThe IP address of the LabSat 4 RT device on the network (e.g. "192.168.1.100"). Use FindAvailableLabSat4RealTimeDevices to discover available devices.
outputModeThe timing mode for the real-time output (UserTime, CurrentTime, or NMEATime).
signalsA list of GNSS signal types to include in the real-time output.
quantizationThe bit depth for each signal sample. Default is OneBit.
optionsOptional configuration for real-time output, including satellite count limiting. If null, defaults are used.

Example:

var labSatIPAddress = "192.168.1.100";
var signals = new[] { SignalType.GpsL1CA, SignalType.GpsL2P };

// Basic usage:
scenario.SetOutputToLabSat4Realtime(
    labSatIPAddress,
    RealTimeOutputMode.UserTime,
    signals);

// Full usage with all parameters and all option properties set:
scenario.SetOutputToLabSat4Realtime(
    labSatIPAddress,
    RealTimeOutputMode.UserTime,
    signals,
    Quantization.TwelveBit,
    new LabSat4RealtimeOutputOptions
    {
        SatCountLimitMode = SatCountLimitMode.Automatic,
        AutoModeInitialSatsCount = 12,
    });
public void SetOutputToLabSat4RealtimePlus(string labSat4IPAddress, RealTimeOutputMode outputMode, IReadOnlyList<SignalType> signals, Quantization quantization = Quantization.TwoBit, LabSat4RealtimePlusOutputOptions? options = null)
Configures the simulation to stream output data to a LabSat 4 Real-Time Plus (RT+) device, using an Ethernet connection for the incoming NMEA trajectory data. The LabSat 4 RT+ supports real-time trajectory input, allowing the simulation to follow a live position feed from the connected LabSat.

This overload configures the trajectory input to come from the LabSat device itself over Ethernet. Use the other overload if you need to receive trajectory data over an RS232 serial connection instead.

ParameterDescription
labSat4IPAddressThe IP address of the LabSat 4 RT+ device on the network (e.g. "192.168.1.100"). Use FindAvailableLabSat4RealTimeDevices to discover available devices.
outputModeThe timing mode for the real-time output (UserTime, CurrentTime, or NMEATime).
signalsA list of GNSS signal types to include in the real-time output.
quantizationThe bit depth for each signal sample. Default is TwoBit for RT+ devices.
optionsOptional configuration for RT+ output, including satellite count limiting and buffer mode. If null, defaults are used.

Example:

var labSatIPAddress = "192.168.1.100";
var signals = new[] { SignalType.GpsL1CA, SignalType.GpsL2P };

// Basic usage:
scenario.SetOutputToLabSat4RealtimePlus(
    labSatIPAddress,
    RealTimeOutputMode.UserTime,
    signals);

// Full usage with all parameters and all option properties set:
scenario.SetOutputToLabSat4RealtimePlus(
    labSatIPAddress,
    RealTimeOutputMode.UserTime,
    signals,
    Quantization.TwelveBit,
    new LabSat4RealtimePlusOutputOptions
    {
        BufferMode = BufferMode._40ms,
        SatCountLimitMode = SatCountLimitMode.Automatic,
        AutoModeInitialSatsCount = 12,
    });
public void SetOutputToLabSat4RealtimePlus(string labSat4IPAddress, string comPort, int baudRate, RealTimeOutputMode outputMode, IReadOnlyList<SignalType> signals, Quantization quantization = Quantization.TwoBit, LabSat4RealtimePlusOutputOptions? options = null)
Configures the simulation to stream output data to a LabSat 4 Real-Time Plus (RT+) device, using an RS232 serial connection for the incoming NMEA trajectory data. This overload is used when the trajectory data source is connected via a serial port rather than the LabSat's Ethernet connection.

Use this when the NMEA position data comes from an external device (e.g. a GNSS receiver) connected to the host computer's serial port, and the LabSat 4 RT+ is used purely for signal output.

ParameterDescription
labSat4IPAddressThe IP address of the LabSat 4 RT+ device on the network (e.g. "192.168.1.100").
comPortThe COM port name for the RS232 serial input (e.g. "COM3"). This is the port connected to the device providing live NMEA trajectory data.
baudRateThe baud rate for the RS232 serial connection (e.g. 4800, 9600, 115200). Must match the sending device's configuration.
outputModeThe timing mode for the real-time output (UserTime, CurrentTime, or NMEATime).
signalsA list of GNSS signal types to include in the real-time output.
quantizationThe bit depth for each signal sample. Default is TwoBit for RT+ devices.
optionsOptional configuration for RT+ output, including satellite count limiting and buffer mode. If null, defaults are used.

Example:

var labSatIPAddress = "192.168.1.100";
var signals = new[] { SignalType.GpsL1CA, SignalType.GpsL2P };

// Basic usage:
scenario.SetOutputToLabSat4RealtimePlus(
    labSatIPAddress,
    comPort: "COM3",
    baudRate: 115200,
    RealTimeOutputMode.UserTime,
    signals);

// Full usage with all parameters and all option properties set:
scenario.SetOutputToLabSat4RealtimePlus(
    labSatIPAddress,
    comPort: "COM3",
    baudRate: 115200,
    RealTimeOutputMode.UserTime,
    signals,
    Quantization.TwelveBit,
    new LabSat4RealtimePlusOutputOptions
    {
        BufferMode = BufferMode._40ms,
        SatCountLimitMode = SatCountLimitMode.Automatic,
        AutoModeInitialSatsCount = 12,
    });
public async Task<(string IPAddress, string SerialNumber, bool IsReady)[]> FindAvailableLabSat4RealTimeDevices()
Discovers all LabSat 4 Real-Time devices available on the network. This method sends a network broadcast and waits for responses from any connected LabSat 4 RT or RT+ devices.

Use the returned IP address with SetOutputToLabSat4Realtime or SetOutputToLabSat4RealtimePlus to configure the output target. The IsReady flag indicates whether the device is available and not currently in use by another application.

Returns: An array of tuples, each containing:
  • IPAddress - The network IP address of the discovered device
  • SerialNumber - The unique serial number of the device
  • IsReady - Whether the device is available for use (not currently running a simulation)
Returns an empty array if no devices are found on the network.

Example:

var devices = await scenario.FindAvailableLabSat4RealTimeDevices();
foreach (var device in devices)
{
    Console.WriteLine($"{device.SerialNumber} @ {device.IPAddress} (ready: {device.IsReady})");
}

Timeline

public void AddSatelliteTimelineChange(double elapsedTimeSeconds, ConstellationType constellation, int prn, bool enabled, double attenuationDB = 0)
Schedules a satellite change to be applied during the simulation at the specified elapsed time. When the simulation reaches the elapsed time, the satellite's enabled state and signal attenuation are updated to the supplied values. This works for both file-based and real-time simulations.

Multiple changes can be scheduled at the same elapsed time by calling this method repeatedly. If a change for the same constellation/PRN already exists at the same elapsed time, the existing values are overwritten by the new ones.

This method must be called before StartSimulation. Changes added after the simulation has started will not take effect, because the timeline is snapshotted when the simulation begins. For reactive control of a running real-time simulation (e.g. responding to user input or external events), use SetSatelliteEnabled and SetSatelliteSignalGainDB instead.

ParameterDescription
elapsedTimeSecondsThe elapsed time (in seconds, from the start of the simulation) at which the change should be applied. Values are rounded to the nearest 0.1 s by the timeline service.
constellationThe GNSS constellation that the satellite belongs to (e.g. ConstellationType.GPS).
prnThe PRN (Pseudo-Random Noise) number identifying the satellite within its constellation. Valid range: 1-50.
enabledWhether the satellite should be enabled (transmitting) after this change is applied.
attenuationDBThe signal attenuation in decibels (dB) to apply to the satellite. 0 dB = nominal level, negative values weaken the signal. The value is rounded to the nearest integer internally.

Example:

// Basic usage - 30 seconds in, disable GPS PRN 7 to simulate a satellite outage:
scenario.AddSatelliteTimelineChange(
    elapsedTimeSeconds: 30,
    ConstellationType.GPS,
    prn: 7,
    enabled: false);

// Full usage - 60 seconds in, partially attenuate GPS PRN 12 by 6 dB:
scenario.AddSatelliteTimelineChange(
    elapsedTimeSeconds: 60,
    ConstellationType.GPS,
    prn: 12,
    enabled: true,
    attenuationDB: -6);
public void ClearSatelliteTimeline()
Removes all user-defined satellite changes from the simulation timeline, returning it to its default state (a single entry at elapsed time 0 representing the initial satellite configuration).

Example:

scenario.ClearSatelliteTimeline();

Satellite Control

public Satellite[] GetSatellitesInRealTimeSimulation(ConstellationType constellation)
Retrieves all visible satellites for the specified constellation during a running LabSat Real-Time simulation. Each satellite includes its PRN number, enabled state, and current signal attenuation level.

Important: This method can only be called while a real-time simulation is actively running. Calling it before starting a simulation, during a file-based simulation, or after the simulation has ended will throw a NotSupportedException.

Use this to inspect which satellites are currently visible and their signal levels, for example to identify satellites that could be disabled or attenuated for interference testing.

ParameterDescription
constellationThe GNSS constellation to query (e.g. ConstellationType.GPS, ConstellationType.Galileo, ConstellationType.GLONASS, ConstellationType.BeiDou).
Returns: An array of Satellite objects representing all visible satellites for the specified constellation. Each satellite includes its constellation type, PRN number, enabled/disabled state, and current attenuation in dB.
Throws NotSupportedException: Thrown if a LabSat Real-Time simulation is not currently running.

Example:

var gpsSats = scenario.GetSatellitesInRealTimeSimulation(ConstellationType.GPS);
public void SetSatelliteSignalGainDB(ConstellationType constellation, int prn, double signalGainDB)
Adjusts the signal gain (power level) for a specific satellite during a running LabSat Real-Time simulation. This allows you to simulate signal degradation, obstruction, or interference for individual satellites.

The gain value is applied relative to the original (nominal) signal level. A value of 0 dB means no change. Negative values attenuate the signal (weaker), and the value is rounded to the nearest integer and clamped to the valid range internally.

Important: This method can only be called while a real-time simulation is actively running.

Use this for reactive, real-time control (e.g. responding to user input or external events). For changes that should occur at known points in the simulation, use AddSatelliteTimelineChange instead - timeline changes also work with file-based output.

ParameterDescription
constellationThe GNSS constellation the satellite belongs to (e.g. ConstellationType.GPS).
prnThe PRN (Pseudo-Random Noise) number identifying the satellite. Valid range: 1-50.
signalGainDBThe signal gain adjustment in decibels (dB). 0 dB = original level, negative values = attenuated.
Throws NotSupportedException: Thrown if a LabSat Real-Time simulation is not currently running.

Example:

// Attenuate GPS satellite PRN 5 by 10 dB
scenario.SetSatelliteSignalGainDB(ConstellationType.GPS, prn: 5, signalGainDB: -10);
public void SetSatelliteEnabled(ConstellationType constellation, int prn, bool enabled)
Enables or disables a specific satellite during a running LabSat Real-Time simulation. Disabled satellites are excluded from the simulation, meaning no signal will be generated for them. This is useful for testing receiver behaviour with reduced satellite visibility.

Restriction: Satellites cannot be manually enabled when Automatic is active, as the automatic algorithm manages satellite availability to prevent CPU overload. You can still disable satellites in automatic mode, but enabling them requires switching to None or Manual.

Important: This method can only be called while a real-time simulation is actively running.

Use this for reactive, real-time control (e.g. responding to user input or external events). For changes that should occur at known points in the simulation, use AddSatelliteTimelineChange instead - timeline changes also work with file-based output and are not blocked by Automatic.

ParameterDescription
constellationThe GNSS constellation the satellite belongs to (e.g. ConstellationType.GPS).
prnThe PRN (Pseudo-Random Noise) number identifying the satellite. Valid range: 1-50.
enabledSet to true to enable the satellite, or false to disable it.
Throws NotSupportedException: Thrown if a LabSat Real-Time simulation is not currently running, or if attempting to enable a satellite while Automatic is active.

Example:

// Disable GPS satellite PRN 12
scenario.SetSatelliteEnabled(ConstellationType.GPS, prn: 12, enabled: false);
public bool SetLabSat4ChannelAttenuation(LabSat4Channel channel, int attenuation)
Adjusts the RF output level (signal level in dB, historically referred to as "attenuation") for a LabSat 4 output channel during a running real-time simulation. This is the same control as the up/down buttons on the LabSat 4 front panel and applies to the entire channel rather than to an individual satellite.

Important: A LabSat 4 RT or RT+ simulation must be actively running. Calling this method when no simulation is running, or when the active output is not a LabSat 4 RT/RT+ device, will throw a NotSupportedException.

ParameterDescription
channelThe LabSat 4 output channel to adjust. The channel must be active in the current channel plan.
attenuationThe signal level in dB. Valid range: -69 to +20 (matching the LabSat 4 front panel range). Values outside this range are clamped by the device.
Returns: true if the device accepted the change, false if the underlying replayer rejected it (e.g. the channel is not active).
Throws NotSupportedException: Thrown if a LabSat 4 RT or RT+ simulation is not currently running.

Example:

scenario.SetLabSat4ChannelAttenuation(LabSat4Channel.A, attenuation: 6);

Simulation

public void StartSimulation()
Starts the simulation, beginning the generation of GNSS signal data to the configured output target. This method returns immediately without blocking - the simulation runs asynchronously in the background.

Before calling this method, you must have:

  1. Set a trajectory (e.g. TrajectoryFromStaticPoint, TrajectoryFromRoute, etc.) unless a real-time input source is in use
  2. Configured the output (e.g. SetOutputToLabSatFile, SetOutputToLabSatRealtime, etc.)

After starting the simulation, you can monitor progress in two ways:

  • Call MonitorSimulationProgress to block and receive periodic updates (recommended for console applications)
  • Poll the IsRunning, SimulationPercentComplete, SimulationSecondsFromStart, and SimulationError properties manually
  • Subscribe to the SimulationStatusChanged event for push-style updates (recommended for GUI applications)

This method performs the following sequence internally:
  1. Configures the input parameters based on the selected input mode (SatGen, LabSat, or RS232)
  2. Sets up the active input source for trajectory data
  3. Subscribes to output events for progress, errors, and completion notifications
  4. Downloads any required almanac updates (if auto-almanac mode is enabled)
  5. Starts the output engine, which begins generating signal data

Example:

scenario.StartSimulation();
public void MonitorSimulationProgress(TimeSpan interval, Action? onInterval = null)
Monitors the simulation progress, writing status updates to the console at the specified interval. This is the recommended way to monitor a simulation in a console application. The method returns when the simulation completes, encounters an error, or is stopped via EndSimulation.

The method handles different input modes:

  • User-defined trajectory: Waits up to 90 seconds for the simulation to reach the running state before timing out
  • real-time trajectory input: Displays a waiting message while the simulation is in the ready state, then monitors once data starts flowing

An optional callback action can be provided to execute custom logic at each polling interval (e.g. logging progress, adjusting satellite levels, or checking external conditions).

ParameterDescription
intervalThe time interval between progress updates. For example, TimeSpan.FromSeconds(1) to check every second. Shorter intervals provide more responsive monitoring but consume more CPU.
onIntervalAn optional callback action that is invoked at each polling interval while the simulation is running. Use this to perform custom per-interval logic such as logging SimulationPercentComplete, adjusting satellite signal levels, or checking external stop conditions. Can be null.

Example:

// Basic usage:
scenario.MonitorSimulationProgress(TimeSpan.FromSeconds(1));

// Full usage with a progress callback:
scenario.MonitorSimulationProgress(TimeSpan.FromSeconds(1), () =>
{
    if (scenario.IsRunning)
    {
        Console.Write($"\r{scenario.SimulationPercentComplete:F1}%  underruns: {scenario.BufferUnderrunCount}   ");
    }
});
public void EndSimulation()
Stops the currently running simulation and releases all associated resources. After calling this method, the Scenario instance is disposed and cannot be reused. Create a new Scenario instance to run another simulation.

For file-based simulations, any partially written output file will remain on disk up to the point the simulation was stopped. For real-time simulations, signal output ceases immediately.

Example:

scenario.EndSimulation();
public string GetSimulationSummary()
Gets a formatted summary of the current simulation configuration, including the start time, trajectory type, output device, signals, quantization, attenuation, and elevation mask. This is intended for display in the console output to give the user a clear overview of the simulation parameters before it starts.
Returns: A multi-line formatted string containing the simulation configuration summary.

Example:

Console.WriteLine(scenario.GetSimulationSummary());
public string GetChannelPlan()
Gets the channel plan for the current scenario configuration as a human-readable string. The channel plan shows the actual signals that will be (or are being) simulated, including the maximum quantization, data rate, sample rate, and details for each frequency channel.

SatGen may automatically reduce quantization when the requested signal configuration exceeds the bandwidth constraints of the selected output device. This method reflects any such adjustments.

Returns: A formatted string containing the channel plan information, including max quantization, data rate, sample rate, and a list of all channels with their names, frequencies, and bandwidths.

Example:

Console.WriteLine(scenario.GetChannelPlan());

Enumerations

The following enumerations are used to configure various aspects of the API.

but

ConstellationType

Identifies a GNSS constellation. Used throughout the API when configuring almanacs, querying or modifying satellites at runtime, and scheduling timeline events.
MemberDescription
GpsThe GPS constellation (United States).
GlonassThe GLONASS constellation (Russia).
BeiDouThe BeiDou (BDS) constellation (China).
GalileoThe Galileo constellation (European Union).
NavicThe NavIC (IRNSS) constellation (India).
SbasThe SBAS (Satellite-Based Augmentation System) constellation.

Dynamics

Defines the pre-configured vehicle dynamics profiles available in SatGen. Each profile specifies the maximum speed, acceleration, deceleration, lateral acceleration, and jerk limits for the simulated vehicle.

The dynamics profile controls how the vehicle moves along a route trajectory. For example, a Car profile will limit the vehicle to normal road speeds with moderate cornering forces, while a RaceCar profile allows much higher speeds and lateral forces typical of motorsport testing.

For full control over individual motion parameters, use SetCustomDynamics with a CustomDynamicsOptions instance instead.

MemberDescription
CarStandard car dynamics. Suitable for simulating normal road driving with moderate speeds, comfortable acceleration/braking, and typical cornering forces. This is the most commonly used profile for automotive GNSS receiver testing.
RaceCarRace car dynamics. Simulates high-performance motorsport driving with high top speeds, aggressive acceleration and braking, and high lateral g-forces during cornering. Use this for testing GNSS receivers under extreme dynamic conditions.
TrainTrain dynamics. Simulates railway vehicle motion with constrained lateral movement, gentle acceleration and deceleration profiles, and moderate top speeds. Suitable for rail-based positioning system testing.
PedestrianPedestrian dynamics. Simulates walking-speed movement with very low acceleration limits and low maximum velocity. Suitable for testing personal navigation devices and pedestrian tracking applications.

GravitationalModel

Specifies the gravitational model (altitude datum) used to interpret altitude values when importing trajectories from external sources such as VBOX or NMEA files.
MemberDescription
WGS84WGS84 ellipsoid. Altitudes are interpreted as height above the WGS84 reference ellipsoid.
EGM84EGM84 geoid over WGS84 ellipsoid.
EGM96EGM96 geoid over WGS84 ellipsoid (mean sea level approximation).
EGM2008EGM2008 geoid over WGS84 ellipsoid.
NMEAUse the geoid separation reported in the NMEA file itself.

InputConnectionStatus

Represents the connection status of the external trajectory input source during a real-time simulation. This status is reported by the InputConnectionStatus property and indicates whether the external device providing live NMEA trajectory data is actively sending data.

This enum is only relevant when using a LabSat or RS232 serial input for real-time trajectory data. For simulations using SatGen's built-in trajectory generation (static point, route, KML, NMEA file, etc.), the status will always be None.

MemberDescription
NoneNo external input source is being used, or the input source does not have a connection status. This is the default status for simulations that use SatGen-generated trajectories.
ConnectedThe external input source is connected and actively sending trajectory data to the simulation. The simulation is receiving and processing NMEA position updates from the input device.
DisconnectedThe external input source has stopped sending data. This may indicate a cable disconnection, the sending device has been powered off, or a communication failure. The simulation will continue running but will not receive updated trajectory data until the connection is restored.

LabSat4Channel

Identifies a LabSat 4 RF output channel for runtime configuration calls such as SetLabSat4ChannelAttenuation. The available channels correspond to the physical RF outputs on the LabSat 4 unit; the number of usable channels for a given simulation depends on the signal selection and quantization (see the LabSat 4 channel plan documentation).
MemberDescription
AChannel A.
BChannel B.
CChannel C.

LabSatFileOutputMode

Specifies the LabSat file format to use when generating file-based output with SetOutputToLabSatFile. Each format corresponds to a specific LabSat hardware model and determines the file structure, extension, and supported signal/quantization combinations.

The generated file can be loaded onto the corresponding LabSat device for playback, which will broadcast the simulated GNSS signals via its RF output for testing GNSS receivers.

MemberDescription
LabSat1LabSat 1 file format (.bin). Supports a single GNSS frequency band with 1-bit or 2-bit quantization. Compatible with LabSat 1 hardware for playback.
LabSat2LabSat 2 file format (.ls2). Supports a single GNSS frequency band with 1-bit or 2-bit quantization. Compatible with LabSat 2 hardware for playback.
LabSat3LabSat 3 file format (.ls3). Supports up to three GNSS frequency bands with 1-bit or 2-bit quantization. Compatible with LabSat 3 hardware for playback. This is the most commonly used file format.
LabSat4LabSat 4 file format (.LS4). Supports the full LabSat 4 channel and signal capabilities for offline recording. Compatible with LabSat 4 hardware for playback.
LabSat3WBLabSat 3 Wideband file format (.LS3W). Supports wideband signal recording with up to 3-bit quantization and higher bandwidth per channel. Compatible with LabSat 3 Wideband hardware for playback. Required for wideband signals such as GPS L5 or Galileo E5.

NmeaTrajectoryOptions

Controls how speed information is extracted when interpreting an NMEA trajectory file.
MemberDescription
NoneDefault behaviour. Speed is derived from successive position fixes.
UseRmcVtgGroundSpeedRead the ground speed from RMC or VTG sentences (where present) and use that speed instead of the position-derived value. This typically reduces velocity noise in the simulated trajectory.

OutputDataRate

Specifies the output data rate in Hz (samples per second) for trajectory generation. This determines how many position updates per second are calculated when generating a trajectory from a script. Higher data rates produce smoother trajectories but require more processing.

Used with OutputDataRate when creating trajectories via TrajectoryFromScript.

MemberDescription
_1Hz1 position update per second. Lowest resolution, suitable for slow-moving or static scenarios.
_2Hz2 position updates per second.
_4Hz4 position updates per second.
_5Hz5 position updates per second.
_10Hz10 position updates per second. Default rate - provides a good balance between resolution and performance.
_20Hz20 position updates per second. Suitable for moderate-speed vehicle testing.
_25Hz25 position updates per second.
_50Hz50 position updates per second. Suitable for high-speed vehicle testing with fine trajectory detail.
_100Hz100 position updates per second. Highest resolution, suitable for high-dynamics motorsport or aerospace scenarios.

Quantization

Specifies the quantization level (bit depth) for the in-phase (I) and quadrature (Q) components of each simulated GNSS signal sample. Higher quantization provides a more accurate representation of the analogue signal but increases the data rate and may limit the number of simultaneous signals or constellations.

The choice of quantization depends on the target LabSat hardware and the desired signal fidelity. Higher bit depths produce more accurate signals but increase the data rate, which may limit the number of simultaneous signals or constellations that can be simulated:

  • OneBit - Lowest fidelity, but allows the maximum number of simultaneous signals
  • TwoBit - Standard quality, recommended for most testing scenarios
  • ThreeBit - Enhanced quality for LabSat 3 Wideband devices
  • FourBit to TwelveBit - High-fidelity modes for LabSat 4 devices

MemberDescription
OneBit1-bit quantization. Each sample is represented by a single bit indicating positive or negative.

For LabSat 2 and LabSat 3: 1 = value is greater than 0.0, 0 = value is zero or negative.

For LabSat 3 Wideband: 0 = value is greater than 0.0, 1 = value is zero or negative (inverted logic).

Provides the lowest data rate, allowing the maximum number of simultaneous signals. Use 1-bit quantization for multi-frequency/multi-constellation output on LabSat RT devices.

TwoBit2-bit quantization. Each sample is represented by 2 bits providing sign and magnitude information.

For LabSat 2 and LabSat 3: Uses "Unsigned Binary" format where the MSB represents the sign (1 = positive, 0 = zero/negative) and the LSB represents the magnitude relative to the signal range centre.

For LabSat 3 Wideband: Uses "Two's Complement" format where the MSB represents the sign (0 = positive, 1 = zero/negative) and the LSB represents the magnitude.

Recommended for single-frequency output on LabSat RT devices. Default for LabSat 4 RT+ devices.

ThreeBit3-bit quantization. Each sample uses 3 bits in Two's Complement format (LabSat 3 Wideband only). The MSB represents the sign (0 = positive, 1 = zero/negative) and the two LSBs represent the magnitude. Provides improved signal fidelity over 2-bit for wideband signal simulations.
FourBit4-bit quantization. Available on LabSat 4 devices. Provides enhanced signal resolution with 16 discrete amplitude levels per sample, enabling more accurate signal representation for receiver testing.
EightBit8-bit quantization. Available on LabSat 4 devices. Provides high-fidelity signal representation with 256 discrete amplitude levels per sample. Suitable for advanced receiver testing requiring precise signal level control and realistic noise floor modelling.
TwelveBit12-bit quantization. Available on LabSat 4 devices. Provides the highest signal fidelity with 4096 discrete amplitude levels per sample. Use this for laboratory-grade testing where maximum signal accuracy is required, at the cost of the highest data rate.

RealTimeOutputMode

Specifies the time source used for the simulated GNSS signals during a real-time output simulation. This determines how the satellite positions and signal timing are calculated relative to time.

The time mode is specified when configuring a real-time output target using SetOutputToLabSatRealtime, SetOutputToLabSat4Realtime, or SetOutputToLabSat4RealtimePlus.

MemberDescription
UserTimeUses the user-defined simulation start time (specified in the Scenario constructor) as the time reference for satellite positions and signal timing. The simulation runs in real-time from this specified start point. This is the most common mode for controlled, repeatable testing.
CurrentTimeUses the current system clock (real-world wall-clock time) as the time reference. Satellite positions are calculated based on the actual current time, producing signals that match what a real receiver would see at this moment. Useful for live testing where time-accurate satellite positions are needed.
NMEATimeUses the user-defined simulation date combined with the time extracted from the incoming NMEA data stream. The date comes from the scenario's start time, but the time-of-day advances based on the NMEA sentences received from the external input source. This mode is only applicable when using a LabSat or RS232 external input source for trajectory data.

RoutingMode

Selects how a route is constructed between waypoints when generating a trajectory via TrajectoryFromRoute.
MemberDescription
StraightLineA direct, point-to-point straight line between two waypoints.
RoadA route that follows mapped roads between waypoints.
RailA route that follows mapped railway lines between waypoints.
WalkingA route that follows mapped walking paths between waypoints.
CustomA custom route defined manually by an explicit set of positions.

SatCountLimitMode

Specifies the satellite count limiting strategy used during real-time simulations to manage CPU load. Simulating too many satellites simultaneously can overwhelm the host computer's processing capacity, causing buffer underruns (gaps in the output signal). This enum controls how the system responds.

Configure this via SatCountLimitMode when setting up a real-time output with SetOutputToLabSatRealtime, SetOutputToLabSat4Realtime, or SetOutputToLabSat4RealtimePlus.

MemberDescription
NoneNo limits are imposed on the number of simulated satellites. All visible satellites will be simulated regardless of CPU load. Use this only when you are confident that the host computer has sufficient processing power, or when the full satellite constellation is required for testing.
AutomaticThe system automatically manages the satellite count to prevent CPU overload. It starts with the initial count (configured via AutoModeInitialSatsCount) and automatically reduces the number of simulated satellites each time a buffer underrun occurs. This is the recommended mode for most real-time simulations as it self-tunes to the host computer's capability.
ManualThe user manually selects which satellites are simulated using SetSatelliteEnabled. No automatic adjustment is performed. This gives full control over the satellite constellation but requires the user to manage CPU load manually by enabling/disabling individual satellites.

SignalType

Identifies a GNSS signal that can be simulated. The set of values exposed here matches the signals selectable in the SatGen 4 desktop application.

Each output method (SetOutputToLabSatFile, SetOutputToLabSatRealtime, SetOutputToLabSat4Realtime, SetOutputToLabSat4RealtimePlus) takes a list of SignalType values to determine which signals are generated. Each enabled signal adds CPU load, so only enable the signals required by the receiver under test.

MemberDescription
GpsL1CAThe GPS L1 C/A civilian signal.
GpsL1CThe GPS L1 C civilian signal.
GpsL1PThe GPS L1 P military signal (using the public unencrypted P-Code).
GpsL1MThe GPS L1 M military signal (SatGen generates just noise with spectral characteristics matching the real L1M signal).
GpsL2CThe GPS L2 C civilian signal.
GpsL2PThe GPS L2 P military signal (using the public unencrypted P-Code).
GpsL2MThe GPS L2 M military signal (SatGen generates just noise with spectral characteristics matching the real L2M signal).
GpsL5The GPS L5 (I+Q) civilian signal.
GlonassL1OFThe GLONASS L1 OF civilian signal (FDMA).
GlonassL2OFThe GLONASS L2 OF civilian signal (FDMA).
BeiDouB1IThe BeiDou B1I civilian signal.
BeiDouB2IThe BeiDou B2I civilian signal.
BeiDouB3IThe BeiDou B3I civilian signal.
BeiDouB1CThe BeiDou B1C civilian signal (data + pilot).
BeiDouB2aThe BeiDou B2a civilian signal (data + pilot).
BeiDouB2bIThe BeiDou B2b I civilian signal.
GalileoE1BCThe composite Galileo E1B/E1C (data + pilot) civilian signal.
GalileoE5aThe Galileo E5a civilian signal (data + pilot).
GalileoE5bThe Galileo E5b civilian signal (data + pilot).
GalileoE6BCThe Galileo E6B/E6C (data + pilot) commercial signal.
NavicL5SPSThe NavIC L5 SPS civilian signal.
NavicSSPSThe NavIC S-band SPS civilian signal.
SbasL1The SBAS L1 civilian signal.

SimulationStatus

Represents the lifecycle status of a simulation, reported by the CurrentStatus property and carried in SimulationStatusEventArgs when the SimulationStatusChanged event fires.
MemberDescription
RunningThe simulation has not yet been started, or is currently running. SimulationStatusChanged fires with this status periodically as the simulation progresses; consumers typically use these events to update progress displays.
CompletedThe simulation finished successfully and produced its full output. When the SimulationStatusChanged event fires with this status, SimulationPercentComplete is guaranteed to be exactly 100.0. After this event fires the consumer should unsubscribe and call EndSimulation. This status will not be reported if the simulation was stopped manually via EndSimulation before reaching the natural end.
FailedThe simulation stopped due to an error. The error message is provided in ErrorMessage (and also in the SimulationError property). After this event fires the simulation cannot continue; the consumer should unsubscribe and call EndSimulation.

Parameter Classes

These classes are used to provide optional configuration when calling API methods.

BaseLabSatOutputOptions

Abstract base class for all LabSat output configuration options. This class defines the trajectory input source settings that are common to all output modes (file and real-time).

The input mode determines where the simulation receives its trajectory data from:

  • SatGen (default) - Trajectory is generated by SatGen from a static point, route, or imported file
  • LabSat - Trajectory comes from the LabSat device itself over Ethernet (RT+ only)
  • RS232 - Trajectory comes from an external GNSS receiver via RS232 serial port (RT+ only)

BaseLabSatRealtimeOutputOptions

Inherits from: BaseLabSatOutputOptions

Abstract base class for all LabSat output configuration options. Extends the base output options with real-time-specific settings for managing satellite count limits to prevent CPU overload during live signal generation.

Real-time simulations are more CPU-intensive than file-based output because the signal data must be generated and streamed at the exact rate the LabSat hardware requires. If the host computer cannot keep up, buffer underruns occur, causing brief gaps in the output signal.

PropertyTypeDescription
SatCountLimitModeSatCountLimitModeGets or sets the satellite count limiting strategy used to manage CPU load during the simulation.

  • Automatic (default) - Automatically reduces satellite count on buffer underruns
  • None - No limits; all visible satellites are simulated
  • Manual - User manually controls which satellites are enabled

AutoModeInitialSatsCountintGets or sets the initial maximum number of satellites to simulate when SatCountLimitMode is set to Automatic. The actual number of satellites simulated will be reduced each time the host machine is unable to keep up (i.e. on each buffer underrun).

Set this to 999 (default) to start with no initial limit, allowing the automatic algorithm to find the optimal satellite count for your hardware. Set to a lower value (e.g. 12) to start with a conservative limit if you know your hardware has limited processing capacity.

Default value: 999 (effectively unlimited - all visible satellites are simulated initially).

CustomDynamicsOptions

Defines custom vehicle dynamics parameters for use with SetCustomDynamics. These parameters control the maximum speed, acceleration, deceleration, lateral forces, and jerk limits of the simulated vehicle when following a route trajectory.

Use this when the pre-defined dynamics profiles (Dynamics) do not match your specific testing requirements. All nine parameters must be provided to fully define the vehicle's motion capabilities.

Units:

  • Velocity: kilometres per hour (km/h)
  • Acceleration: g-force (g), where 1g = 9.81 m/s^2
  • Jerk: g per second (g/s) - the rate of change of acceleration

public CustomDynamicsOptions(double horizontalVelocity, double longitudinalAcceleration, double longitudinalDeceleration, double lateralAcceleration, double verticalAcceleration, double longitudinalAccelerationJerk, double longitudinalDecelerationJerk, double lateralJerk, double verticalJerk)
Creates a new custom dynamics configuration with the specified motion parameters. All parameters are required to fully define the vehicle's motion capabilities.
ParameterDescription
horizontalVelocityThe maximum horizontal velocity in kilometres per hour (km/h). This is the top speed the simulated vehicle can reach on a straight road.
longitudinalAccelerationThe maximum forward acceleration in g-force units (g). Controls how quickly the vehicle can speed up.
longitudinalDecelerationThe maximum braking deceleration in g-force units (g). Controls how quickly the vehicle can slow down.
lateralAccelerationThe maximum lateral (cornering) acceleration in g-force units (g). Controls how aggressively the vehicle can corner.
verticalAccelerationThe maximum vertical acceleration in g-force units (g). Controls altitude change rate for 3D trajectories.
longitudinalAccelerationJerkThe rate of change of forward acceleration in g per second (g/s). Controls the smoothness of acceleration onset.
longitudinalDecelerationJerkThe rate of change of braking deceleration in g per second (g/s). Controls the smoothness of braking onset.
lateralJerkThe rate of change of lateral acceleration in g per second (g/s). Controls the smoothness of cornering transitions.
verticalJerkThe rate of change of vertical acceleration in g per second (g/s). Controls the smoothness of altitude change transitions.

KMLTrajectoryOptions

Configuration options for creating a trajectory from a KML (Keyhole Markup Language) file via TrajectoryFromKMLFile. KML files are commonly created using Google Earth or other mapping tools to define geographic paths and routes.

These options control how the KML data is interpreted and processed into a SatGen trajectory, including route repetition, height interpretation, vehicle speed, and cornering behaviour.

public KMLTrajectoryOptions()
Creates a new KML trajectory options instance with default settings (no repeat, height as altitude, 100 km/h target speed, 10m apex distance).
PropertyTypeDescription
RepeatCountintGets or sets the number of times the KML route should be repeated after the initial traversal. A value of 0 means the route is driven once (no repeats). A value of 1 means the route is driven twice, etc.

Useful for creating longer simulations from a short route, for example driving around a test track multiple times. The vehicle will seamlessly transition from the end of the route back to the start.

Default value: 0 (no repeats - the route is driven once).
UseHeightAsStopTimeboolGets or sets a value indicating whether the altitude/height value for each KML coordinate should be interpreted as a stop time (delay in seconds) at that position rather than an actual altitude.

When set to true, the height field of each KML coordinate defines how long (in seconds) the simulated vehicle should remain stationary at that point. This is useful for creating trajectories with stop-and-go behaviour (e.g. simulating traffic lights or parking manoeuvres).

When set to false (default), the height value is used as the actual altitude above the ellipsoid.

Default value: false (height values represent altitude in metres).
TargetSpeedKilometersPerHourdoubleGets or sets the target speed in kilometres per hour (km/h) for the simulated vehicle along the KML route. The actual speed achieved depends on the configured dynamics profile, which imposes acceleration, deceleration, and cornering limits. Default value: 100 km/h.
ApexDistanceLimitMetresdoubleGets or sets the maximum allowed distance in metres between each route position and the apex of the curve when the vehicle rounds a corner. Smaller values produce tighter corners; larger values produce smoother, wider curves. See ApexDistanceLimitMetres for more detail. Default value: 10 metres.

LabSat4RealtimeOutputOptions

Inherits from: BaseLabSatRealtimeOutputOptions

Configuration options for LabSat 4 Real-Time output via SetOutputToLabSat4Realtime. The LabSat 4 RT connects over Ethernet and supports higher bandwidth configurations than earlier models.

This class inherits all real-time output settings from BaseLabSatRealtimeOutputOptions, including satellite count limiting options. It exists as a dedicated type to allow LabSat 4-specific options to be added in future API versions.

public LabSat4RealtimeOutputOptions()
Creates a new LabSat 4 real-time output options instance with default settings inherited from BaseLabSatRealtimeOutputOptions (automatic satellite count limiting enabled).

LabSat4RealtimePlusOutputOptions

Inherits from: LabSat4RealtimeOutputOptions

Configuration options for LabSat 4 Real-Time Plus (RT+) output via SetOutputToLabSat4RealtimePlus. The LabSat 4 RT+ extends the standard RT with support for real-time trajectory input, allowing the simulation to follow a live position feed from an external source (LabSat Ethernet or RS232 serial).

Inherits all LabSat 4 RT options from LabSat4RealtimeOutputOptions (and satellite count limiting from LabSatRealtimeOutputOptions in turn), and adds a BufferMode setting that controls the output buffering strategy.

public LabSat4RealtimePlusOutputOptions()
Creates a new LabSat 4 RT+ output options instance with default settings (automatic satellite count limiting, 40ms buffer mode).
PropertyTypeDescription
BufferModeBufferModeGets or sets the output buffer mode for the LabSat 4 RT+ device. The buffer mode controls the size of the signal data buffer used between the simulation engine and the LabSat hardware.

A larger buffer provides more resilience against brief CPU load spikes but introduces additional latency between trajectory changes and the corresponding signal output. A smaller buffer reduces latency but is more sensitive to CPU load variations.

Default value: _40ms (40 milliseconds of buffered data).

LabSatFileOutputOptions

Inherits from: BaseLabSatOutputOptions

Configuration options for file-based LabSat output via SetOutputToLabSatFile.

This class currently inherits all settings from BaseLabSatOutputOptions without adding any file-specific options. It exists as a dedicated type to allow file-specific options to be added in future API versions without breaking the existing method signatures.

public LabSatFileOutputOptions()
Creates a new file output options instance with default settings.

LabSatRealtimeOutputOptions

Inherits from: BaseLabSatRealtimeOutputOptions

Configuration options for LabSat Real-Time output via SetOutputToLabSatRealtime. Extends the base output options with real-time-specific settings for managing satellite count limits to prevent CPU overload during live signal generation.

This class inherits all real-time output settings from BaseLabSatRealtimeOutputOptions, including satellite count limiting options. It exists as a dedicated type to allow LabSat-specific options to be added in future API versions.

public LabSatRealtimeOutputOptions()
Creates a new LabSat real-time output options instance with default settings inherited from BaseLabSatRealtimeOutputOptions (automatic satellite count limiting enabled).

NMEAFileTrajectoryOptions

Configuration options for creating a trajectory from an NMEA log file via TrajectoryFromNMEAFile. NMEA files contain standardised position and velocity sentences logged from a real GNSS receiver.

These options control how the NMEA data is interpreted, including the altitude datum (gravitational model) and which NMEA sentence types are used for speed information.

public NMEAFileTrajectoryOptions()
Creates a new NMEA file trajectory options instance with default settings (WGS84 gravitational model, use RMC/VTG ground speed).
PropertyTypeDescription
GravitationalModelGravitationalModelGets or sets the gravitational model (altitude datum) used to interpret altitude values from the NMEA data.

  • GravitationalModel.WGS84 - Treats altitude as height above the WGS84 ellipsoid (most common for raw GNSS data)
  • GravitationalModel.EGM96 - Treats altitude as height above the EGM96 geoid (mean sea level approximation)
Choose the model that matches how the altitude was recorded in the NMEA file. Most GNSS receivers output ellipsoidal height in the GGA sentence, which corresponds to WGS84.

Default value: WGS84 (WGS84 ellipsoid height).
OptionsNmeaTrajectoryOptionsGets or sets the NMEA trajectory processing options, which control how speed and course information is extracted from the NMEA sentences.

The default option (NmeaTrajectoryOptions.UseRmcVtgGroundSpeed) uses the ground speed from RMC (Recommended Minimum) and VTG (Course Over Ground and Ground Speed) sentences, which is the most reliable speed source for most GNSS receivers.

Default value: UseRmcVtgGroundSpeed.

RouteWaypoint

Defines a single waypoint along a route trajectory, including its geographic position, target speed, and cornering behaviour. Waypoints are used with TrajectoryFromRoute to define a multi-point route that the simulation engine will follow.

Each waypoint specifies a location (latitude, longitude, altitude) and optional driving parameters that control how the simulated vehicle approaches and rounds the corner at this point:

  • TargetSpeedKilometersPerHour - The desired speed when approaching this waypoint
  • ApexDistanceLimitMetres - How tightly the vehicle should corner at this point

public RouteWaypoint(double latitudeDecDegrees, double longitudeDecDegrees, double altitudeMetres)
Creates a new route waypoint at the specified geographic position. The target speed defaults to 100 km/h and the apex distance limit defaults to 10 metres.
ParameterDescription
latitudeDecDegreesThe latitude of the waypoint in decimal degrees (e.g. 51.5074 for London). Valid range: -90.0 to 90.0.
longitudeDecDegreesThe longitude of the waypoint in decimal degrees (e.g. -0.1278 for London). Valid range: -180.0 to 180.0.
altitudeMetresThe altitude of the waypoint above the WGS84 ellipsoid in metres (e.g. 0.0 for sea level).
PropertyTypeDescription
TargetSpeedKilometersPerHourdoubleGets or sets the target speed in kilometres per hour (km/h) that the simulated vehicle should aim to reach when travelling towards this waypoint. The actual speed achieved depends on the configured dynamics profile (SetDynamics or SetCustomDynamics), which imposes acceleration and deceleration limits. Default value: 100 km/h.
ApexDistanceLimitMetresdoubleGets or sets the maximum allowed distance in metres between this waypoint and the apex of the curve when the simulated vehicle rounds the corner at this point. A smaller value produces tighter corners (closer to the waypoint) while a larger value allows the vehicle to take a wider, smoother line.

This parameter controls the trade-off between route accuracy (staying close to the defined waypoints) and driving realism (smooth, natural cornering). For sharp turns at intersections, use a smaller value (e.g. 5m). For highway curves, a larger value (e.g. 50m) produces more natural results.

Default value: 10 metres.

Satellite

Represents a single GNSS satellite as observed during a running real-time simulation. This class provides read-only information about the satellite's identity, enabled state, and current signal attenuation.

Instances of this class are returned by GetSatellitesInRealTimeSimulation and represent a snapshot of the satellite's state at the time of the call. The satellite's enabled state can be modified using SetSatelliteEnabled, and its signal gain can be adjusted using SetSatelliteSignalGainDB.

PropertyTypeDescription
ConstellationConstellationTypeGets the GNSS constellation that this satellite belongs to (e.g. GPS, Galileo, GLONASS, BeiDou, QZSS, NavIC/IRNSS, SBAS).
PrnintGets the PRN (Pseudo-Random Noise) number that uniquely identifies this satellite within its constellation.

For GPS, this is the SVN/PRN number (1-32). For GLONASS, this is the slot number. For Galileo and BeiDou, this is the satellite vehicle number. Valid range: 1-50.

EnabledboolGets a value indicating whether this satellite is currently enabled in the simulation. Enabled satellites contribute GNSS signals to the output; disabled satellites are excluded.

Use SetSatelliteEnabled to change this value during a running simulation.

AttenuationdoubleGets the current signal attenuation level of this satellite in decibels (dB). A value of 0 dB represents the nominal (full-strength) signal level. Negative values indicate the signal has been attenuated (weakened).

Use SetSatelliteSignalGainDB to adjust this value during a running simulation.

ScenarioParams

Defines the core configuration parameters for a SatGen simulation scenario. This class encapsulates the essential settings that are applied when creating a new Scenario instance, including the simulation start time, signal attenuation level, and satellite elevation mask.

Note: This class is from an earlier API version. The current Scenario constructor accepts these parameters directly rather than through this class.

public ScenarioParams(DateTime startUTCDateTime)
Creates a new scenario parameters instance with the specified simulation start time. The attenuation and elevation mask will use their default values unless explicitly set.
ParameterDescription
startUTCDateTimeThe UTC date and time at which the simulation should begin. This determines the satellite constellation positions via almanac data. Sub-second precision will be truncated when applied to the scenario.
PropertyTypeDescription
AttenuationDBdoubleGets or sets the global signal attenuation level in decibels (dB), which adds artificial noise to the simulated GNSS signals to model real-world signal degradation.

A value of 0.0 disables attenuation entirely (clean signal). More negative values apply stronger attenuation, producing a weaker, noisier signal that better represents real-world conditions.

Valid range: -15.0 to 0.0 dB. Default value: -3.0 dB (provides a realistic noise floor for most testing scenarios).
ElevationMaskDegdoubleGets or sets the elevation mask angle in degrees. Satellites below this angle relative to the horizon at the simulated position will be excluded from the simulation.

Low-elevation satellites typically have weaker, more distorted signals due to longer atmospheric path lengths. Setting an appropriate elevation mask improves simulation realism by excluding satellites that a real receiver would struggle to track.

Valid range: -90 to 90 degrees. Default value: 5 degrees (excludes satellites within 5 degrees of the horizon).

ScriptTrajectoryOptions

Configuration options for creating a trajectory from a SatGen script file via TrajectoryFromScript.

Scripts define complex trajectories using the SatGen scripting language, which supports commands for straight-line motion, turns, altitude changes, and speed profiles. This options class allows you to configure how the trajectory is generated from the parsed script.

public ScriptTrajectoryOptions()
Creates a new script trajectory options instance with default settings (10 Hz output data rate).
PropertyTypeDescription
OutputDataRateOutputDataRateGets or sets the output data rate for the generated trajectory. This determines how many position samples per second are calculated from the script commands. Higher rates produce smoother trajectories with finer time resolution, but require more processing.

For most testing scenarios, the default of 10 Hz provides sufficient resolution. Increase to 50 Hz or 100 Hz for high-dynamics scenarios (e.g. motorsport or aerospace) where sub-100ms position changes are significant.

Default value: _10Hz (10 position samples per second).

SimulationStatusEventArgs

Inherits from: EventArgs

Event arguments carried by the SimulationStatusChanged event. Provides a snapshot of the simulation's progress and lifecycle status at the moment the event was raised.

The same event args type is used for all status transitions; the Status property indicates which transition occurred:

  • Running - fires periodically as the simulation progresses.
  • Completed - fires once when the simulation finishes naturally; SimulationPercentComplete is guaranteed to be exactly 100.0.
  • Failed - fires once when an error stops the simulation; ErrorMessage contains a description of the error.

PropertyTypeDescription
StatusSimulationStatusThe current lifecycle status of the simulation at the moment the event was raised.
SimulationTimeFromStartTimeSpanHow far the simulation has progressed from its start time, measured in simulated (not wall-clock) time. For file-based simulations this can advance faster than real time.
SimulatedDateTimeDateTimeThe UTC date/time currently being simulated. Equivalent to SimulationStartTime + SimulationTimeFromStart.
SimulationPercentCompletedoubleCompletion percentage of the simulation, from 0.0 to 100.0. When Status is Completed this value is exactly 100.0; for Failed it carries the last known progress at the time of error.
ErrorMessagestringA human-readable description of the error that stopped the simulation, populated only when Status is Failed. For other statuses this is Empty.

Complete Example

Below is a complete working example demonstrating a full integration.


// ===================================================================================================
// SatGen 4 API Code Sample
// ===================================================================================================
// A starting point for integrating the SatGen Scenario API into your own application. The code below
// demonstrates the minimal steps required to configure and run a GNSS simulation: the active calls
// produce a static-point trajectory streamed in real time to a LabSat 4, but every section can be
// swapped for one of the alternatives described in the comments.
//
// For the full list of methods, parameters, and supported values, see API-Documentation.html
// (generated alongside this sample on build).
//
// Prerequisites:
//   - SatGen 4 must be installed (the API DLLs are loaded from the SatGen 4 install directory)
//   - A valid SatGen 4 licence must be available (hardware dongle)
//   - For real-time output only: a LabSat Real-Time or LabSat 4 device connected and accessible
//     (file output does not require any LabSat hardware)
//
// Startup parameters (optional):
//   SatGen4APICodeSamples.exe [LabSat4IPAddress] [SimulationDateTime]
//   Example: SatGen4APICodeSamples.exe 192.168.1.100 "01 Jan 2026 12:00:00"
// ===================================================================================================

using SatGen.ScenarioAPI;

internal static class Program
{
	private static void Main(string[] args)
	{
		// -- CONFIGURATION -----------------------------------------------------------------------
		// Default LabSat 4 IP address - change this to match your device, or pass as a startup parameter.
		var labSatIPAddress = "192.168.1.100";

		// Simulation start date/time in UTC. Satellite constellation positions are calculated from this
		// time, so use a recent date for realistic satellite geometry. Sub-second precision is discarded.
		var simulationDateTime = new DateTime(2026, 01, 01, 12, 00, 00);

		// Allow overriding configuration via startup parameters
		if (args.Length >= 1)
		{
			labSatIPAddress = args[0];
		}

		if (args.Length >= 2 && DateTime.TryParse(args[1], out var startupParamSimulationDateTime))
		{
			simulationDateTime = startupParamSimulationDateTime;
		}

		try
		{
			// -- SCENARIO CREATION ---------------------------------------------------------------
			// The Scenario is the root object representing a simulation run. Its constructor takes
			// the simulation start time and an optional attenuationDB value, which adds artificial
			// noise to the output signal (equivalent to the 'Attenuation' box on the Output tab in
			// SatGen 4; typical values range from -10 to 0 dB).
			using var scenario = new Scenario(simulationDateTime, attenuationDB: -3);

			// -- ALMANACS (optional) -------------------------------------------------------------
			// By default the API downloads the latest almanac for each constellation from the
			// Racelogic almanac server. If you need to reproduce a known scenario or work offline,
			// a local almanac file can be supplied per constellation via ManualAlmanacFile().

			// -- SIGNALS -------------------------------------------------------------------------
			// Defines which GNSS signals are simulated. Each enabled signal adds CPU load, so only
			// enable what your receiver under test requires. See API-Documentation.html (SignalType)
			// for the full list of supported signals across all constellations.
			var signals = new[]
			{
				SignalType.GpsL1CA,
				SignalType.GpsL2C,
            };

			// -- DYNAMICS (optional) -------------------------------------------------------------
			// The dynamics profile constrains how the simulated vehicle accelerates, decelerates,
			// and corners. It only applies to route-style trajectories (waypoints, KML, etc.);
			// imported trajectories (NMEA, VBOX, CSV) carry their own motion data.
			//
			// SetDynamics() selects a built-in preset (Car, RaceCar, Train, Pedestrian, ...) and
			// SetCustomDynamics() lets you specify exact velocity, acceleration, and jerk limits.

			// -- TRAJECTORY ----------------------------------------------------------------------
			// Defines where and how the simulated receiver moves. Many trajectory types are
			// available - static point, route waypoints, KML, NMEA, VBOX, CSV, and full
			// .sgen scenarios - each exposed as a TrajectoryFrom... method. See API-Documentation.html
			// for the full list and per-method options.
			scenario.TrajectoryFromStaticPoint(
				latitudeDecDegrees: 51.9831552,
				longitudeDecDegrees: -0.999424,
				altitudeMetres: 100,
				durationInSeconds: 600);

            // -- DEVICE DISCOVERY (optional) -----------------------------------------------------
            // FindAvailableLabSat4RealTimeDevices() returns the LabSat 4 devices discovered on the
            // network, including each device's IP address, serial number, and ready state. Useful
            // when the IP address is not known in advance.

            // -- OUTPUT --------------------------------------------------------------------------
            // Configures where the simulated signals are sent. Real-time targets (LabSat 1/2/3,
            // LabSat 4, LabSat 4 RT+) and file outputs (LS2 / LS3 / LS3W / LS4) are all supported,
            // each exposed as a SetOutputTo... method. See API-Documentation.html for the full list.
            //
            // Quantization controls signal fidelity: higher bit depths produce more accurate signals
            // but increase the data rate, which may limit the number of simultaneous signals.
            //
            // SatCountLimitMode controls CPU load management for real-time outputs. Automatic
            // (recommended) starts with the maximum number of satellites and reduces if the CPU is
            // overloaded; the alternatives let you simulate all visible satellites or manage them
            // manually via SetSatelliteEnabled().
            scenario.SetOutputToLabSat4Realtime(
                labSatIPAddress,
                RealTimeOutputMode.UserTime,
                signals,
                Quantization.TwelveBit,
                new LabSat4RealtimeOutputOptions { SatCountLimitMode = SatCountLimitMode.Automatic });

            // -- TIMELINE EVENTS (optional) ------------------------------------------------------
            // Schedule satellite changes to be applied automatically as the simulation progresses.
            // Each AddSatelliteTimelineChange() call queues a change at a specified elapsed time;
            // when the simulation reaches that time, the satellite's enabled state and attenuation
            // are updated. Useful for repeatable test cases such as driving through a tunnel,
            // simulating a satellite outage, or staging a gradual signal degradation.
            // ClearSatelliteTimeline() removes every previously scheduled change.
            //
            // IMPORTANT: schedule changes BEFORE calling StartSimulation. The timeline is snapshotted
            // when the simulation begins; subsequent additions will not take effect on the running run.

            // -- INSPECT THE CONFIGURATION (optional) --------------------------------------------
            // Before starting the simulation, you can inspect what the engine has decided to do:
            // GetSimulationSummary() reports the start time, trajectory, output, and signals;
            // GetChannelPlan() reports the RF channels, sample rate, bandwidth, and quantization.

            // -- SIMULATION ----------------------------------------------------------------------
            // Starts the simulation. The API will print the configuration summary, almanac status,
            // and channel plan to the console before the simulation begins.
            scenario.StartSimulation();

			// Track the simulation start time so we can display the total duration when it finishes
			var simulationStartTime = DateTime.Now;

			// MonitorSimulationProgress blocks until the simulation ends (either the trajectory
			// duration elapses, or EndSimulation() is called from another thread). The optional
			// callback runs on each interval tick - useful for printing progress or reacting to
			// simulation state.
			scenario.MonitorSimulationProgress(TimeSpan.FromSeconds(1),
				() =>
				{
					if (scenario.IsRunning)
					{
						// Format elapsed time and build a progress bar for visual feedback
						var elapsed = TimeSpan.FromSeconds(scenario.SimulationSecondsFromStart);
						var percent = scenario.SimulationPercentComplete;
						int barWidth = 20;
						int filled = (int)(percent / 100 * barWidth);
						string bar = new string('#', filled) + new string('-', barWidth - filled);

						Console.Write($"\r  [{bar}] {percent,5:F1}%   Elapsed: {elapsed:hh\\:mm\\:ss}   Underruns: {scenario.BufferUnderrunCount}   ");

						// -- RUNTIME CONTROL (optional) -----------------------------------------
						// While a real-time simulation is running, several methods can adjust the
						// output and constellation on the fly:
						//   - GetSatellitesInRealTimeSimulation(), SetSatelliteEnabled(), and
						//     SetSatelliteSignalGainDB() inspect and control individual satellites
						//     (useful for stress-testing receiver behaviour under degraded
						//     constellations).
						//   - SetLabSat4ChannelAttenuation() adjusts the RF output level of an
						//     entire LabSat 4 channel - the API equivalent of the LabSat 4 front-
						//     panel up/down buttons.
						//
						// IMPORTANT: this callback fires on every interval tick. Calling any of
						// these methods directly here will re-apply the change on every tick,
						// which is rarely what you want. Guard one-shot changes with a flag or an
						// elapsed-time check - for example, apply the change the first time
						// scenario.SimulationSecondsFromStart crosses a threshold.
						//
						// IMPORTANT: these calls are only valid for real-time outputs. On a file
						// output they throw.
						//
						// For changes that should happen at fixed times, the TIMELINE EVENTS
						// section above is usually a better fit - the engine handles the timing.
					}
					else if (scenario.IsReady)
					{
						Console.Write("\r  Waiting for trajectory data...                                          ");
					}
				});

			// Print the final simulation summary
			var totalDuration = DateTime.Now - simulationStartTime;
			Console.WriteLine();
			Console.WriteLine();
			Console.WriteLine($"  Simulation complete. Total time: {totalDuration:hh\\:mm\\:ss}");
			scenario.EndSimulation();
		}
		catch (Exception ex)
		{
			// ex.Message is fully formatted by the API for every exception type it throws, including
			// the AggregateException used to report multiple script-parser errors - no special handling
			// is needed here. Advanced consumers can catch a more specific type (e.g. AggregateException)
			// and inspect InnerExceptions if they need to react to individual errors programmatically.
			Console.WriteLine();
			Console.WriteLine($"  ERROR: {ex.Message}");
		}
	}
}