Signal Processing Mini Project · Final Review
An adaptive, self-calibrating OFDM modem that moves files between the speaker and microphone of ordinary consumer devices, in the 4–12 kHz audio band. This bench shows the complete signal chain and every measurement behind it.
Every constant is derived from one place (ofdm/config.py) so that
experiments can sweep the design without touching the DSP. The band starts at 4 kHz because
laptop speakers roll off badly below it, and stops at 12 kHz because that is where the
microphone response falls away on the test hardware.
A speaker is peak-limited, so the figure that sets received SNR is average power at a fixed peak. An unclipped OFDM block throws away about 11 dB of that budget. Clipping the waveform and re-filtering it back into the band buys the power back, until the distortion it introduces starts costing more than the power gains.
A single simulated transmission at 18 dB SNR through a multipath room with a 60 ppm sampling-clock offset — the cross-device case. Each panel is one stage of the receiver, in the order the receiver runs them.
Chirp preamble, then the OFDM burst. The two are scaled separately: OFDM has a 9 dB peak-to-average ratio, so one global normalisation would leave the chirp far too quiet to detect.
After the room, the transducers, noise and an unknown arrival delay.
Correlating against the known chirp. A 30 ms sweep across 10 kHz has a time–bandwidth product near 300, so the peak stays sharp well below 0 dB SNR.
Occupied band after the IFFT. Energy outside 4–12 kHz is the cyclic-prefix discontinuity and the clipping used for peak reduction.
Least-squares estimate from the reference symbol, per subcarrier. The nulls are what make equalisation necessary — and what set the error floor.
Common phase error removed by the adaptive tracker each symbol. The steady ramp is the sampling-clock offset between the two devices.
The channel's own phase rotation, uncorrected.
One estimate from the reference symbol, held for the whole burst.
Pilot-tracked, with per-symbol phase correction.
Each point is 16 independent transmissions of 6 200 bits — about 99 000 bits per point. Every SNR point in a sweep sees the same set of simulated rooms, so differences between points come from noise alone. Points at the floor line had zero errors in all 99 000 bits.
With multipath switched off the measured curve should sit on the coherent-QPSK theory curve. It does, which says the IFFT, cyclic prefix, synchroniser and demapper are all correct.
The headline Phase 2 result. Without equalisation the link never works at any SNR; with it, BER falls until it hits the floor set by the channel's deepest spectral null.
Two devices never share a crystal. This is the case a one-shot calibration cannot survive, and the reason the adaptive stage exists.
The tracking-versus-noise trade-off. Too small and the tracker cannot follow a drifting clock; too large and it injects its own estimation noise.
Played through a laptop speaker and captured on the same laptop's microphone via ALSA — no simulation anywhere in this section.
Swept with the chirp. This is the measurement that changed the design: the response varies enormously across the band, and subcarriers landing in the deep region are unrecoverable no matter how good the equaliser is.
After Stage-1 subcarrier selection, synchronisation and adaptive equalisation.
Simulated room (multipath, transducer roll-off, 80 ppm clock offset), adaptive equaliser. Each FEC point is 8 transmissions of a 293-byte file through the same set of rooms for every scheme, so the comparison is paired.
Rate-½ convolutional code (K = 7, soft-decision Viterbi, interleaved) against repetition-3 and no coding. Hollow points had zero errors.
Share of frames recovered exactly for the longest frame tested, with and without the receiver's sample-clock correction pass.
From experiments/run_two_device.py: one device transmits, another records and decodes blind. The clock offset is measured from the received pilots.