242 lines
11 KiB
Markdown
242 lines
11 KiB
Markdown
# 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:
|
||
|
||
```bash
|
||
git -C signalsim/SignalSim remote -v
|
||
git -C signalsim/SignalSim rev-parse HEAD
|
||
git -C signalsim/SignalSim status --short --branch
|
||
```
|
||
|
||
## Reproducible build
|
||
|
||
```bash
|
||
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:
|
||
|
||
```text
|
||
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](../reports/signalsim_bit_generation_report.md) 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.
|
||
|
||
```bash
|
||
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
|
||
|
||
1. Galileo generation: **yes**.
|
||
2. Galileo bands: E1, E5a, E5b, E6; E5 AltBOC is not in the open path.
|
||
3. E1B: **yes, only as part of combined E1**.
|
||
4. E1C: **yes, only as part of combined E1**.
|
||
5. Modulation: BOC(1,1) approximation, not CBOC.
|
||
6. Navigation data: complete encoded/interleaved I/NAV symbols are generated,
|
||
with the field limitations described above.
|
||
7. E1C secondary symbols: **yes**, 25 symbols.
|
||
8. Configurable IF: **yes**, through center frequency, kHz granularity.
|
||
9. Configurable sample rate: **yes**, kHz granularity.
|
||
10. Output: complex IQ only; no native real IF.
|
||
11. Binary formats: exact table above; IQ8 is the validated integration format.
|
||
12. PCPS acquisition: **pass** for E1B and E1C.
|
||
13. Carrier/code tracking: **pass** for E1B and E1C over the available vector.
|
||
14. E1B symbols: **raw symbols and sync recovered**; navigation decoder absent.
|
||
15. E1C secondary: **phase synchronized and long-coherent gain measured**.
|
||
16. 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
|
||
|
||
```bash
|
||
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.
|