Bind sw::dsp::sdr::CarrierRecovery — the Costas / decision-directed carrier
loop.
Upstream source: include/sw/dsp/sdr/carrier_recovery.hpp (closes upstream
#99). Upstream tests: tests/test_sdr_carrier_recovery.cpp.
Surface
enum class CarrierDetector { bpsk, qpsk, decision_directed }
CarrierRecoveryConfig<T> — loop_bandwidth, damping, detector_gain,
max_frequency, detector, enable_afc, afc_gain, lock_threshold,
lock_average_symbols
CarrierRecovery<StateScalar, SampleScalar> — process(in), reset(),
invariants_hold(), lock metric accessor
Binding notes
- Reuses
PiLoopFilter bound by the timing-recovery issue. Do not bind it
twice.
max_frequency is in radians per symbol and also bounds the integrator.
Note the unit in the docstring — this repo has already been bitten once by a
units mismatch in a phase accumulator (the NCO documented as radians while
actually stepping in normalized cycles, corrected in
src/acquisition_bindings.cpp). Verify against the header before writing the
docstring, and add a test that pins the unit.
- AFC (
enable_afc, afc_gain) widens acquisition beyond the phase detector's
pull-in range. A test with an initial frequency offset outside pull-in,
passing with AFC on and failing with it off, documents the feature better
than prose.
- Block
process method required, same argument as the timing loop.
- Same type-erased pattern; same scalar-pair scheme as AGC and timing.
Depends on
Foundations issue; PiLoopFilter from the timing-recovery issue.
Deliverables
Part of the SDR binding epic #130.
Bind
sw::dsp::sdr::CarrierRecovery— the Costas / decision-directed carrierloop.
Upstream source:
include/sw/dsp/sdr/carrier_recovery.hpp(closes upstream#99). Upstream tests:
tests/test_sdr_carrier_recovery.cpp.Surface
enum class CarrierDetector { bpsk, qpsk, decision_directed }CarrierRecoveryConfig<T>—loop_bandwidth,damping,detector_gain,max_frequency,detector,enable_afc,afc_gain,lock_threshold,lock_average_symbolsCarrierRecovery<StateScalar, SampleScalar>—process(in),reset(),invariants_hold(), lock metric accessorBinding notes
PiLoopFilterbound by the timing-recovery issue. Do not bind ittwice.
max_frequencyis in radians per symbol and also bounds the integrator.Note the unit in the docstring — this repo has already been bitten once by a
units mismatch in a phase accumulator (the NCO documented as radians while
actually stepping in normalized cycles, corrected in
src/acquisition_bindings.cpp). Verify against the header before writing thedocstring, and add a test that pins the unit.
enable_afc,afc_gain) widens acquisition beyond the phase detector'spull-in range. A test with an initial frequency offset outside pull-in,
passing with AFC on and failing with it off, documents the feature better
than prose.
processmethod required, same argument as the timing loop.Depends on
Foundations issue;
PiLoopFilterfrom the timing-recovery issue.Deliverables
src/sdr_bindings.cpp.python/mpdsp/__init__.py.tests/test_sdr_carrier_recovery.py— lock from a phase offset for eachdetector, AFC pull-in beyond the phase detector's range, integrator
bounded by
max_frequency.scripts/build_api_ref.pytables updated,docs/api_reference.mdregenerated.
Part of the SDR binding epic #130.