Linrad Notes
Source Issues

Spur removal

Spur removal cancels stable, unmodulated carriers — birdies, reference leakage, switching-supply lines — from the fine fft2 spectrum before AFC and the audio path use it. Each spur is modeled as a drifting complex sinusoid tracked by a PLL and (with two channels) on its own polarization, then subtracted.

Spur removal

Detecting spurs

When AFC is in auto mode (genparm[AFC_ENABLE] == 2, wg.spur_inhibit == 0), Linrad searches the averaged spectrum for narrow peaks that stand above a noise threshold and are frequency-stable, adding them as spurs up to genparm[MAX_NO_OF_SPURS]. The search runs incrementally so it does not stall the DSP thread.

In the source

Driver spur_removal()wcw.c:204 (called from second_fft()). Candidate search and setup: init_spur_elimination() and spursearch_spectrum_cleanup() in spursub.c; the threshold is noise × 10^(1.5/√(3·spur_speknum)) (spursub.c:93). Spur size constants: SPUR_N = 3, SPUR_SIZE = 8, SPUR_WIDTH = 7 (globdef.h:173, seldef.h:6); genparm[MAX_NO_OF_SPURS] and genparm[SPUR_TIMECONSTANT] (globdef.h:311).

Modeling and subtracting each spur

For every spur, each new second-FFT frame updates:

The modeled spur is subtracted from the spectrum. If the model drifts off the signal, spur_relock() re-acquires it.

In the source

Main loop eliminate_spurs()spur.c:36; PLL update refine_pll_parameters()spur.c:634 (uses spur_d0pha/spur_d1pha/spur_d2pha for φ, φ′, φ″); polarization update update_spur_pol()spur.c:496 (same covariance form as fft3_mix2(), see diversity); subtraction remove_spur()spur.c:596; re-lock spur_relock()spur.c:682. Initial per-spur setup and polarization: initial_remove_spur() / make_spur_pol() in spursub.c.

Spur removal operates on the second FFT output and feeds AFC; its polarization tracking is the same computation as adaptive polarization and the pulse blanker.