Documentation
¶
Overview ¶
Package diversity combines IQ streams from N receivers tuned to the same frequency into a single per-sample IQ stream that's stronger and less faded than any one source. Two complementary strategies live here:
selection.go Selection combining — pick the branch with the
highest instantaneous |x|^2. Cheap, no calibration,
graceful degradation when one branch goes silent.
mrc.go Maximal-ratio combining — weight each branch by an
estimate of its complex channel response and sum.
Optimal in AWGN; needs SNR estimates per branch and
cooperating front-ends (matched RF chains).
Both combiners take []complex64 chunks per branch and emit a single []complex64 chunk. Branch alignment is the caller's job: a delay line before the combiner equalizes path-length skew across antennas, and a coarse phase recovery (e.g. a CMA equalizer per branch) keeps the branches phase-aligned. With one antenna this package is a no-op; with two or more it's where the diversity gain lives.
Public surface: a Combiner interface and two implementations (NewSelection / NewMRC), so a higher-level pipeline can swap the strategy without changing the call site.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Combiner ¶
Combiner takes one chunk of complex samples per branch (in branch order) and returns a single combined chunk. All branch chunks must have the same length; mismatches return an error rather than silently truncating.
type MRC ¶
type MRC struct {
// contains filtered or unexported fields
}
MRC implements maximal-ratio combining: each branch is weighted by an estimate of its complex channel gain (or, equivalently for our purposes, by its measured signal power) and summed coherently. In AWGN with cooperating front-ends this is the optimal linear combiner — its output SNR equals the sum of the per-branch SNRs.
What this implementation does:
y[i] = ( sum_k conj(h_k) · x_k[i] ) / sum_k |h_k|^2
where h_k is the per-branch complex gain estimate. Two estimation modes are supported:
- Power-based (default). h_k is taken as a real, positive number equal to sqrt(P_k), where P_k is the moving-average power of branch k. Phase-blind — assumes the branches are already phase- aligned at the combiner input (an upstream CMA equalizer per branch handles that).
- Pilot-based. h_k is supplied externally via SetGain and the combiner uses the operator-provided complex weight directly. Used when a known reference symbol is available — e.g. P25 FSW or a pilot tone.
The struct is stateful: power estimates are EMA-smoothed across successive Combine calls so a branch's recent history influences its weight. Reset() clears the smoothing.
Properties:
- Robust to a silent branch (its weight collapses toward zero).
- Sensitive to phase mis-alignment: with two equal-power branches in anti-phase, MRC cancels the signal. The phase-blind power mode here is a deliberately conservative choice; pilot mode unlocks the full coherent gain.
func NewMRC ¶
NewMRC constructs a maximal-ratio combiner for `branches` inputs. `alpha` sets the smoothing rate of the per-branch power estimate in [0,1]; smaller values average over a longer window. A reasonable default is 0.05 — slow enough to ignore single-sample noise, fast enough to track fading on the scale of tens of milliseconds at typical sample rates.
func (*MRC) Combine ¶
Combine produces one output sample per input sample-index. In power mode, per-branch power is updated with an EMA of the chunk's average |x|^2 before weighting; in pilot mode, the operator-set gains drive the weights and no smoothing happens.
func (*MRC) PowerEstimates ¶
PowerEstimates returns a copy of the current EMA power vector. Test helper / diagnostics; harmless to call in production.
func (*MRC) Reset ¶
func (m *MRC) Reset()
Reset zeroes the smoothed power estimates and gains; the next chunk boots both fresh.
type Selection ¶
type Selection struct{}
Selection is the simplest diversity combiner: per output sample, pick the branch with the highest |x|^2. No SNR calibration, no phase alignment, no per-branch weights — just the loudest sample wins.
Properties:
- With M independent Rayleigh-faded branches, selection diversity gives ~ M-fold reduction in deep-fade probability while only paying the cost of one branch's data path downstream. The theoretical SNR gain is 10·log10(sum_{k=1..M}(1/k)) dB above one branch — about 4.8 dB for M=4.
- Phase-blind: it doesn't matter if branches are anti-phase.
- Robust to a silent branch: a dead branch contributes |x|^2=0 and never wins.
The struct is empty (the algorithm has no per-call state) but kept concrete so future variants — selection with hysteresis, or hybrid switch-and-stay diversity — can hang state off it without breaking callers.