diversity

package
v0.7.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: Apache-2.0 Imports: 1 Imported by: 0

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

type Combiner interface {
	Combine(branches [][]complex64) ([]complex64, error)
}

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

func NewMRC(branches int, alpha float64) *MRC

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

func (m *MRC) Combine(branches [][]complex64) ([]complex64, error)

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

func (m *MRC) PowerEstimates() []float64

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.

func (*MRC) SetGain

func (m *MRC) SetGain(k int, h complex64)

SetGain switches the combiner into pilot-based mode and assigns the channel gain estimate for branch k. Call once per branch with a fresh estimate (typically derived from a known training symbol). SetGain(-1, 0) reverts to power-based mode (k<0 means "all").

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.

func NewSelection

func NewSelection() *Selection

NewSelection constructs a selection combiner.

func (*Selection) Combine

func (s *Selection) Combine(branches [][]complex64) ([]complex64, error)

Combine selects, per sample index, the branch with the largest |x|^2. With a single branch the input chunk is returned verbatim (allocated copy so the caller can safely mutate the result).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL