A practical recipe for successfully improving signal detection using two orthogonal monopoles in a cantenna.
A practical recipe for successfully improving signal detection using two orthogonal monopoles in a cantenna.
Great — here’s a practical recipe you can use with your setup (2 orthogonal probes, 2 LNAs, 2 SDRs). I’ll outline it in steps, then give you the minimal processing pipeline.
1. Hardware layout
- Antenna: two monopole probes at 90° inside your cantenna (sampling two orthogonal linear polarisations).
- Front-ends: each probe → SAWBird H1 → RTL-SDR (or RSPduo channels if you go that route).
- Calibration source: noise diode or RF tone generator, split equally to both probes (or injected before the LNAs).
2. Recording streams
- Use GNU Radio (or rtl_sdr + SoX) to record complex64 IQ streams from both SDRs simultaneously.
- Ensure same center frequency (1420.4058 MHz) and sample rate.
- Save with metadata in filenames:
- ProbeX_2025-09-21T1200Z_1420MHz_2Msps.c64
- ProbeY_2025-09-21T1200Z_1420MHz_2Msps.c64
- If using RTLs without shared clock: expect drift → you’ll fix later.
- If using RSPduo: channels are already coherent, no drift problem.
3. Calibration step
- Inject noise/tone (short burst) every 5–10 minutes.
- In processing, find this burst in both streams.
- Estimate:
- Relative delay (cross-correlation peak).
- Relative phase (argument of cross-spectrum at tone frequency).
- Store correction factors.
4. Processing pipeline (Python + NumPy/Scipy)
For each calibration interval:
- Align streams
- Apply fractional sample delay correction.
- Apply complex phase rotation.
- Form spectra
- FFT both aligned streams → X(f), Y(f).
- Compute cross-products
- Auto-powers:
- XX = X · X*
- YY = Y · Y*
- Cross-power:
- XY = X · Y*
- Auto-powers:
- Form Stokes parameters
- I = XX + YY
- Q = XX – YY
- U = 2 · Re(XY)
- V = 2 · Im(XY)
5. Incoherent fallback (if no clock share)
- Skip delay/phase alignment.
- Just compute XX and YY, then add: I = XX + YY.
- Sensitivity improvement ~√2.
- Q/U/V won’t be reliable.
6. Minimal GNU Radio flowgraph
- Two RTL-SDR Source blocks (or RSPduo Source).
- Set center freq = 1420.4058 MHz, sample rate ~2 MHz.
- Record to files (File Sink) → complex64.
- Optional: FFT Sink for live spectrum view.
7. Python skeleton (for later analysis)
import numpy as np
# Load IQ streams
x = np.fromfile(“ProbeX.c64”, dtype=np.complex64)
y = np.fromfile(“ProbeY.c64”, dtype=np.complex64)
# — Calibration example with tone/noise burst —
# Cross-correlate
corr = np.fft.ifft(np.fft.fft(x) * np.conj(np.fft.fft(y)))
delay = np.argmax(np.abs(corr))
phase = np.angle(corr[delay])
# Apply corrections
y_corr = np.roll(y, -delay) * np.exp(-1j*phase)
# — FFTs —
X = np.fft.fft(x, n=4096)
Y = np.fft.fft(y_corr, n=4096)
# Stokes
XX = X * np.conj(X)
YY = Y * np.conj(Y)
XY = X * np.conj(Y)
I = XX + YY
Q = XX – YY
U = 2 * np.real(XY)
V = 2 * np.imag(XY)
⚠️ If you want to do this with two RTL-SDR Blog V3s, you’ll need to handle clock drift (resample one stream continuously). With RSPduo, you can skip that — it’s already coherent, and you can get true polarimetry much more easily.