Running a receiver against an exported scenario
A receiver maker who owns a laboratory GNSS simulator can replay a Kshana scenario's
vehicle motion through it, record what the receiver under test does, and score that log
with kshana receiver-trust against events stated before the run. Kshana supplies the
motion, the event times and the scoring. It writes no signal: nothing exported here
synthesises, models or transmits a radio-frequency or baseband waveform, and an exported
event is a labelled time interval, not a recipe for producing interference. The simulator
and its operator supply the signals, and the operator is responsible for running them
only where that is authorised (conducted or shielded, per the simulator's own safety
instructions).
This page is a method. It publishes no results.
1. Export#
kshana bench-export scenarios/gnss-ins.toml --out run1 --epoch 2025-03-01T10:00:00Z
Applies to the gnss-ins kind (a driving profile with attitude; the navigation-state
outages are the events), and to jamming and gnss-sim (a stationary receiver for the
scenario's duration; a jamming scenario's jammer is one event over the run). Other kinds
say why they have no vehicle trajectory. --epoch is the UTC instant of motion time zero
(default 2024-01-01T00:00:00Z); the scenarios carry no calendar date of their own for
vehicle motion. It must be a real UTC instant, YYYY-MM-DDTHH:MM:SS (a trailing Z is
accepted) with the year in 2000 to 2099 and every field in range; anything else is refused.
The output is byte-identical for the same scenario and epoch.
| File | Content |
|---|---|
run1.motion.csv |
one row per sample: time_s, Earth-fixed x_m,y_m,z_m, vx_m_s,vy_m_s,vz_m_s, geodetic lat_deg,lon_deg,h_m, heading_deg,pitch_deg,roll_deg, utc, kshana_row |
run1.motion.json |
the epoch, frames, units, columns and round-trip tolerances of that CSV |
run1.nmea |
NMEA 0183 GGA and RMC sentences per sample, with checksums |
run1.waypoints.txt |
a RESOLUTION: <ms> line then longitude,latitude,altitude rows (written only when every sample interval is the same whole number of milliseconds; when it is left out, the command says why on standard error) |
run1.events.csv |
label,kind,onset_s,end_s,description |
run1.events.toml |
the same events as [[events]] blocks for a receiver-trust scenario |
Frames and conventions#
- Position: WGS 84, Earth-fixed (ECEF:
xthrough the equator at the prime meridian,zthrough the pole);lat_deg,lon_deg,h_mgive the same position geodetically,h_mabove the ellipsoid. - Velocity: Earth-fixed axes, relative to the Earth.
- Attitude:
heading_degclockwise from true north in [0, 360),pitch_degnose up positive,roll_degright wing down positive; yaw-pitch-roll (3-2-1) from the local north-east-down frame to body axes x forward, y right, z down. A stationary source writes zeros. NMEA and the waypoint text carry no attitude. - Heading is the body's yaw, not the direction of travel. In the
gnss-insdriving profile the body yaws in square waves while the velocity follows, so heading and the course over ground can differ by tens of degrees (up to about 77 degrees in the bundledautomotive-urban-canyonscenario). The NMEARMCcourse is the course over ground, the direction of the velocity vector, so a simulator that reads heading from the motion file and one that reads course from the NMEA file see different angles. The course over ground from the CSV isatan2(v_east, v_north)of its velocity rotated to north-east-down. - Height follows the scenario. For
gnss-ins,h_mis the kind's own tangent-plane stepping of its truth and is not held constant (about 7 m over the 180 s ofautomotive-urban-canyon); it is the scenario's motion, written as it is. - NMEA
GGAplaceholders. Fix quality (1), satellites used (12) and HDOP (1.0) are written only to make the sentence well formed. They say nothing about the scenario's geometry or any receiver state. - Time:
time_safter the epoch, UTC, leap seconds not modelled. - NMEA heights are ellipsoidal. The
GGAaltitude holds the ellipsoidal height and the geoid separation is written as 0.0. A simulator that treats the altitude as height above mean sea level will place the vehicle off by the local geoid undulation. - Round-trip tolerances (tested by reading each file back): CSV position 0.1 mm, latitude and longitude 1e-9 degree, velocity 0.1 mm/s, angles 1e-6 degree; NMEA horizontal position 5 mm, height 1 mm, speed 0.001 knot, course 0.001 degree.
Loading the files into a simulator#
Laboratory simulators differ, and this repository does not reproduce any simulator's manual. Check which of the formats above yours reads, and its stated requirements:
- Many motion importers expect a fixed update rate, commonly 10 Hz. The
gnss-insscenario steps at 0.1 s; for a stationary scenario, set[time] step_sto the rate your simulator wants. - Some importers skip samples that fall between whole seconds, or ignore the time column and use the row order. Start the motion on a whole second and keep the grid regular.
- A CSV importer that lets you map columns can read
run1.motion.csvdirectly: choose the Earth-fixed or geodetic columns and set their units fromrun1.motion.json. Truncating the decimals produces false acceleration, so keep the written precision. - The file is motion only. Configure the constellation, the interference and the receiver
front end in the simulator, and time them to the events in
run1.events.csv.
No vendor scripting interface is written by Kshana.
2. State what you will score before the run#
The events file gives the intervals the scenario defines. Copy run1.events.toml into a
receiver-trust scenario, add any prediction you want checked, and fix the monitor
thresholds and tolerances before the receiver runs. Do not adjust them after seeing the
log; the scenario, the thresholds and the log's SHA-256 are all in the result's hash.
kind = "receiver-trust"
name = "bench session 1"
[log]
format = "ubx" # ubx, rinex, android or nmea
path = "receiver-log.ubx"
[monitors]
calibration_s = 60.0
# paste run1.events.toml here, and shift onsets by the log offset (step 4)
[[events]]
label = "gnss-denied-1"
kind = "other"
onset_s = 100.0
end_s = 160.0
The exported events carry the scenario's own kind: a jamming scenario's jammer is
jamming; a navigation-state outage is other, because the scenario states that GNSS was
unavailable, not how. Change the kind to match what you configure the simulator to do.
3. Run the receiver#
Start the receiver and its logger, start the simulator scenario with the motion file, and let the run cover the calibration interval, every event, and a margin after the last one. Keep the receiver's own log (UBX, RINEX 3 observations, an Android logger CSV, or NMEA with satellite status sentences). A log without per-satellite signal strength can still be scored on the receiver's own position, but the carrier-to-noise monitors need it.
4. Align the clocks#
receiver-trust counts event times from the first epoch of the receiver's log; the motion
file counts from its first sample. If the log starts d seconds before the motion's first
sample, add d to every onset_s and end_s. Record the offset and how you measured it,
and state it in the scenario's name or a comment, since a wrong offset moves every score.
Event times alone cannot tell you the offset; use the simulator's start-of-scenario marker
or the receiver's own time stamps.
5. Score#
kshana receiver-trust bench-session.toml
writes bench-session.result.json, .trust.csv and .trust.svg. For each event the
result gives false alarms before the onset, the first alarm and its monitors, the latency,
and the outcome (detected, late, missed, not-evaluable), plus a predicted and
observed carrier-to-noise drop where you stated a prediction. A disagreement is reported,
never tuned away. See RECEIVER-TRUST.md.
To see which public framework rows the session supports evidence for:
kshana compliance-report bench-session.result.json
See compliance/README.md. That report describes the evidence in the runs you give it; it makes no finding about the receiver or any framework.
What this method does not do#
- It does not produce a signal, and it does not say what interference a simulator should generate. The events say when, not what.
- A single session is a single data point. The result describes that log under that configuration, and says nothing about other receivers, firmware, antennas, or real interference.
- Heights, rates and time alignment are the operator's to check against the simulator; the export states its own conventions and tolerances and no more.