Compensate IFFT window / zero-padding loss in TD

Depending on the chosen window and mode, the magnitude of the
impulse response in time-domain previously was to low. This can
be explained by looking at the signal processing. For example,
in bandpass mode with normal window, it applies a 101 point Kaiser
window (shape factor 6) and zero-pads to do a 256 point IFFT.
Therefore, the loss is 20*log10(256/sum(kaiser(101,6))) ≈ 14.2 dB.

This change compensates the signal processing losses in bandpass
and lowpass impulse mode depending on the window type, which makes
the time-domain results similar to other VNAs.
This commit is contained in:
Christian Zietz 2020-10-25 13:31:08 +01:00
parent bc1b57c3f0
commit 4d64ef6e48

46
main.c
View file

@ -198,40 +198,54 @@ transform_domain(void)
// and calculate ifft for time domain
float* tmp = (float*)spi_buffer;
// correct IFFT window and zero-padding loss
// assuming a 2*POINT_COUNT window
float wincorr = 1.0f;
float beta = 0.0;
switch (domain_mode & TD_WINDOW) {
case TD_WINDOW_MINIMUM:
beta = 0.0; // this is rectangular
// loss by zero-padding 202 to 256 points
wincorr = (float)FFT_SIZE / (float)(2*POINTS_COUNT);
break;
case TD_WINDOW_NORMAL:
beta = 6.0;
// additional window loss: 1/mean(kaiser(202,6)) = 2.01
wincorr = (float)FFT_SIZE / (float)(2*POINTS_COUNT) * 2.01f;
break;
case TD_WINDOW_MAXIMUM:
beta = 13;
// additional window loss: 1/mean(kaiser(202,13)) = 2.92
wincorr = (float)FFT_SIZE / (float)(2*POINTS_COUNT) * 2.92f;
break;
}
uint8_t window_size = POINTS_COUNT, offset = 0;
uint8_t is_lowpass = FALSE;
switch (domain_mode & TD_FUNC) {
case TD_FUNC_BANDPASS:
offset = 0;
window_size = POINTS_COUNT;
// window size is half the size as assumed above => twice the IFFT loss
wincorr *= 2.0f;
break;
case TD_FUNC_LOWPASS_IMPULSE:
case TD_FUNC_LOWPASS_STEP:
// no IFFT losses need to be considered to calculate the step response
wincorr = 1.0f;
// fall-through
case TD_FUNC_LOWPASS_IMPULSE:
is_lowpass = TRUE;
offset = POINTS_COUNT;
window_size = POINTS_COUNT * 2;
break;
}
float beta = 0.0;
switch (domain_mode & TD_WINDOW) {
case TD_WINDOW_MINIMUM:
beta = 0.0; // this is rectangular
break;
case TD_WINDOW_NORMAL:
beta = 6.0;
break;
case TD_WINDOW_MAXIMUM:
beta = 13;
break;
}
for (int ch = 0; ch < 2; ch++) {
memcpy(tmp, measured[ch], sizeof(measured[0]));
for (int i = 0; i < POINTS_COUNT; i++) {
float w = kaiser_window(i + offset, window_size, beta);
tmp[i * 2 + 0] *= w;
tmp[i * 2 + 1] *= w;
tmp[i * 2 + 0] *= w * wincorr;
tmp[i * 2 + 1] *= w * wincorr;
}
for (int i = POINTS_COUNT; i < FFT_SIZE; i++) {
tmp[i * 2 + 0] = 0.0;