Skip to content

AcresGnssModel.h#

Acres/Source/Acres/AcresGnssModel.h Generated

GNSS receiver model for the sensor recorder, in the position domain.

Parts: a synthetic GPS/Galileo/GLONASS constellation (circular Keplerian orbits, Earth rotation); sky-view obstruction by scene buildings, grain bins and tree crowns; DOP (dilution of precision); an RTK fix-state machine (none / single / DGPS / RTK float / RTK fixed) with convergence and correction age; state-dependent first-order Gauss-Markov + white + multipath errors whose reported sigma equals the modelled error standard deviation; and the datum chain NAD83(HARN) -> NAD83(2011) -> ITRF2014 = WGS84(G2139) at the observation epoch, with GEOID12B heights and an NMEA $GNGGA sentence.

There are no pseudoranges or carrier phases: the model perturbs the true antenna position. Pure maths except GatherStructures, which reads the Unreal world. FAcresGnssModel::Epoch runs on the physics thread.

GeodeticToEcef#

Geodetic latitude/longitude/ellipsoidal height to Earth-centred Earth-fixed (ECEF) coordinates.

Argument Description
LatDeg Latitude, degrees.
LonDeg Longitude, degrees.
H Ellipsoidal height, m.
A Ellipsoid semi-major axis, m.
InvF Inverse flattening.
Out Receives ECEF X, Y, Z, m.
void GeodeticToEcef(double LatDeg, double LonDeg, double H, double A, double InvF, double Out[3]);

EcefToGeodetic#

ECEF to geodetic coordinates (fixed-point iteration on latitude, 8 rounds; sub-millimetre near the surface).

Argument Description
In ECEF X, Y, Z, m.
A Ellipsoid semi-major axis, m.
InvF Inverse flattening.
LatDeg Output latitude, degrees.
LonDeg Output longitude, degrees.
H Output ellipsoidal height, m.
void EcefToGeodetic(const double In[3], double A, double InvF, double& LatDeg, double& LonDeg, double& H);

HelmertForward#

Applies the Helmert parameter set in its own direction (source -> target), at an epoch.

Uses the small-angle rotation matrix (PROJ "helmert" without +exact).

Argument Description
P Parameters.
Epoch Observation epoch, decimal year.
In Source ECEF, m.
Out Target ECEF, m.
void HelmertForward(const FHelmert14& P, double Epoch, const double In[3], double Out[3]);

HelmertInverse#

Applies the Helmert parameter set in reverse (target -> source), at an epoch. Uses the transpose of the small-angle rotation, which matches the exact inverse to well below a millimetre for these angles.

Argument Description
P Parameters.
Epoch Observation epoch, decimal year.
In Target-frame ECEF, m.
Out Source-frame ECEF, m.
void HelmertInverse(const FHelmert14& P, double Epoch, const double In[3], double Out[3]);

DecimalYear#

Converts a UTC time to a decimal year (e.g. 2026.73), counting the actual length of that year.

Argument Description
Utc Time, UTC.

Returns: Decimal year.

double DecimalYear(const FDateTime& Utc);

FHelmert14#

struct FHelmert14

14-parameter time-dependent Helmert transformation, in PROJ units and the coordinate-frame rotation convention.

Name Type Unit Default Description
T, R, S, dT, dR, dS, Epoch0 double T: translation, m. R: rotation, arc-seconds. S: scale, ppm. dT, dR, dS: rates of each per year. Epoch0: reference epoch, decimal year.

FAcresGnssStateParams#

struct FAcresGnssStateParams

Error parameters for one fix state. All sigmas are 1-sigma per axis, metres; H = east and north, V = up.

Name Type Unit Default Description
SigmaH, SigmaV, InitialSigmaH, InitialSigmaV, ConvergenceTauS, WhiteH, WhiteV, TauS, MultipathH double SigmaH, SigmaV: Gauss-Markov (slowly varying) error sigma, m. InitialSigmaH, InitialSigmaV: RTK float sigma at lock, decaying to SigmaH/V with ConvergenceTauS (s). WhiteH, WhiteV: white noise per epoch, m. TauS: Gauss-Markov correlation time, s. MultipathH: horizontal multipath sigma at multipath index 1, m.

FAcresGnssModelConfig#

struct FAcresGnssModelConfig

GNSS receiver settings (sensors.json "gnss" block, minus rate and antenna position, which live in FAcresSensorConfig).

