Implements the Apollo composite PRN ranging code (5,456,682 chips) from five component sequences (CL, X, A, B, C) combined via majority-vote logic, matching Ken Shirriff's Teensy rangeGenerator.ino bit-for-bit. LFSR taps corrected to produce maximal-length sequences: A: 5-bit, taps [2,0] (x^5+x^2+1, period 31) B: 6-bit, taps [1,0] (x^6+x+1, period 63) C: 7-bit, taps [1,0] (x^7+x+1, period 127) New files: src/apollo/ranging.py -- pure-Python code generator and correlator src/apollo/ranging_source.py -- GR sync_block streaming PRN chips src/apollo/ranging_mod.py -- GR hier_block2 NRZ chip modulator src/apollo/ranging_demod.py -- GR basic_block FFT-based range correlator grc/apollo_ranging_*.block.yml -- GRC block definitions (3 files) examples/ranging_demo.py -- standalone demo with delay simulation
61 lines
1.9 KiB
Python
61 lines
1.9 KiB
Python
"""
|
|
Apollo Ranging Source -- streams PRN ranging chips.
|
|
|
|
Outputs a continuous stream of bytes (0 or 1) representing the composite
|
|
PRN ranging code. The code repeats every 5,456,682 chips (~5.49 seconds
|
|
at the nominal 993,963 chip/s rate).
|
|
|
|
The full code period is pre-generated and cycled through, so startup cost
|
|
is paid once and streaming is zero-allocation.
|
|
|
|
Reference: Ken Shirriff's Apollo ranging analysis
|
|
http://www.righto.com/2022/04/the-digital-ranging-system-that.html
|
|
"""
|
|
|
|
import numpy as np
|
|
|
|
from apollo.ranging import RANGING_CODE_LENGTH, RangingCodeGenerator
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# GNU Radio block (optional -- only if gnuradio is available)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
try:
|
|
from gnuradio import gr
|
|
|
|
class ranging_source(gr.sync_block):
|
|
"""GNU Radio source: continuous PRN ranging chip stream.
|
|
|
|
Outputs bytes (0 or 1) at the chip rate. Pre-generates the full
|
|
code period and cycles through it.
|
|
"""
|
|
|
|
def __init__(self):
|
|
gr.sync_block.__init__(
|
|
self,
|
|
name="apollo_ranging_source",
|
|
in_sig=None,
|
|
out_sig=[np.byte],
|
|
)
|
|
|
|
self._gen = RangingCodeGenerator()
|
|
self._code = self._gen.generate_sequence()
|
|
self._pos = 0
|
|
|
|
def work(self, input_items, output_items):
|
|
out = output_items[0]
|
|
n = len(out)
|
|
produced = 0
|
|
|
|
while produced < n:
|
|
remaining = RANGING_CODE_LENGTH - self._pos
|
|
chunk = min(n - produced, remaining)
|
|
out[produced : produced + chunk] = self._code[self._pos : self._pos + chunk]
|
|
self._pos = (self._pos + chunk) % RANGING_CODE_LENGTH
|
|
produced += chunk
|
|
|
|
return produced
|
|
|
|
except ImportError:
|
|
pass
|