diff --git a/matlab/one_pfb.m b/matlab/one_pfb.m index f8434022c4a271275bc509248e0006918f2ee3fb..d759b7bfb30d47a3f0cd8d1f210e6356031e8a2a 100644 --- a/matlab/one_pfb.m +++ b/matlab/one_pfb.m @@ -83,6 +83,50 @@ % filterbank is defined by the FFT size (tb.subband_fft_size). The block % size after the subband filterbank is defined by the number of subbands % (tb.nof_subbands). +% +% * Flipped order of FIR coefficients: +% The FIR coefficients in the PFB are flipped per column of N_fft = 1024 +% coefficients, for all N_taps = 16 columns. In VHDL simulation this shows +% with tb_verify_pfb_response.vhd and in the Matlab model this flip is also +% done by ctrl_pfir_subband.coeff = flipud(ctrl_pfir_subband.coeff). +% With the flip the one_pfb.m yields SNR subband / spurious max = 64.305310 +% dB in subband 64 for an input WG at 64.015625. Without the flip the SNR +% subband / spurious max = 29.857938 dB, so much worse. Hence flipping the +% FIR coefficients is needed, and not due to an implementation detail in +% the VHDL. The run_pfb.m is equivalent to one_pfb.m and is used to create +% reference input and expected output data for the wpfb implementation in +% VHDL by wpfb_unit_wide.vhd. The tb_tb_wpfb_unit_wide.vhd verifies multiple +% sets of reference data including sinus, chirp, noise and real input or +% complex input and wideband (f_sample > f_clk) or same rate (f_sample = +% f_clk). This tb guarantees that the VHDL agrees with the Matlab model. +% In the Matlab model the data blocks and data time are defined as: +% +% WG FIR with four taps FFT +% index t t +% 0 -1023 1023 2047 3071 4095 --> + --> -1023 +% . . . . . +% . . . . . +% -2 2 . . . -2 +% -1 1 . . . -1 +% 1023 0 0 1024 2048 3072 --> + --> 0 +% d h h h h d +% +% The waveform generator (WG) generates a block of 1024 samples with index +% 0:1023, where sample at index 1023 is the newest and sample at index 0 is +% the oldest. In a filter the newest sample needs to be multiplied with h[0] +% and the older samples are multiplied by the subsequent coefficients, +% because it is a convolution. Therefore the FIR coefficients need to be +% flipped up/down per column, to allow doing the filter as a d .* h vector +% multiply in pfir.m. The FFT operates on blocks of data with same index and +% time range as the WG. The data output of the FIR filter fits this input +% range of the FFT. Therefore no data flipping is needed. +% +% In the tb_verify_pfb_response.vhd the input stimuli is a block of N_fft = +% 1024 ones followed by N_taps-1 blocks with zeros. In time the oldest data +% will appear first in the simulator Wave Window, so therefore the +% fil_re_scope signal in the tb_verify_pfb_response.vhd will show the FIR +% coefficients h[] in order 1023:0, 2047:1024, ..., so flipped per block. +% clear all; close all; fig=0; @@ -205,7 +249,7 @@ if strcmp(tb.model_filterbank, 'LOFAR') ctrl_pfir_subband.nof_taps = 16; % Number of taps ctrl_pfir_subband.nof_coefficients = ctrl_pfir_subband.nof_polyphases*ctrl_pfir_subband.nof_taps; % Number of filter coefficients (taps) ctrl_pfir_subband.data_w = 16; - ctrl_pfir_subband.config.design = 'lofar file'; + ctrl_pfir_subband.config.design = 'lofar_file'; hfir_subband_coeff = load('data/Coeffs16384Kaiser-quant.dat'); hfir_subband_coeff = hfir_subband_coeff/max(hfir_subband_coeff); hfir_subband_coeff = hfir_subband_coeff'; % Use column vector, same format as by pfir_coeff() diff --git a/matlab/run_pfb.m b/matlab/run_pfb.m index 55455b2a997a28eeb1abccb1d175dca9f6eee1d0..30025d3cbd5dfbfb531b9f8b921d718b8c2ac506 100644 --- a/matlab/run_pfb.m +++ b/matlab/run_pfb.m @@ -236,6 +236,7 @@ x = fliplr(x); % Flip ctrl_pfir_subband.coeff per poly phase, because that is the order % in which the pfir() model and HDL expect the FIR coefficients +% See one_pfb.m for more detailed clarification. ctrl_pfir_subband.coeff = reshape(hfir_subband_coeff, ctrl_pfir_subband.nof_polyphases, ctrl_pfir_subband.nof_taps); ctrl_pfir_subband.coeff = flipud(ctrl_pfir_subband.coeff); ctrl_pfir_subband.Zdelays = zeros(ctrl_pfir_subband.nof_polyphases, ctrl_pfir_subband.nof_taps-1); diff --git a/matlab/run_pfb_complex.m b/matlab/run_pfb_complex.m index a9baa0a4a3508e13ea1d0d7bf1bf6f946947aec1..7716e4a640a0d884eed44e613b3d1a6a174ebbf0 100644 --- a/matlab/run_pfb_complex.m +++ b/matlab/run_pfb_complex.m @@ -203,7 +203,7 @@ hfir_channel_coeff = pfir_coeff(ctrl_pfir_channel.nof_polyphases, ... ctrl_pfir_channel.coeff_w, ... ctrl_pfir_channel.config); ctrl_pfir_channel.coeff = reshape(hfir_channel_coeff, ctrl_pfir_channel.nof_polyphases, ctrl_pfir_channel.nof_taps); -ctrl_pfir_channel.coeff = flipud(ctrl_pfir_channel.coeff); +ctrl_pfir_channel.coeff = flipud(ctrl_pfir_channel.coeff); % See one_pfb.m for more detailed clarification. ctrl_pfir_channel.Zdelays = zeros(ctrl_pfir_channel.nof_polyphases, ctrl_pfir_channel.nof_taps-1); ctrl_pfir_channel.gain = 1; % no gain adjustment in PFIR, just apply the coefficients to the input data