Name Type Unit Default Description
States FAcresGnssStateParams Error parameters per EState. Defaults: fixed 8/15 mm, float 0.10/0.20 m (from 0.40/0.80), DGPS 0.35/0.70 m, single 1.0/2.0 m (H/V).
Start FString TEXT("converged") "converged" (receiver already running with RTK fixed at t = 0) or "cold" (no fix until ColdTtffS).
ColdTtffS double s 20 Time to first fix after a cold start, s.
ElevationMaskDeg double ° 10 Satellites below this are ignored, degrees (0-45).
Gps, Galileo, Glonass bool Constellations simulated (at least one).
TtfMedianS, TtfLogSigma, TtfMultipathGain, ReacquireFactor, ReacquireWindowS double Time to fix after an RTK lock = TtfMedianS exp(TtfLogSigma g) (1 + TtfMultipathGain m), times ReacquireFactor when within ReacquireWindowS of the last loss (s, dimensionless, dimensionless, 0-1, s).
RtkMinClear int 6 Unobstructed satellites needed for ambiguity convergence.
FloatMinSatellites int 5 Used satellites needed for any RTK solution.
RtkMaxPdop double 5 PDOP limit for convergence.
CycleSlipRatePerS double s .3 Cycle-slip rate at multipath index 1, per second.
MultipathTauS double s 8 Multipath correlation time, s.
MultipathVerticalRatio double 1.5 Vertical / horizontal multipath sigma.
CorrectionIntervalS, CorrectionLatencyS, RtkMaxAgeS, DgpsMaxAgeS, BaselineKm, PpmH, PpmV double Correction stream: one message every CorrectionIntervalS arriving CorrectionLatencyS later (s). RTK needs age <= RtkMaxAgeS, DGPS age <= DgpsMaxAgeS (s). BaselineKm: distance to the base station, km; adds PpmH / PpmV parts per million of the baseline to the RTK sigmas.
OutagesS TArray&lt;FVector2D> s Correction outages as [start, end) in episode seconds (x = start, y = end). Messages generated inside are lost.
NearMarginM double m 1.5 A line of sight passing within this of a solid edge counts as "near" (diffraction/multipath), m.
FoliageBlockPathM double m 8 Crown path length that blocks a satellite, m.
ReflectorRangeM double m 60 Structures farther than this do not add to the reflector index, m.
OutputFrame FString TEXT("wgs84_g2139") Frame of latitude_deg / longitude_deg / ellipsoidal_height_m: "wgs84_g2139" or "nad83".
StartUtc FString TEXT("2026-09-23T15:00:00Z") UTC at episode time 0 (ISO 8601); sets the epoch for the time-dependent Helmert and the GGA time.
HarnTo2011DegLat, HarnTo2011DegLon double NADCON5 NAD83(HARN) -> NAD83(2011) shift at the site, degrees of latitude and longitude (constant).
GeoidModel FString TEXT("GEOID12B") Geoid model name (documentation only).
GeoidN0M, GeoidDnDeM, GeoidDnDnM double Geoid undulation as a plane: N = GeoidN0M + GeoidDnDeM x east + GeoidDnDnM x north (m, m/m, m/m; ENU metres about the origin). A least-squares fit to the GEOID12B grid tile.
Helmert AcresGeo::FHelmert14 ITRF2014 -> NAD83(2011), EPSG/PROJ "ITRF2014 to NAD83(2011) (1)" from NGS HTDP, reference epoch 2010.0.
Noise bool true False (-SensorNoNoise) zeroes all position errors and sigmas; random draws still happen.

FAcresGnssModelConfig::FAcresGnssModelConfig#

Sets the per-state defaults and the NGS Helmert parameters.

FAcresGnssModelConfig();

FAcresGnssModelConfig::Parse#

Reads the sensors.json "gnss" block (states, rtk, corrections, obstruction, datum).

Argument Description
Gnss The "gnss" JSON object. Missing keys keep their defaults.
void Parse(const TSharedPtr<FJsonObject>& Gnss);

FAcresGnssModelConfig::ApplyCommandLine#

Applies -SensorGnssStart=, -SensorGnssFrame=, -SensorGnssBaselineKm=, -SensorGnssOutage=<start>:<end> (appended to the outage list) and -SensorNoNoise.

Argument Description
CommandLine The command line to read (null: the process's; "" gives the file settings with the derived values updated, as the sensor profile's reference needs).
void ApplyCommandLine(const TCHAR* CommandLine = nullptr);

FAcresGnssModelConfig::Validate#

Checks every parameter against its supported range; stops the game with a checkf message if not.

void Validate() const;

FAcresGnssModelConfig::ToJson#

Serialises the settings with the same keys as sensors.json.

FString ToJson() const;

FAcresGnssModelConfig::EpochYear#

Observation epoch as a decimal year.

Argument Description
EpisodeTimeS Seconds since episode start.

Returns: StartUtc + EpisodeTimeS as a decimal year.

double EpochYear(double EpisodeTimeS) const;

EState#

enum EState

Fix states with their own error parameters. "No fix" has none; it reports nothing.

Value Description
Fixed
Float
Dgps
Single
StateCount

FAcresGnssObstacle#

struct FAcresGnssObstacle

One sky-view obstacle, in Unreal world metres (X east, Y south, Z up).

