aethersdr / aethersdr/AetherSDR
Hl2Spectrum averages in the dB domain: accumulate power, take the log once at emit
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 221
- Forks
- 117
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 302
Description
Splitting the part of #5782 that is invariant under whatever that RFC rules, so it isn't blocked waiting on the seam and ownership questions.
The arithmetic
Hl2Spectrum::computeFrame already has the power term and discards it:
const double mag = std::sqrt(re * re + im * im) / m_coherentGain;
binsDbfs[k] = static_cast<float>(20.0 * std::log10(mag + 1e-12));
20·log10(mag) is 10·log10(mag²), and mag² is (re² + im²) / m_coherentGain² — the square root is taken only to be undone by the logarithm. Accumulating
(re*re + im*im) / (m_coherentGain * m_coherentGain)
and taking 10·log10 once at emit is arithmetically identical for a single frame and correct for several, which averaging the dBFS values is not: the mean of logs is the log of the geometric mean, which sits below the arithmetic mean and biases low exactly where the display is noisiest.
That is the great majority of the work for #5782's row 2.1, and it depends on none of that RFC's open questions.
Deliberately NOT in scope here
These are #5782's to rule on and building them now would be building the parts most likely to be routed differently:
- The seam verb — whether it's a defaulted
IRadioBackend::setPanAverage(panId, frames, weighted)mirroringsetPanFrameRate, or something else. (#5782 q2) - A shared component in
src/core/dsp/across the three raw-spectrum families vs. each keeping its own. (#5782 q3) - ANAN's
smoothSpectrumBins— left alone. (#5782 q4)
Two constraints any implementation has to respect
Both already established by reading the surrounding code, both easy to get wrong:
- Averaging state must survive a pan rebuild.
Hl2RxDsp::configurereplacesm_config, so a setting stored inConfigsilently resets on every zoom. It belongs in its own member — the noise blanker, the notch mirror and the shift all already do this. - State must be DROPPED across a geometry change, not carried. A change of FFT size or span makes accumulated bins describe a different thing.
Hl2Spectrum::reset()is the existing precedent to follow.
One open design question
A boxcar average=N must not divide the display cadence by N — that's not the operator's to lose. So it's a sliding mean (a ring of N × fftSize doubles: 512 kB at N=16, fftSize=4096) or an EMA with alpha = 1/N (one vector, but a different estimator). Flex exposes both (average and weighted_average), so both are presumably wanted eventually.
I've deliberately not resolved this — it's cheap to decide and expensive to get wrong, and #5782 q1 may constrain it. If a maintainer states a preference I'll implement it; otherwise I'll do the EMA first as the smaller change and add the boxcar behind the same control once the seam exists.
Provenance
Nothing here is measured. The claim is arithmetic about Hl2Spectrum::computeFrame, read from source on origin/main and re-verified against it before filing. No spectrum has been captured before or after, and the visible improvement on a real waterfall remains an inference from the arithmetic — as #5782 says of itself.
🤖 Generated with Claude Code
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in Hl2Spectrum::computeFrame, then read Hl2RxDsp::configure and Hl2Spectrum::reset to understand the existing state lifetimes. Implement accumulation of power before a single logarithm at emit, preserving averaging state across pan rebuilds but dropping it on geometry changes. Done means the averaging estimator and its control are resolved, without changing the explicitly excluded seam, shared component, or ANAN smoothing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100