Lesson 29 of 30 advanced 5 min read

Before this:DSP in GopherTrunk

Testing & debugging DSP

Key takeaways DSP is deterministic arithmetic, which makes it testable. Golden vectors pin known input→output pairs so any behaviour drift fails a test. Offline replay of a recorded .cfile capture turns an un-reproducible on-air bug into a repeatable one. And invariants — properties that must always hold, like GopherTrunk’s rate-invariance — catch whole classes of failure. Together they let you prove a decoder works instead of hoping.

The final skill in this module isn’t an algorithm — it’s how you know any of them are correct. This lesson draws the whole pipeline together under the question: how do you verify a signal path? It reflects the practices GopherTrunk’s own repository enforces.

Golden vectors: deterministic reference outputs

Because a DSP block is pure arithmetic, the same input always yields the same output. That determinism is a gift for testing. A golden vector captures a known input and the correct output beside it; a regression test runs the input through the code and asserts the result matches.

input vector   ->  [ DSP under test ]  ->  output
                                              ||  compare
golden output  ------------------------------ '
mismatch => a behaviour change => test fails

This is exactly the project’s rule for a bug fix: a regression test that fails without the fix and passes with it. If you can’t write a vector that fails first, you haven’t truly reproduced the bug — a discipline that stops “fixes” for problems that were never understood.

Offline replay: making the un-reproducible repeatable

The hardest bugs appear on live signals that never recur. The cure is to record the raw I/Q — a .cfile of complex samples — once, then replay that same file through the pipeline as often as you like. GopherTrunk has a dedicated replay path for exactly this: the same samples, the same result, every run. A live mystery becomes a deterministic test you can bisect and, crucially, re-run to confirm a fix rather than guess at one.

Invariants: properties that must always hold

Beyond specific vectors, the strongest tests assert invariants — statements true for every valid input. GopherTrunk’s headline example is rate-invariance: because the downconverter normalizes every channel to a fixed channel rate, a given channel must decode to the same in-channel quality whether it was captured at 2.4 MS/s or 10 MS/s and decimated down. A test that asserts this pins the whole front-end’s behaviour with one property.

That invariant is also a diagnostic. Read the table:

Symptom What the invariant tells you
Fails live at high rate, reproduces in offline replay the fault is in the captured data (front-end overload, phase noise) — not the DSP
Fails live but cannot be reproduced offline from the same file the DSP is fine; look upstream at capture/timing
Same file decodes differently across runs non-determinism — a real bug in the code

The project used precisely this reasoning on a field issue: a channel that locked from a 2.4 MS/s capture but not a 10 MS/s one. Decimating the high-rate file with an independent resampler and replaying it through the proven path reproduced the same deficit — proving the ~10 dB shortfall was baked into the samples (front-end reciprocal mixing), not GopherTrunk’s downconverter.

A workable debugging loop

Putting it together, the reliable loop is:

  1. Capture the failing signal to a .cfile.
  2. Replay it to reproduce the failure deterministically.
  3. Write a golden-vector or invariant test that fails on it.
  4. Fix until the test passes — and only then claim it fixed.

That last point is a hard rule in this project: a fix isn’t verified until a failing-first test passes and the symptom is shown resolved. It is why the same discipline that grades a link — SNR, EVM, BER — also grades your changes to the code that decodes it.

Quick check: a bug appears only at a high capture rate but reproduces in offline replay of that file. Where is the fault?

Recap

  • DSP is deterministic, so golden vectors (input→output) turn numeric drift into test failures.
  • Offline replay of a .cfile makes an un-reproducible on-air bug repeatable.
  • Invariants like rate-invariance pin whole behaviours and double as diagnostics.
  • A fix is verified only when a failing-first test passes and the symptom is shown gone.

Next up: the last lesson — how numbers are stored, and why it matters for performance.

Frequently asked questions

What is a golden vector in DSP testing?

A golden vector is a saved reference: a known input and the exact output a correct implementation must produce for it. A regression test feeds the input through the code and compares against the stored output. Because DSP is deterministic arithmetic, any drift from the golden output signals a change in behaviour — it turns a subtle numeric bug into a hard test failure you can catch automatically.

Why replay a recorded capture instead of testing with live radio?

A live signal is never the same twice, so a bug that appears on the air is nearly impossible to reproduce or to prove fixed. A recorded capture — a .cfile of raw I/Q — is a fixed, repeatable stimulus. Replaying it runs the exact same samples through the pipeline every time, so you can reproduce a failure deterministically, bisect it, and confirm a fix by re-running the same file.