On 6/14/22 4:29 AM, Brian Beezley wrote:
15070000 -1.000470519 -0.000045675
15194750 -1.000452399 -0.000081647
15319500 -1.000464559 -0.000072501
15444250 -1.000433683 -0.000034980
15569000 -1.000416160 -0.000060047
15693750 -1.000486493 -0.000025182
15818500 -1.000452280 -0.000066847
Jim, that's a data sample for the short. The real part is consistently beyond -1.0004. The open is similarly beyond +1. The largest |S11| I found in other .s1p files was 1.0037. I think it is some sort of systematic issue, not noise. Most users will never notice it since the effect is so tiny. My application is sensitive to errors at extreme S11 values, which yield nonphysical results (negative conductivity).
I forgot to mention that the VNA firmware for the open and short was DiSlord 1.2.
Brian
Interesting - I wonder if it's a "round off" or truncation error of some sort.? The "detector" mixes with I/Q 5 kHz, summing, and there could be a 1/2 LSB bias or something like that.
here's the raw I/Q calculation code:
void dsp_process(int16_t *capture, size_t length)
{
uint32_t *p = (uint32_t*)capture;
uint32_t len = length / 2;
uint32_t i;
int32_t samp_s = 0;
int32_t samp_c = 0;
int32_t ref_s = 0;
int32_t ref_c = 0;
for (i = 0; i < len; i++) {
uint32_t sr = *p++;
int16_t ref = sr & 0xffff;
int16_t smp = (sr>>16) & 0xffff;
int32_t s = sincos_tbl[i][0];
int32_t c = sincos_tbl[i][1];
samp_s += smp * s / 16;
samp_c += smp * c / 16;
ref_s += ref * s / 16;
ref_c += ref * c / 16;
}
acc_samp_s = samp_s;
acc_samp_c = samp_c;
acc_ref_s = ref_s;
acc_ref_c = ref_c;
}
raw (uncalibrated) gamma is calculated here
void calculate_gamma(float gamma[2])
{
#if 1
// calculate reflection coeff. by samp divide by ref
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;
#elif 0
gamma[0] =acc_samp_s;
gamma[1] =acc_samp_c;
#else
gamma[0] =acc_ref_s;
gamma[1] =acc_ref_c;
#endif
}
this is the code that applies the calibration:
if (cal_status & CALSTAT_APPLY)
apply_error_term_at(i);
static void apply_error_term_at(int i)
{
// S11m' = S11m - Ed
// S11a = S11m' / (Er + Es S11m')
float s11mr = measured[0][i][0] - cal_data[ETERM_ED][i][0];
float s11mi = measured[0][i][1] - cal_data[ETERM_ED][i][1];
float err = cal_data[ETERM_ER][i][0] + s11mr * cal_data[ETERM_ES][i][0] - s11mi * cal_data[ETERM_ES][i][1];
float eri = cal_data[ETERM_ER][i][1] + s11mr * cal_data[ETERM_ES][i][1] + s11mi * cal_data[ETERM_ES][i][0];
float sq = err*err + eri*eri;
float s11ar = (s11mr * err + s11mi * eri) / sq;
float s11ai = (s11mi * err - s11mr * eri) / sq;
measured[0][i][0] = s11ar;
measured[0][i][1] = s11ai;
// CAUTION: Et is inversed for efficiency
// S21m' = S21m - Ex
// S21a = S21m' (1-EsS11a)Et
float s21mr = measured[1][i][0] - cal_data[ETERM_EX][i][0];
float s21mi = measured[1][i][1] - cal_data[ETERM_EX][i][1];
float esr = 1 - (cal_data[ETERM_ES][i][0] * s11ar - cal_data[ETERM_ES][i][1] * s11ai);
float esi = - (cal_data[ETERM_ES][i][1] * s11ar + cal_data[ETERM_ES][i][0] * s11ai);
float etr = esr * cal_data[ETERM_ET][i][0] - esi * cal_data[ETERM_ET][i][1];
float eti = esr * cal_data[ETERM_ET][i][1] + esi * cal_data[ETERM_ET][i][0];
float s21ar = s21mr * etr - s21mi * eti;
float s21ai = s21mi * etr + s21mr * eti;
measured[1][i][0] = s21ar;
measured[1][i][1] = s21ai;