Skip to content

Repository files navigation

SSB Visualization

An interactive, in-browser demonstration of Single Side Band (SSB) modulation — how it differs from full AM, why an envelope (AM) detector can't recover it, and how a real SSB receiver gets the signal back by re-injecting the carrier.

▶ View online: begoon.github.io/ssb

SSB visualization screenshot

What it shows

Starting from a message — either a 1 kHz test tone or your microphone — the app builds and plots:

  1. The message waveform.
  2. Full AM (carrier + both sidebands): (1 + m·s)·cos(ωc·t), with the envelope drawn on top.
  3. SSB (upper sideband only — carrier and lower sideband suppressed), via the phasing/Hilbert method: s·cos(ωc·t) − ŝ·sin(ωc·t).
  4. Spectra of AM vs SSB, zoomed around the carrier so the suppressed carrier and lower sideband are obvious.
  5. A recovery comparison of the original message against two demodulation attempts.

The point: how do you get SSB back?

  • AM decoder attempt (envelope detection) — rectify + low-pass.
    • For a tone the SSB envelope is constant → silence. (√(cos² + sin²) = 1.)
    • For voice you get the analytic (Hilbert) envelope of your speech: distorted, wrong pitch, partly recognizable — but not the real signal. This is fundamental, not a tuning artifact: the amplitude envelope of speech is inherently informative.
  • SSB receiver (product / coherent detection) — re-inject the carrier and low-pass: LPF{ ssb · 2·cos(ωc·t) } → clean recovery.
    • The BFO offset slider simulates a mistuned re-injected carrier: every recovered frequency shifts by that many Hz (the "Donald Duck" effect). It's why real SSB radios have a clarifier/RIT knob.

Frequencies & why they differ

A real SSB voice carrier is in the MHz range (HF/CB), but a browser can't sample or play that. So each domain uses the highest frequency it can actually represent, keeping the carrier-to-message ratio intact:

DomainCarrierWhy
Tone — visual plots1 MHz (default)synthetic math, oversampled, no real-time limit
Mic — spectrum27 MHz (default)exact frequency translation of the voice band (CB-SSB)
Mic — time view & all audioscaled (~8 kHz / 5 kHz)real audio is 48 kHz → must stay under the 24 kHz Nyquist

The mic spectrum is shown at a true RF carrier because SSB is just a frequency shift of the voice band — so the displayed axis is translated up to the carrier exactly, while the time waveform and playback necessarily stay in a scaled, audible/representable domain.

Run it

Requires Bun. Recipes via just:

just dev # dev server with hot reload at http://localhost:3000
just test# run the DSP unit tests
just build # bundle into a single self-contained docs/index.html
just open # build + open the single-file page (no server)

Without just:

bun install
bun index.ts # dev server
bun test# tests
bun run build.ts # produce docs/index.html

The microphone needs a secure origin, so use http://localhost:3000 (dev server) or the built file — getUserMedia won't prompt from a bare file:// in some browsers.

Deploy

just build writes a fully self-contained docs/index.html (all JS inlined, no external requests). Point GitHub Pages at the docs/ folder to publish.

Project layout

FileRole
dsp.jsFFT, Hilbert transform, AM/SSB synthesis, envelope & product detectors, filters
plot.jsCanvas waveform / spectrum / multi-trace plotting (theme-aware)
audio.jsWeb Audio playback, mic capture, building the demodulation buffers
frontend.jsUI wiring: controls → DSP → plots + audio
index.htmlLayout, styling, light/dark theme
index.tsBun.serve() dev server
build.tsBundles + inlines everything into docs/index.html
dsp.test.tsUnit tests for the DSP core

Tests

bun test covers the DSP core: the Hilbert transform (90° shift), SSB constant amplitude for a tone, carrier/lower-sideband suppression, envelope detection (AM recovers, SSB is silent), and product detection (re-injected carrier recovers the message; a detuned carrier does not).

License

MIT © 2026 Alexander Demin

About

In-browser demonstration of Single Side Band (SSB) modulation

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages