On 3/23/21 5:39 PM, Roger Need via groups.io wrote:
On Tue, Mar 23, 2021 at 06:15 AM, Jim Lux wrote:
You should really be looking at the I/Q uncertainty (R and X) rather
than mag and phase.? The VNA directly measures I and Q, which is then
converted to reflection coefficient with sqrt and atan.? For "small"
random uncertainties in I/Q on a vector, the uncertainty in magnitude
and angle (in radians) are comparable. This is comparable to the "small
angle approximation for sin(x) = x. Think of a vector with a "cloud" of
measurement points around the tip of the vector - the noise on I and the
noise on Q are comparable, and as long as noise is "small" compared to
magnitude, that cloud is pretty symmetrical in shape.
Jim,,
I did some research today on how the NanoVNA calculates the reflection coefficient, Gamma, from the digitized bridge signals. There is very little information on this available and the firmware source code does not have a flowchart or text description. The best I could find was edy555 notes where he said he first calculates the magnitude and phase of the reflection coefficient in polar form (magnitude and phase) . From there the real and imaginary form of gamma, impedance and SWR etc. is easily calculated. If anyone has specific information on the steps done in the nanoVNA I would be interested to hear about it.
The basic instrument calculates I/Q (dsp.c, dsp_process()) from the input samples, with the usual multiply by sin/cos. acc_samp_s and _c, and acc_ref_s and _c.
It then calculates gamma by dividing by the reference (dsp.c, calculate_gamma())
? float rs = acc_ref_s;
? float rc = acc_ref_c;
? float rr = rs * rs + rc * rc;
? //rr = sqrtf(rr) * 1e8;
? float ss = acc_samp_s;
? float sc = acc_samp_c;
? gamma[0] =? (sc * rc + ss * rs) / rr;
? gamma[1] =? (ss * rc - sc * rs) / rr;
that's the usual (a+bj)/(c+dj)? identity -> (a+bj) * (c-dj)/[(c+dj)(c-dj)]
that's gamma as a complex number.
sweep() in main.c actually does the measurements for the frequencies, and applies the calibrations.? It calls *sample_func, which is defined on line 610:
static void (*sample_func)(float *gamma) = calculate_gamma;
The conversion to phase is done in plot.c - look for the function phase()
in main.c, the trace type is set to TRC_PHASE in cmd_trace(), and that sets it up
so when trace_into_index() in plot.c is called,
??? v = refpos - phase(coeff[i]) * scale;
which turns the phase into a the plot value.
If you're looking to turn gamma (reflection coefficient) into impedance, that's done in plot.c, also in gamma2imp()
? float z0 = 50;
? float d = z0 / ((1-coeff[0])*(1-coeff[0])+coeff[1]*coeff[1]);
? float zr = ((1+coeff[0])*(1-coeff[0]) - coeff[1]*coeff[1]) * d;
? float zi = 2*coeff[1] * d;
similarly for displaying phase, trace_get_value_string() turns the value (coeff[2]) into a string.
? case TRC_PHASE:
??? v = phase(coeff[i]);
??? chsnprintf(buf, len, "%.3f" S_DEGREE, v);
??? break;
So, in summary, the NanoVNA measures things in cartesian coordinates, and only converts to polar for display or plotting.
My analysis program does have the Gamma I and Q output capability so here is the output based on a 470 pF capacitor at 3.4 MHz. with a reactance of 100 ohms. You can see that a .03 to .04% error in I or Q measurement results in a calculated Q error of 100 for this example. If the Q to be measured is higher even less IQ error can be tolerated. For example with a reactance of 20 ohms and a Q of 1000 the ESR is .02 ohms and a .007% in I or Q measurement results in a Q error of 50.
Chasing High Q on the NanoVNA seems pointless....
Roger