Bind sw::dsp::sdr::AutomaticGainControl — the level-regulating loop that
belongs upstream of every other synchronization block.
Upstream source: include/sw/dsp/sdr/agc.hpp (closes upstream #100).
Upstream tests: tests/test_sdr_agc.cpp.
Surface
enum class LevelDetector { magnitude, rms }
AgcConfig<T> — reference_level, attack_time_s, decay_time_s,
averaging_time_s, sample_rate_hz, min_gain_db, max_gain_db,
initial_gain_db, detector
AutomaticGainControl<StateScalar, SampleScalar> — process(sample),
block process(vector), reset(), set_gain_db(db), gain_db(),
invariants_hold()
Binding notes
- First consumer of the scalar-pair dispatch decision from the foundations
issue. <StateScalar, SampleScalar> here is not incidental: the whole point
of an AGC study is a narrow sample path against a wide-enough loop state, so
whatever scheme is chosen must be able to express that combination.
AgcConfig<T> is templated on the state scalar. Binding one config class per
arithmetic config would be absurd; bind a single float64-valued config struct
and narrow the fields on construction of the Impl<T>. The config is
parameters, not state.
- Times are in seconds against
sample_rate_hz, and leaving the rate at 1
makes them sample counts. Say this in the docstring — it is the kind of
detail that silently produces a loop 48000x too slow.
invariants_hold() is a debug predicate. Bind it; it is exactly the sort of
thing a precision study wants to assert at narrow widths.
- Follow the type-erased
IImpl + templated Impl<T> + Py* wrapper pattern
already used in src/acquisition_bindings.cpp and
src/multirate_bindings.cpp.
- Complex
process() — see the foundations issue for the inbound convention.
Depends on
Foundations issue (both decisions).
Deliverables
Part of the SDR binding epic #130.
Bind
sw::dsp::sdr::AutomaticGainControl— the level-regulating loop thatbelongs upstream of every other synchronization block.
Upstream source:
include/sw/dsp/sdr/agc.hpp(closes upstream #100).Upstream tests:
tests/test_sdr_agc.cpp.Surface
enum class LevelDetector { magnitude, rms }AgcConfig<T>—reference_level,attack_time_s,decay_time_s,averaging_time_s,sample_rate_hz,min_gain_db,max_gain_db,initial_gain_db,detectorAutomaticGainControl<StateScalar, SampleScalar>—process(sample),block
process(vector),reset(),set_gain_db(db),gain_db(),invariants_hold()Binding notes
issue.
<StateScalar, SampleScalar>here is not incidental: the whole pointof an AGC study is a narrow sample path against a wide-enough loop state, so
whatever scheme is chosen must be able to express that combination.
AgcConfig<T>is templated on the state scalar. Binding one config class perarithmetic config would be absurd; bind a single float64-valued config struct
and narrow the fields on construction of the
Impl<T>. The config isparameters, not state.
sample_rate_hz, and leaving the rate at 1makes them sample counts. Say this in the docstring — it is the kind of
detail that silently produces a loop 48000x too slow.
invariants_hold()is a debug predicate. Bind it; it is exactly the sort ofthing a precision study wants to assert at narrow widths.
IImpl+ templatedImpl<T>+Py*wrapper patternalready used in
src/acquisition_bindings.cppandsrc/multirate_bindings.cpp.process()— see the foundations issue for the inbound convention.Depends on
Foundations issue (both decisions).
Deliverables
src/sdr_bindings.cpp.python/mpdsp/__init__.py.tests/test_sdr_agc.py— settling behaviour, gain clamping atmin_gain_db/max_gain_db, and a narrow-dtype run that shows where theloop stops converging.
scripts/build_api_ref.pytables updated,docs/api_reference.mdregenerated.
Part of the SDR binding epic #130.