Skip to content

Calibration Error Model

No VNA is perfect. Cables have loss, connectors have mismatch, and internal circuitry introduces errors. Calibration measures these systematic errors so the firmware can mathematically remove them. The NanoVNA-H uses a 3-term model for S11 (reflection) and extends it to a 5-term model when S21 (transmission) is also calibrated.

Without calibration, your measurements include errors from:

  • Directivity leakage: Signal that appears reflected even with a perfect load
  • Source mismatch: The VNA’s output impedance is not exactly 50 ohms
  • Frequency response: Cables and mixers have frequency-dependent behavior
  • Crosstalk: Signal leaking from Port 1 to Port 2 without going through the DUT

These errors can completely dominate your measurement. A 40 dB return loss device might measure as 20 dB without calibration.

For reflection measurements (S11), the NanoVNA uses three error terms:

flowchart LR
  A[Actual S11] --> B{Error Box}
  B --> C[Measured S11m]

  subgraph Error Terms
      ED[ED: Directivity]
      ES[ES: Source Match]
      ER[ER: Reflection Tracking]
  end
TermNameWhat It Represents
EDDirectivitySignal appearing as reflection even with perfect load
ESSource MatchMismatch at VNA output (re-reflections)
ERReflection TrackingOverall frequency response of reflection path

The measured S11 (S11m) relates to actual S11 (S11a) by:

S11m = ED + (ER * S11a) / (1 - ES * S11a)

Solving for the actual value:

S11a = (S11m - ED) / (ER + ES * (S11m - ED))

The firmware implements this correction in main.c:

static void apply_CH0_error_term(float data[4], float c_data[CAL_TYPE_COUNT][2])
{
// S11m' = S11m - Ed
// S11a = S11m' / (Er + Es * S11m')
float s11mr = data[0] - c_data[ETERM_ED][0];
float s11mi = data[1] - c_data[ETERM_ED][1];
float err = c_data[ETERM_ER][0] + s11mr * c_data[ETERM_ES][0] - s11mi * c_data[ETERM_ES][1];
float eri = c_data[ETERM_ER][1] + s11mr * c_data[ETERM_ES][1] + s11mi * c_data[ETERM_ES][0];
float sq = err*err + eri*eri;
data[0] = (s11mr * err + s11mi * eri) / sq;
data[1] = (s11mi * err - s11mr * eri) / sq;
}

The three SOL (Short-Open-Load) measurements provide enough equations to solve for ED, ES, and ER:

A perfect 50 ohm load has S11 = 0. Whatever we measure is pure error:

ED = S11m_load

A short circuit has S11 = -1 (total reflection, inverted phase):

S11m_short = ED + ER*(-1) / (1 - ES*(-1))

An open circuit has S11 = +1 (total reflection, same phase):

S11m_open = ED + ER*(+1) / (1 - ES*(+1))

Solving these three equations simultaneously gives ED, ES, and ER.

For transmission measurements, two additional terms are needed:

TermNameWhat It Represents
ETTransmission TrackingFrequency response of transmission path
EXIsolation/CrosstalkSignal leaking from Port 1 to Port 2 directly
S21a = (S21m - EX) / ET

With optional enhancement for source match:

S21a = (S21m - EX) / ET * (1 - ES * S11a)

The firmware implementation:

static void apply_CH1_error_term(float data[4], float c_data[CAL_TYPE_COUNT][2])
{
// S21a = (S21m - Ex) * Et` (Et is stored inverted for efficiency)
float s21mr = data[2] - c_data[ETERM_EX][0];
float s21mi = data[3] - c_data[ETERM_EX][1];
data[2] = s21mr * c_data[ETERM_ET][0] - s21mi * c_data[ETERM_ET][1];
data[3] = s21mi * c_data[ETERM_ET][0] + s21mr * c_data[ETERM_ET][1];
// Enhanced response correction using S11
if (cal_status & CALSTAT_ENHANCED_RESPONSE) {
float esr = 1.0f - (c_data[ETERM_ES][0] * data[0] - c_data[ETERM_ES][1] * data[1]);
float esi = 0.0f - (c_data[ETERM_ES][1] * data[0] + c_data[ETERM_ES][0] * data[1]);
float re = data[2];
float im = data[3];
data[2] = esr * re - esi * im;
data[3] = esi * re + esr * im;
}
}

From ISOLATION Measurement (nothing connected, or loads on both ports):

EX = S21m_isolation

From THRU Measurement (Port 1 connected directly to Port 2):

S21m_thru = EX + ET * 1 / (1 - ES * 0)
ET = S21m_thru - EX

The firmware tracks which calibration steps have been performed:

#define CALSTAT_LOAD (1<<0) // Load measured
#define CALSTAT_OPEN (1<<1) // Open measured
#define CALSTAT_SHORT (1<<2) // Short measured
#define CALSTAT_THRU (1<<3) // Thru measured
#define CALSTAT_ISOLN (1<<4) // Isolation measured
#define CALSTAT_ED CALSTAT_LOAD // ED calculated
#define CALSTAT_ES (1<<5) // ES calculated
#define CALSTAT_ER (1<<6) // ER calculated
#define CALSTAT_ET (1<<7) // ET calculated
#define CALSTAT_EX CALSTAT_ISOLN // EX calculated
#define CALSTAT_APPLY (1<<8) // Calibration active
#define CALSTAT_INTERPOLATED (1<<9) // Using interpolated cal data

The NanoVNA stores calibration data as arrays of complex values at each sweep point:

#define CAL_TYPE_COUNT 5
#define CAL_LOAD 0 // ETERM_ED
#define CAL_OPEN 1 // Used to calculate ES, ER
#define CAL_SHORT 2 // Used to calculate ES, ER
#define CAL_THRU 3 // ETERM_ET
#define CAL_ISOLN 4 // ETERM_EX
float cal_data[CAL_TYPE_COUNT][SWEEP_POINTS_MAX][2]; // [type][point][re/im]

Directivity (ED)

Cause: Imperfect directional coupler or bridge Effect: Limits how low you can measure return loss Typical: -40 to -50 dB before cal After Cal: Removed mathematically

Source Match (ES)

Cause: VNA output not exactly 50 ohms Effect: Re-reflections between VNA and DUT Typical: -20 to -30 dB After Cal: Corrected by SOL

Reflection Tracking (ER)

Cause: Cable loss, connector mismatch, mixer response Effect: Magnitude and phase errors vs frequency Typical: Varies with frequency After Cal: Normalized to unity

Transmission Tracking (ET)

Cause: Cable loss, path differences Effect: Insertion loss errors Typical: Increases with frequency After Cal: Normalized to thru

After calibration, verify by re-measuring standards:

StandardIdealGood CalPoor Cal
LoadS11 < -40 dBS11 < -35 dBS11 > -25 dB
OpenS11 = 0 dB, phase = 0Within 0.5 dB, 5 degLarge deviation
ShortS11 = 0 dB, phase = 180Within 0.5 dB, 5 degLarge deviation
ThruS21 = 0 dBS21 within 0.1 dBS21 error > 0.5 dB
ModelTermsStandards NeededCorrects
1-Port (S11)ED, ES, ERShort, Open, LoadReflection measurements
2-Port (S11 + S21)ED, ES, ER, ET, EXSOL + Thru + IsolationBoth reflection and transmission

Learn what makes good calibration standards in SOLT Standards, and how the firmware handles measurements between calibration points in Calibration Interpolation.