8,592 QPSK Bits Through One FPGA Pin and a Resonant Tank

July 27, 2026

Physical QPSK · receiver path

The iCE40 generated its own PRBS16 QPSK, reduced complex I and Q to two one-bit streams, selected among four 216 MHz phases, and drove a single pMOS-switched pad into a hand-built resonant tank.

An independently clocked RTL-SDR received the three-second burst after the tank and a nominal 3 dB pad. Direct FPGA telemetry identified 4,296 held-out symbols that actually occurred in silicon. All 8,592 corresponding bits came back without an observed error, at 2.0696356% carrier-tracked RMS EVM.

4,296directly observed held-out symbols
8,592checked bits
0observed errors
2.0696%carrier-tracked RMS EVM

The Message Began Inside the FPGA

The host did not stream payload samples into Physical27. A PRBS16 generator inside the FPGA started at 0x1D2B. Lane 62 selected two changing taps, applied its fixed salt, and turned each two-bit word into one of four cardinal complex states: +I, +Q, −I, or −Q.

The lane advanced at 3,295.8984375 symbols/s. Signed first-order sigma-delta modulators converted its I and Q components into two one-bit streams. A common +7.5 MHz Gray rotation moved the entire complex word, rather than offsetting I and Q independently. The rotated bits selected one of the PLL’s four quadrature phases at 216 MHz. N16 then switched high or high-impedance into the resonant network.

Signal path from FPGA-native PRBS16 QPSK through a spatial complex lane, signed one-bit I and Q sigma-delta streams, a 7.5 megahertz rotation, four 216 megahertz phases, one switched N16 output, a resonant tank, and an RTL-SDR
The complete Physical27 path. The quadrature combination occurs before the single FPGA output reaches the tank.

The Receiver Saw One Finite Burst

The orchestrator opened direct FPGA telemetry and armed the RTL-SDR before loading the volatile CRAM image. The receiver sampled unsigned 8-bit complex values at 2.4 MS/s with its tuner centered at 223.4875 MHz. The wanted QPSK lane sat 75 kHz above that center, at 223.5625 MHz.

N16 stayed active for a nominal three seconds. The capture also retained RF-off samples on both sides of the burst. Afterward the transmitter returned to high impedance, and postflight telemetry counted 22,528 idle frames with no burst-active, physical-RF-pulse, or TX-LED assertion.

Actual RTL-SDR spectrum around the wanted 223.5625 megahertz QPSK lane during the Physical27 burst
The actual Physical27 receiver spectrum around the wanted lane. Vertical level is receiver-relative dBFS per FFT bin, not calibrated RF output power. Plotted frequency bins and levels.

From 2.4 Million Samples per Second to One Point per Symbol

The receiver clocks and FPGA clocks were independent. I therefore recovered carrier and timing from the captured waveform, while direct telemetry supplied the precise transmitted symbol only at epochs that reached the host.

  1. Translate the lane to zero frequency. Complex mixing moved the +75 kHz wanted lane to baseband.
  2. Reduce and filter. Each group of 45 input samples became one complex sample, followed by a 257-tap low-pass filter with a 10 kHz cutoff.
  3. Locate the RF burst. Channel energy selected the interval from 0.7995 to 3.80761875 seconds without consulting the transmitted symbol sequence.
  4. Seed the carrier tracker. Fourth-power phase removed QPSK data modulation and produced an initial residual-frequency estimate of −79.0627 Hz.
  5. Choose the phase bandwidth. Early directly observed epochs selected a 65-sample smoothing width, equivalent to 1.21875 ms after reduction.
  6. Freeze symbol timing. Early alignment set the first epoch at 0.807219774 seconds and fitted 3,295.899426 symbols/s, about 0.3 ppm above the nominal FPGA rate.
  7. Freeze orientation and affine correction. The early region selected the normal QPSK orientation, complex gain, and offset.
  8. Measure each received symbol. Thirteen interpolated points across the central 72% of each symbol epoch were averaged into one complex value.
  9. Track held-out phase from RF alone. During the scored interval, the carrier tracker used received I/Q; it did not use held-out symbol truth or its own hard decisions.
  10. Score only direct matches. A symbol entered the count only when its physical receive epoch and its directly observed FPGA telemetry epoch were both present.

Initialization Ended Before the Checked Interval Began

The first 993 directly observed symbols supplied the timing, orientation, complex gain, offset, and tracker-width choices. The held-out boundary then began at zero-based epoch 4,200 and ended before epoch 9,823. Those settings stayed frozen while phase continued to follow the received waveform.

The nominal held-out span contained 5,623 epochs. Direct telemetry reached 4,296 of them. The other 1,327 epochs inside that span remained holes; no symbol was inferred, interpolated, or counted there. Across the complete run, 2,332 telemetry epochs were absent.

Actual Physical27 held-out constellation with 4296 received QPSK points clustered around four ideal cardinal states
The 4,296 directly paired held-out symbols after received-signal carrier tracking. The small ideal markers identify the four intended cardinal states.

Every Directly Paired Symbol Chose the Intended Quadrant

Hard decisions used the nearest of the four cardinal QPSK states. All 4,296 held-out symbols selected the intended state, so the two-bit mapping produced 8,592 checked bits with zero observed errors. The normalized complex correlation was 0.999584. Eleven local time windows stayed between 1.9828% and 2.1650% RMS EVM.

This finite burst does not define a zero bit-error rate. A BER curve needs many more bits, repeated bursts, controlled received level, temperature and supply variation, and failures as well as successes. Here the specific engineering result is smaller and concrete: every directly paired held-out symbol in Physical27 survived the complete one-pin FPGA, tank, pad, and receiver path.

Held-out constellation points

Each row contains one received complex point, its directly observed FPGA symbol, and the frozen corrected point used for the nearest-state decision.

Download 4,296 points

Recompute the four numbers

The small standard-library Python program recomputes symbol errors, bit errors, RMS EVM, and normalized correlation from that table.

Open the scoring program

The Conjugate Image Required a Second Tuning

Physical28 kept the FPGA image, receiver gain, sample rate, path, and duration unchanged, then moved only the RTL-SDR center to the 208.4375 MHz conjugate-image region. Signed excess power in the predeclared 25 kHz wanted and image windows gave a 29.443932 dB wanted/image ratio.

The two regions were measured sequentially through different RTL-SDR tuner settings. The ratio therefore includes the tank, cable, nominal 3 dB pad, tuner response, receiver response, independent clocks, and the time between captures. It is a complete-path comparison, not device-only Weaver cancellation.

Actual receiver views of the wanted 223.5625 megahertz lane and the 208.4375 megahertz conjugate-image region with RF-on and same-capture RF-off traces
Physical27 wanted-lane tuning and Physical28 conjugate-image tuning. A stronger unassigned line near 208.5 MHz remains visible outside the predeclared image window. Plotted receiver windows.

The Next Receiver Must Share More Time With the Transmitter

Host arrival times were enough to pair thousands of low-rate symbols, but USB telemetry is not a 216 MHz logic analyzer. A common trigger or clock would make sub-symbol timing causal instead of host-associated. Repeated controlled bursts can then sweep received level, temperature, supply, tap settings, tank loading, and symbol rate while keeping the same physical reference plane.

The stronger 216 MHz term remains a separate transmitter problem from the conjugate image. The next receiver work therefore needs to follow information recovery, carrier feedthrough, image behavior, and wideband flatness as four different consequences rather than compressing them into one flattering ratio.