Name Type Unit Default Description
Kind uint8 Box Which shape this is (EKind).
Min FVector FVector::ZeroVector See above.
Max FVector FVector::ZeroVector Axis-aligned bounds, m.
Center FVector FVector::ZeroVector Shape centre, m.
Radius double 0 Cylinder or sphere radius, m.

EKind#

enum EKind : uint8

Box: building (axis-aligned bounds). Cylinder: grain bin (vertical). Foliage: tree crown (sphere).

Value Description
Box
Cylinder
Foliage

FAcresGnssModel#

class FAcresGnssModel

The simulated receiver: constellation, obstruction, fix state and error processes.

The recorder calls Initialize and SetObstacles in Start (game thread), then Epoch at the GNSS rate from PhysicsSample (physics thread). Not thread-safe; only one thread uses it at a time.

Example

FAcresGnssModel Receiver;
Receiver.Initialize(Config.GnssModel, 42, OriginFt, true);
const FString Row = Receiver.Epoch(Step, TimeS, AntennaUeM, AntennaEnuM, RngGnss);
Name Type Unit Default Description
StateEpochs uint64 Epochs spent in each fix state, indexed rtk_fixed, rtk_float, dgps, single, no_fix.
Transitions uint64 0 Number of fix-state changes.

FAcresGnssModel::Initialize#

Resets the receiver and builds the constellation.

Argument Description
Config Receiver settings.
Seed Master seed; the constellation uses its own PCG32 stream (Seed + 3027, sequence 4).
OriginFt Site origin: EPSG:2968 easting, northing (US survey ft) and NAVD88 height (ft).
bGeoreferenced False when site.json is missing; then no latitude/longitude or GGA is written.
void Initialize(const FAcresGnssModelConfig& Config, int Seed, const FVector& OriginFt, bool bGeoreferenced);

FAcresGnssModel::SetObstacles#

Replaces the obstacle list (buildings, bins, tree crowns).

void SetObstacles(TArray<FAcresGnssObstacle>&& In) ;

FAcresGnssModel::Epoch#

Computes one receiver epoch.

Argument Description
Step Physics step, copied to the row.
TimeS Episode time, s.
AntennaUeM True antenna position, Unreal world metres (for obstruction).
AntennaEnuM True antenna position, ENU metres about the local origin (perturbed and reported).
Rng The GNSS noise stream; exactly 11 draws are consumed every epoch, whatever the state: 9 Gaussians (Gauss-Markov, white, multipath per ENU axis), 1 uniform (cycle slip), 1 Gaussian (time to fix).

Returns: The jsonl row body (without timing fields and closing brace): fix type, satellites, DOP, multipath, correction age, RTK timers, model sigmas, position, sigma, covariance, geodetic outputs and NMEA GGA.

Note

Physics thread.

FString Epoch(uint64 Step, double TimeS, const FVector& AntennaUeM, const FVector& AntennaEnuM, FAcresPcg32& Rng);

FAcresGnssModel::Manifest#

Settings plus constellation size, obstacle count, fix-state counts and plain-text model descriptions, for episode.json "gnss".

TSharedPtr<FJsonObject> Manifest() const;

FAcresGnssModel::GatherStructures#

Collects building visuals (boxes) and grain-bin visuals (vertical cylinders) from actor tags.

Argument Description
World The game world.
Out Obstacles are appended here, Unreal world metres.

Note

Game thread (iterates actors).

static void GatherStructures(UWorld* World, TArray<FAcresGnssObstacle>& Out);

FAcresGnssModel::Geodetic#

Runs the forward datum chain for an ENU point.

Argument Description
EnuM Point in ENU metres about the origin.
EpochYear Observation epoch, decimal year.

Returns: Every intermediate and final geodetic coordinate.

FGeo Geodetic(const FVector& EnuM, double EpochYear) const;

FAcresGnssModel::EnuFromWgs84#

WGS84(G2139) latitude/longitude/ellipsoidal height to ENU metres about the origin, via the inverse chain.

Argument Description
LatDeg Latitude, degrees.
LonDeg Longitude, degrees.
H Ellipsoidal height, m.
EpochYear Observation epoch, decimal year.

Returns: ENU position, m (up relative to the origin's NAVD88 height).

FVector EnuFromWgs84(double LatDeg, double LonDeg, double H, double EpochYear) const;

FGeo#

struct FGeo

Geodetic outputs for one ENU point. Exposed for the landmark check in episode.json.

Name Type Unit Default Description
HarnLat, HarnLon, Lat2011, Lon2011, NavdH, GeoidN, Nad83H, WgsLat, WgsLon, WgsH double HarnLat, HarnLon: NAD83(HARN), deg. Lat2011, Lon2011: NAD83(2011), deg. NavdH: NAVD88 height, m. GeoidN: geoid undulation, m. Nad83H: NAD83(2011) ellipsoidal height, m. WgsLat, WgsLon, WgsH: WGS84(G2139) at the epoch, deg, deg, m.