RF Testing and Calibration with TofuPilot
Every wireless product needs RF testing: output power, receiver sensitivity, frequency accuracy, spurious emissions. For products with WiFi, Bluetooth, LoRa, cellular, or custom RF, these measurements determine whether the product meets regulatory requirements and actually works in the field. TofuPilot stores RF test data for trending, calibration tracking, and compliance.
RF Test Parameters
| Parameter | What it measures | Why it matters |
|---|---|---|
| TX output power (dBm) | Transmitted signal strength | Too high: regulatory violation. Too low: poor range |
| RX sensitivity (dBm) | Minimum receivable signal | Determines receive range |
| Frequency error (ppm) | Crystal/oscillator accuracy | Affects interoperability |
| EVM (Error Vector Magnitude) | Modulation quality | Affects data throughput |
| Spurious emissions | Unintended RF output | Regulatory compliance |
| RSSI accuracy | Received signal strength indicator | Affects link management |
Logging RF Test Results
Basic RF Parametric Test
from tofupilot import TofuPilotClient
client = TofuPilotClient()
def rf_production_test(serial, tx_power, rx_sensitivity, freq_error_ppm, evm_pct):
client.create_run(
procedure_id="RF-PARAMETRIC-BLE",
unit_under_test={
"serial_number": serial,
"part_number": "IOT-SENSOR-V3",
},
run_passed=True,
steps=[{
"name": "TX Performance",
"step_type": "measurement",
"status": 0 <= tx_power <= 4,
"measurements": [
{"name": "tx_power_dbm", "value": tx_power, "unit": "dBm", "limit_low": 0, "limit_high": 4},
{"name": "freq_error_ppm", "value": freq_error_ppm, "unit": "ppm", "limit_low": -20, "limit_high": 20},
{"name": "evm_pct", "value": evm_pct, "unit": "%", "limit_high": 30},
],
}, {
"name": "RX Performance",
"step_type": "measurement",
"status": rx_sensitivity <= -90,
"measurements": [
{"name": "rx_sensitivity_dbm", "value": rx_sensitivity, "unit": "dBm", "limit_high": -90},
],
}],
)Multi-Channel RF Test
Test across all operating channels to catch channel-specific issues.
# BLE has 40 channels (0-39)
# Test a representative set
test_channels = [0, 12, 19, 20, 38, 39]
measurements = []
for ch in test_channels:
set_channel(ch)
power = measure_tx_power()
measurements.append({
"name": f"tx_power_ch{ch}_dbm",
"value": power,
"unit": "dBm",
"limit_low": 0,
"limit_high": 4,
})
client.create_run(
procedure_id="RF-MULTI-CHANNEL-BLE",
unit_under_test={"serial_number": serial},
run_passed=all(0 <= m["value"] <= 4 for m in measurements),
steps=[{
"name": "Multi-Channel TX Power",
"step_type": "measurement",
"status": True,
"measurements": measurements,
}],
)RF Calibration
Many wireless products require per-unit RF calibration to compensate for component tolerances. The calibration process:
- Measure actual TX power at a reference level
- Calculate the offset from target
- Write a calibration value to the DUT's flash/EEPROM
- Verify calibrated output matches target
def calibrate_rf(serial):
# Step 1: Measure uncalibrated power
raw_power = measure_tx_power()
# Step 2: Calculate calibration offset
target_power = 0.0 # dBm
cal_offset = target_power - raw_power
# Step 3: Write calibration to DUT
write_cal_value(cal_offset)
# Step 4: Verify
calibrated_power = measure_tx_power()
client.create_run(
procedure_id="RF-CALIBRATION-BLE",
unit_under_test={"serial_number": serial},
run_passed=abs(calibrated_power - target_power) < 1.0,
steps=[{
"name": "TX Calibration",
"step_type": "measurement",
"status": True,
"measurements": [
{"name": "raw_tx_power_dbm", "value": raw_power, "unit": "dBm"},
{"name": "cal_offset_db", "value": cal_offset, "unit": "dB"},
{"name": "calibrated_tx_power_dbm", "value": calibrated_power, "unit": "dBm",
"limit_low": -1.0, "limit_high": 1.0},
],
}],
)Tracking RF Performance Across Production
Calibration Offset Distribution
The distribution of calibration offsets tells you about your RF hardware consistency. A tight distribution (small offsets) means consistent PCB manufacturing. A wide or drifting distribution suggests:
- Antenna placement variation
- PCB impedance variation
- Component lot changes (balun, matching network)
TX Power Over Time
Plot TX power across production. Look for:
| Pattern | Cause |
|---|---|
| Gradual drift | Test equipment calibration drift |
| Step change | New component lot, PCB revision |
| Increased variance | Manufacturing process variation |
| Channel-dependent failures | Antenna or matching network issues |
RX Sensitivity Monitoring
Receiver sensitivity is harder to measure in production (requires a shielded environment and calibrated signal source). Track it to catch:
- LNA gain degradation
- Filter mistuning
- Increased noise figure from layout changes
Test Fixture Considerations
RF testing requires controlled RF environments:
| Setup | Use case | Isolation |
|---|---|---|
| Shielded box | Production testing | 60-80 dB |
| Anechoic chamber | Antenna characterization | 80+ dB |
| RF cable (conducted) | Board-level testing | Direct connection |
Log the fixture type and serial number with each test run. If RF test results shift, the fixture calibration or cable condition may have changed.
Regulatory Compliance Data
RF certification (FCC, CE, IC, MIC) requires specific test data. While certification testing is done at accredited labs, pre-compliance data from TofuPilot helps you:
- Predict certification outcomes based on production margins
- Compare production units to the original certified unit
- Track any changes that could void certification