11 KiB
SignalSim integration and measured compatibility
Repository identity and immutable baseline
The detected project is the GNSS simulator by Jun Mo (globsky/SignalSim), not
another repository with a similar name.
| Item | Detected value |
|---|---|
| Local path | /home/onur/Desktop/galileo/signalsim/SignalSim |
| Remote | https://github.com/globsky/SignalSim |
| Commit | 80b262113e77c4482ca9f5cbfef9bcada402ed28 |
| Branch/status before integration | main...origin/main, clean |
| License evidence | No LICENSE/COPYING file; source headers say “All rights reserved”; README identifies some commercially licensed features |
SignalSim itself was not modified. The receiver parses its code tables from the external checkout at run time, so the SignalSim commit remains part of the test vector provenance and its copyrighted tables are not copied into this project.
The identity commands were:
git -C signalsim/SignalSim remote -v
git -C signalsim/SignalSim rev-parse HEAD
git -C signalsim/SignalSim status --short --branch
Reproducible build
tools/build_signalsim.sh /home/onur/Desktop/galileo/signalsim/SignalSim
ctest --test-dir build/signalsim --output-on-failure
The build used CMake 3.31.9, GCC 11.4.0, Ninja 1.11.1, C++20, Release mode,
OpenMP, and USE_NATIVE_OPT=OFF. It produced build/signalsim/IFdataGen.
CTest reported No tests were found!!!; the repository does not define
IFdataGen CTest tests at this commit. The documented -v/--version options do
not print a version and instead fall through to configuration handling.
Source-to-sample trace
The executed Galileo E1 path is:
JSON output.systemSelect "Galileo"/"E1"
-> IFdataGen frequency selection
-> PrnGenerate(GalileoSystem, SIGNAL_INDEX_E1, SVID)
E1B = E1MemoryCode[(SVID-1)*128]
E1C = E1MemoryCode[(SVID+49)*128]
-> SatelliteSignal
E1B = -I/NAV symbol / sqrt(2)
E1C = 25-symbol pilot sign / sqrt(2)
-> SatIfSignal BOC half-chip sign and carrier rotation
-> complex Gaussian noise + AGC
-> IQ8/IQ16/IQ4/IQ2 quantizer
-> binary file, I before Q
GetMemorySequence() reads four storage sectors per E1 code. Within each
32-word/1024-bit sector it consumes 1023 bits MSB first and discards the last
padding bit. The receiver adapter mirrors that exact behavior. Treating the
table as 4092 contiguous bits was experimentally shown to reduce peak/second
from about 7 to about 1; the sector-aware implementation restores acquisition.
SignalSim models E1 as equal-amplitude E1B and E1C on the same real baseband
axis. It flips every second 2.046-Mchip/s half-chip, which is BOC(1,1). It does
not synthesize the BOC(6,1) term or full Galileo E1 OS CBOC in this path. E1B
and E1C cannot be selected separately by the JSON/CLI; E1 always generates
the combined signal.
Source-inspected Galileo selection (only E1 was generated in this validation):
| Band selector | Components implemented in open source path | Data layer / pilot overlay | Validation status |
|---|---|---|---|
| E1 | E1B data + E1C pilot, inseparable | I/NAV / common CS25 | Generated and received |
| E5a | data I + pilot Q codes | F/NAV / PRN-specific CS100 | Source inspected only |
| E5b | data I + pilot Q codes | I/NAV / PRN-specific CS100 | Source inspected only |
| E6 | pilot output (data amplitude set to zero) | no open data path / CS100 | Source inspected only |
| E5 AltBOC | Listed as commercially licensed | N/A | Not available/tested |
Navigation and secondary data
E1B is not a fixed or random placeholder bit stream. INavBit::GetFrameData()
constructs Galileo I/NAV words from the selected RINEX ephemeris/almanac/UTC
data, adds CRC-24Q, convolutionally encodes, interleaves, inserts the 10-symbol
sync pattern, and emits 500 encoded symbols per 2-second page. Word types above
20 are forced to dummy word 63; reserved/SAR/spare fields include zero-filled
placeholders. Reed-Solomon ephemeris parity words 17–20 are implemented.
E1C uses a common 25-symbol value held in PilotBit.cpp as 0x9b501c, addressed
LSB first. This work verifies the sequence SignalSim actually emits; it does
not independently certify that constant against a particular Galileo ICD
revision.
See the bit-layer report for a stage-by-stage distinction between navigation fields, channel symbols, spreading chips, and samples.
Output formats and controls
sampleFreq and centerFreq are configurable JSON values in MHz and are
converted internally to integer kHz. A signal's complex IF is
RF carrier - centerFreq; out-of-band signals are disabled. Native output is
complex IQ only—there is no real-only IF binary mode.
| Format | Exact packing | Quantization at AGC gain G |
Status |
|---|---|---|---|
| IQ16 | little-endian signed I16, signed Q16 | truncate 3277*G*x, saturate −32768…32767 |
usable |
| IQ8 | signed I8, signed Q8 | truncate 25*G*x, saturate −128…127 |
validated |
| IQ4 | one byte; I high nibble, Q low; sign-magnitude | truncate 3*G*abs(x), magnitude saturates at 7 |
adapter tested |
| IQ2 | two complex samples/byte, low then high nibble; sign/magnitude | threshold levels | broken in this commit: computed byte is never assigned to output |
The adapter in galileo_rx.io.signalsim_reader validates file length, signed
conversion, byte order, IQ order, offsets, counts, memory mapping, and streaming.
All decoded samples are promoted to numpy.complex128; quantized integer widths
remain explicit input boundaries.
Generated vector and executable results
The deterministic vector configuration is
verification/vectors/signalsim/high_cn0_single_prn/config.json. It requests
one visible Galileo PRN 1, combined E1B/E1C, 55 dB-Hz configured C/N0, 8.184
MHz complex IQ8, center 1573.374 MHz (IF +2.046 MHz), static receiver, bundled
RINEX navigation data, and 2.2 seconds duration.
build/signalsim/IFdataGen \
-c verification/vectors/signalsim/high_cn0_single_prn/config.json \
-o verification/vectors/signalsim/high_cn0_single_prn/high_cn0_single_prn_iq8.bin \
-t -st
MPLBACKEND=Agg python -m galileo_rx.cli validate-signalsim \
--signalsim-path signalsim/SignalSim \
--config configs/signalsim_validation.yaml \
--output-dir reports/signalsim_validation \
--mode quick
The sample file is 36,009,600 bytes (18,004,800 complex samples) with SHA-256
3e72a5ad2d35ee68273b77587a66847b0fb328650b39c9e39272f0dc54e39e3c.
SignalSim's validation summary reports PRN 1 Doppler +1828 Hz; this is rounded
to integer hertz. SignalSim does not emit exact sample-side code-delay truth.
Measured quick-mode results:
| Quantity | E1B | E1C |
|---|---|---|
| PCPS detected PRN | 1 | 1 |
| Raw Doppler bin | +1750 Hz | +1750 Hz |
| Interpolated Doppler | +1766.36 Hz | +1776.64 Hz |
| Code phase | 18309.410 samples | 18309.256 samples |
| Peak/second metric | 7.511 | 6.903 |
| Final tracking Doppler | +1828.251 Hz | +1828.284 Hz |
| Tracking Doppler jitter | 1.326 Hz RMS | 1.082 Hz RMS |
| DLL error | 0.0963 chips RMS | 0.0849 chips RMS |
| Final state | PLL_TRACK | PLL_TRACK |
| Reacquisition epochs | 0 | 0 |
E1B uses 2 ms pull-in integrations. A 4 ms BPSK-squared FLL has an unambiguous range of only ±62.5 Hz, almost exactly the residual between the interpolated estimate and the +1828 Hz truth. Two milliseconds expands that range to ±125 Hz, after which the channel converges and 2 ms prompt pairs form one 4 ms symbol. Two exact I/NAV sync patterns were recovered 250 symbols (one second) apart after a 300 ms tracking transient. This proves raw symbol recovery and page-boundary synchronization, not FEC/page/CRC decoding.
E1C synchronization jointly searched secondary phase and residual carrier frequency. It found phase 10 and +52.0 Hz residual, correlation 0.9830, and 0/100 sign errors. Wiping the secondary code yielded 13.72 dB of 25-period coherent gain versus a 4 ms period, and 14.58 dB improvement relative to the unwiped 25-period sum.
Full mode adds three generated vectors. The 50 dB-Hz configured nominal vector
passes E1C acquisition (metric 12.49), secondary synchronization (correlation
0.9947, 0/100 errors), and pilot tracking at +1828.672 Hz with 0.817 Hz jitter.
The negative-Doppler PRN 27 vector passes
acquisition at −2750 Hz versus −2637 Hz truth and, after pull-in, tracks at
−2637.776 Hz with 0.531 Hz jitter and 0.0615-chip DLL RMS. Five-PRN acquisition
detects PRNs 1, 4, 19, 21, and 27; every raw Doppler result is within one 250 Hz
bin. The negative channel raised five reacquisition flags during initial pull-in
but none after epoch 500, and finished in PLL_TRACK; that transient is retained
in the report rather than hidden.
Detailed machine results and plots are in
reports/signalsim_validation/, with acquisition-only results in
reports/signalsim_acquisition_report.{json,md}.
Direct answers and limitations
- Galileo generation: yes.
- Galileo bands: E1, E5a, E5b, E6; E5 AltBOC is not in the open path.
- E1B: yes, only as part of combined E1.
- E1C: yes, only as part of combined E1.
- Modulation: BOC(1,1) approximation, not CBOC.
- Navigation data: complete encoded/interleaved I/NAV symbols are generated, with the field limitations described above.
- E1C secondary symbols: yes, 25 symbols.
- Configurable IF: yes, through center frequency, kHz granularity.
- Configurable sample rate: yes, kHz granularity.
- Output: complex IQ only; no native real IF.
- Binary formats: exact table above; IQ8 is the validated integration format.
- PCPS acquisition: pass for E1B and E1C.
- Carrier/code tracking: pass for E1B and E1C over the available vector.
- E1B symbols: raw symbols and sync recovered; navigation decoder absent.
- E1C secondary: phase synchronized and long-coherent gain measured.
- Failures: no component-only E1, no CBOC, no real IF, broken IQ2 writer, no exported exact delay/symbol truth, no receiver I/NAV FEC/page decoder, and the remaining signal-format/component limitations listed above.
Compatibility and RTL readiness
“Ready” below means the external stimulus, convention adapter, Python golden result, and automated check exist. It does not claim the RTL IP itself is built.
| Capability | SignalSim support | Python receiver result | RTL readiness |
|---|---|---|---|
| Galileo E1B generation | Partial (combined E1 only) | Pass | Ready |
| Galileo E1C generation | Partial (combined E1 only) | Pass | Ready |
| Real IF | No | Not tested | Blocked |
| Complex IQ | Yes | Pass | Ready |
| Configurable sample rate | Yes | Pass at 8.184 MHz | Ready |
| Configurable IF | Yes | Pass at +2.046 MHz | Ready |
| PCPS acquisition | N/A | Pass | Ready |
| Carrier tracking | N/A | Pass | Ready |
| Code tracking | N/A | Pass | Ready |
| E1B symbol recovery | Generated | Pass (raw + sync) | Ready |
| Full I/NAV decoding | Generated | Not implemented | Blocked |
| E1C secondary-code synchronization | Generated | Pass | Ready |
Regression commands
pytest -m signalsim -v
pytest tests/integration/test_signalsim_acquisition.py -v
pytest tests/integration/test_signalsim_tracking.py -v
--mode full additionally regenerates/validates nominal-C/N0 acquisition,
negative-Doppler acquisition and tracking, and five-PRN acquisition. E1B-only
and E1C-only cases remain blocked because SignalSim cannot generate them.