diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd index a22fd834f9ef73e68976c18c5bc16c31cb4f0cef..322ebe95addbe9d3bfa6b4b75a559be9f9a22445 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd @@ -35,6 +35,9 @@ -- -- 3) Read subband statistics (SST) via MM and verify with exp_subband_sst at g_subband. -- . use weighted subbands (default selected by MM) +-- . g_use_cross_weight = TRUE, then use g_cross_weight_gain/phase and c_cross_sp +-- . g_use_cross_weight = FALSE, then do not use c_cross_sp, so only use g_sp and +-- g_subband_weight_gain/phase -- -- 4) View in wave window -- . in_sosi.sop and in_data in u_si_arr(g_sp) to check that: @@ -71,15 +74,19 @@ USE dp_lib.dp_stream_pkg.ALL; USE diag_lib.diag_pkg.ALL; USE wpfb_lib.wpfb_pkg.ALL; USE lofar2_sdp_lib.sdp_pkg.ALL; +USE lofar2_sdp_lib.tb_sdp_pkg.ALL; USE unb2c_board_lib.unb2c_board_pkg.ALL; ENTITY tb_lofar2_unb2c_sdp_station_fsub IS GENERIC ( g_sp : NATURAL := 3; -- signal path index in range(S_pn = 12) - g_wg_ampl : REAL := 1.0; -- WG normalized amplitude + g_wg_ampl : REAL := 0.5; -- WG normalized amplitude, use same WG settings for both polarizations (g_sp and c_cross_sp) g_subband : NATURAL := 102; -- select subband at index 102 = 102/1024 * 200MHz = 19.921875 MHz - g_subband_weight_gain : REAL := 1.0; -- subband weight normalized gain - g_subband_weight_phase : REAL := 30.0; -- subband weight phase rotation in degrees + g_subband_weight_gain : REAL := 1.0; -- subband weight normalized gain, for co-polarization in g_sp + g_subband_weight_phase : REAL := 30.0; -- subband weight phase rotation in degrees, for co-polarization in g_sp + g_use_cross_weight : BOOLEAN := TRUE; + g_cross_weight_gain : REAL := 0.5; -- subband weight normalized gain, for cross polarization of g_sp + g_cross_weight_phase : REAL := 30.0; -- subband weight phase rotation in degrees, for cross polarization of g_sp g_read_all_SST : BOOLEAN := TRUE -- when FALSE only read SST for g_subband, to save sim time ); END tb_lofar2_unb2c_sdp_station_fsub; @@ -90,6 +97,7 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub IS CONSTANT c_unb_nr : NATURAL := 0; -- UniBoard 0 CONSTANT c_node_nr : NATURAL := 0; CONSTANT c_init_bsn : NATURAL := 17; -- some recognizable value >= 0 + CONSTANT c_cross_sp : NATURAL := sel_a_b(g_sp MOD c_sdp_N_pol = 0, g_sp + 1, g_sp - 1); CONSTANT c_id : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000"; CONSTANT c_version : STD_LOGIC_VECTOR(1 DOWNTO 0) := "00"; @@ -125,11 +133,15 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub IS CONSTANT c_wg_phase : REAL := c_subband_phase + c_wg_phase_offset; -- WG phase in degrees -- FSUB - -- . WPFB CONSTANT c_pol_index : NATURAL := g_sp MOD c_sdp_Q_fft; CONSTANT c_pfb_index : NATURAL := g_sp / c_sdp_Q_fft; -- only read used WPFB unit out of range(c_sdp_P_pfb = 6) + CONSTANT c_exp_subband_ampl_raw : REAL := REAL(c_wg_ampl) * c_sdp_wpfb_subband_sp_ampl_ratio; - CONSTANT c_exp_subband_ampl_weighted : REAL := c_exp_subband_ampl_raw * g_subband_weight_gain; + CONSTANT c_exp_subband_tuple : t_real_arr(0 TO 3) := func_sdp_subband_equalizer( + c_exp_subband_ampl_raw, c_subband_phase, g_subband_weight_gain, g_subband_weight_phase, + c_exp_subband_ampl_raw, c_subband_phase, g_cross_weight_gain, g_cross_weight_phase); + CONSTANT c_exp_subband_ampl_weighted : REAL := sel_a_b(g_use_cross_weight, c_exp_subband_tuple(0), c_exp_subband_ampl_raw * g_subband_weight_gain); + CONSTANT c_exp_subband_power_raw : REAL := c_exp_subband_ampl_raw**2.0; -- complex signal ampl, so power is A**2 (not A**2 / 2 as for real) CONSTANT c_exp_subband_power_weighted : REAL := c_exp_subband_ampl_weighted**2.0; -- complex signal ampl, so power is A**2 (not A**2 / 2 as for real) CONSTANT c_exp_subband_sst_raw : REAL := c_exp_subband_power_raw * REAL(c_nof_block_per_sync); @@ -147,6 +159,10 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub IS CONSTANT c_subband_weight_re : INTEGER := INTEGER(g_subband_weight_gain * REAL(c_sdp_unit_sub_weight) * COS(g_subband_weight_phase * MATH_2_PI / 360.0)); CONSTANT c_subband_weight_im : INTEGER := INTEGER(g_subband_weight_gain * REAL(c_sdp_unit_sub_weight) * SIN(g_subband_weight_phase * MATH_2_PI / 360.0)); + -- . Subband weights cross for selected g_sp + CONSTANT c_cross_subband_weight_re : INTEGER := INTEGER(g_cross_weight_gain * REAL(c_sdp_unit_sub_weight) * COS(g_cross_weight_phase * MATH_2_PI / 360.0)); + CONSTANT c_cross_subband_weight_im : INTEGER := INTEGER(g_cross_weight_gain * REAL(c_sdp_unit_sub_weight) * SIN(g_cross_weight_phase * MATH_2_PI / 360.0)); + -- MM -- . Address widths of a single MM instance CONSTANT c_addr_w_reg_diag_wg : NATURAL := 2; @@ -157,6 +173,7 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub IS CONSTANT c_mm_file_reg_bsn_scheduler_wg : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SCHEDULER"; CONSTANT c_mm_file_reg_diag_wg : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_WG"; CONSTANT c_mm_file_ram_equalizer_gains : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "RAM_EQUALIZER_GAINS"; + CONSTANT c_mm_file_ram_equalizer_gains_cross : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "RAM_EQUALIZER_GAINS_CROSS"; CONSTANT c_mm_file_reg_dp_selector : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_DP_SELECTOR"; CONSTANT c_mm_file_ram_st_sst : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "RAM_ST_SST"; @@ -179,6 +196,7 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub IS SIGNAL sp_subband_sst : REAL := 0.0; SIGNAL sp_subband_sst_leakage : REAL := 0.0; SIGNAL sp_subband_sst_leakage_snr_dB : REAL := 0.0; -- signal to noise (leakage) ratio + SIGNAL sp_subband_sst_cross : REAL := 0.0; SIGNAL sp_subband_sst_crosstalk : REAL := 0.0; SIGNAL sp_subband_sst_crosstalk_snr_dB : REAL := 0.0; -- signal to noise (crosstalk) ration @@ -195,6 +213,13 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub IS SIGNAL sp_subband_weight_im : INTEGER := 0; SIGNAL sp_subband_weight_gain : REAL := 0.0; SIGNAL sp_subband_weight_phase : REAL := 0.0; + SIGNAL sp_subband_weight_val : STD_LOGIC := '0'; + + SIGNAL cross_subband_weight_re : INTEGER := 0; + SIGNAL cross_subband_weight_im : INTEGER := 0; + SIGNAL cross_subband_weight_gain : REAL := 0.0; + SIGNAL cross_subband_weight_phase : REAL := 0.0; + SIGNAL cross_subband_weight_val : STD_LOGIC := '0'; -- DUT SIGNAL ext_clk : STD_LOGIC := '0'; @@ -327,12 +352,22 @@ BEGIN -- 1 : phase[15:0] -- 2 : freq[30:0] -- 3 : ampl[16:0] + -- g_sp is co-polarization v_offset := g_sp * c_mm_span_reg_diag_wg; mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 0, 1024*2**16 + 1, tb_clk); -- nof_samples, mode calc mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 1, INTEGER(c_wg_phase * c_diag_wg_phase_unit), tb_clk); -- phase offset in degrees mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 2, INTEGER(REAL(g_subband) * c_sdp_wg_subband_freq_unit), tb_clk); -- freq mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 3, INTEGER(REAL(c_wg_ampl) * c_sdp_wg_ampl_lsb), tb_clk); -- ampl + IF g_use_cross_weight THEN + -- c_cross_sp is cross-polarization for g_sp, use same WG settings for c_cross_sp as for g_sp + v_offset := c_cross_sp * c_mm_span_reg_diag_wg; + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 0, 1024*2**16 + 1, tb_clk); -- nof_samples, mode calc + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 1, INTEGER(c_wg_phase * c_diag_wg_phase_unit), tb_clk); -- phase offset in degrees + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 2, INTEGER(REAL(g_subband) * c_sdp_wg_subband_freq_unit), tb_clk); -- freq + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 3, INTEGER(REAL(c_wg_ampl) * c_sdp_wg_ampl_lsb), tb_clk); -- ampl + END IF; + -- Read current BSN mmf_mm_bus_rd(c_mm_file_reg_bsn_scheduler_wg, 0, current_bsn_wg(31 DOWNTO 0), tb_clk); mmf_mm_bus_rd(c_mm_file_reg_bsn_scheduler_wg, 1, current_bsn_wg(63 DOWNTO 32), tb_clk); @@ -347,6 +382,8 @@ BEGIN ---------------------------------------------------------------------------- -- Write subband weight for selected g_sp and g_subband ---------------------------------------------------------------------------- + + -- Co-polarization subband weight for g_sp -- . MM format: (cint16)RAM_EQUALIZER_GAINS[S_pn/Q_fft]_[Q_fft][N_sub] = [S_pn][N_sub] v_addr := g_sp * c_sdp_N_sub + g_subband; -- . read @@ -357,6 +394,10 @@ BEGIN sp_subband_weight_im <= v_im; sp_subband_weight_gain <= SQRT(REAL(v_re)**2.0 + REAL(v_im)**2.0) / REAL(c_sdp_unit_sub_weight); sp_subband_weight_phase <= atan2(Y => REAL(v_im), X => REAL(v_re)) * 360.0 / MATH_2_PI; + sp_subband_weight_val <= '1'; + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT sp_subband_weight_re = c_sdp_unit_sub_weight REPORT "Default sp_subband_weight_re /= c_sdp_unit_sub_weight" SEVERITY ERROR; + ASSERT sp_subband_weight_im = 0 REPORT "Default sp_subband_weight_im /= 0" SEVERITY ERROR; -- . write v_weight := pack_complex(re => c_subband_weight_re, im => c_subband_weight_im, w => c_sdp_W_sub_weight); -- c_sdp_W_sub_weight = 16 bit mmf_mm_bus_wr(c_mm_file_ram_equalizer_gains, v_addr, v_weight, tb_clk); @@ -368,6 +409,39 @@ BEGIN sp_subband_weight_im <= v_im; sp_subband_weight_gain <= SQRT(REAL(v_re)**2.0 + REAL(v_im)**2.0) / REAL(c_sdp_unit_sub_weight); sp_subband_weight_phase <= atan2(Y => REAL(v_im), X => REAL(v_re)) * 360.0 / MATH_2_PI; + ASSERT sp_subband_weight_re = c_subband_weight_re REPORT "Readback sp_subband_weight_re /= c_subband_weight_re" SEVERITY ERROR; + ASSERT sp_subband_weight_im = c_subband_weight_im REPORT "Readback sp_subband_weight_im /= c_subband_weight_im" SEVERITY ERROR; + + IF g_use_cross_weight THEN + -- Cross-polarization subband weight for g_sp + -- . MM format: (cint16)RAM_EQUALIZER_GAINS_CROSS[S_pn/Q_fft]_[Q_fft][N_sub] = [S_pn][N_sub] + v_addr := g_sp * c_sdp_N_sub + g_subband; + -- . read + mmf_mm_bus_rd(c_mm_file_ram_equalizer_gains_cross, v_addr, rd_data, tb_clk); + v_re := unpack_complex_re(rd_data, c_sdp_W_sub_weight); + v_im := unpack_complex_im(rd_data, c_sdp_W_sub_weight); + cross_subband_weight_re <= v_re; + cross_subband_weight_im <= v_im; + cross_subband_weight_gain <= SQRT(REAL(v_re)**2.0 + REAL(v_im)**2.0) / REAL(c_sdp_unit_sub_weight); + cross_subband_weight_phase <= atan2(Y => REAL(v_im), X => REAL(v_re)) * 360.0 / MATH_2_PI; + cross_subband_weight_val <= '1'; + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT cross_subband_weight_re = 0 REPORT "Default cross_subband_weight_re /= 0" SEVERITY ERROR; + ASSERT cross_subband_weight_im = 0 REPORT "Default cross_subband_weight_im /= 0" SEVERITY ERROR; + -- . write + v_weight := pack_complex(re => c_cross_subband_weight_re, im => c_cross_subband_weight_im, w => c_sdp_W_sub_weight); -- c_sdp_W_sub_weight = 16 bit + mmf_mm_bus_wr(c_mm_file_ram_equalizer_gains_cross, v_addr, v_weight, tb_clk); + -- . read back + mmf_mm_bus_rd(c_mm_file_ram_equalizer_gains_cross, v_addr, rd_data, tb_clk); + v_re := unpack_complex_re(rd_data, c_sdp_W_sub_weight); + v_im := unpack_complex_im(rd_data, c_sdp_W_sub_weight); + cross_subband_weight_re <= v_re; + cross_subband_weight_im <= v_im; + cross_subband_weight_gain <= SQRT(REAL(v_re)**2.0 + REAL(v_im)**2.0) / REAL(c_sdp_unit_sub_weight); + cross_subband_weight_phase <= atan2(Y => REAL(v_im), X => REAL(v_re)) * 360.0 / MATH_2_PI; + ASSERT cross_subband_weight_re = c_cross_subband_weight_re REPORT "Readback cross_subband_weight_re /= c_cross_subband_weight_re" SEVERITY ERROR; + ASSERT cross_subband_weight_im = c_cross_subband_weight_im REPORT "Readback cross_subband_weight_im /= c_cross_subband_weight_im" SEVERITY ERROR; + END IF; ---------------------------------------------------------------------------- -- Wait for enough WG data and start of sync interval @@ -423,6 +497,8 @@ BEGIN -- to sp_subband_sst_sum_arr(c_pol_index), because the input is a -- sinus, so most power will be in 1 subband. sp_subband_sst <= TO_UREAL(sp_subband_ssts_arr2(c_pol_index)(g_subband)); + -- Subband power of g_subband in c_cross_sp + sp_subband_sst_cross <= TO_UREAL(sp_subband_ssts_arr2(not_int(c_pol_index))(g_subband)); proc_common_wait_some_cycles(tb_clk, 1); -- The sp_subband_sst_leakage shows how much power from the input sinus at a specific @@ -436,15 +512,18 @@ BEGIN REPORT "Wrong, zero leakage is unexpected for SP-" & NATURAL'IMAGE(g_sp) SEVERITY ERROR; END IF; - -- The sp_subband_sst_crosstalk shows how much power from one WPFB input cross talks - -- into the other output, due to quantization cross talk in the complex FFT. The power - -- ration indicates the suppression, provided that the other input was zero. - v_power := sp_subband_sst_sum_arr(not_int(c_pol_index)); - sp_subband_sst_crosstalk <= v_power; - IF sp_subband_sst > c_eps AND v_power > c_eps THEN - sp_subband_sst_crosstalk_snr_dB <= 10.0 * LOG10(sp_subband_sst / v_power); - ELSIF g_read_all_SST THEN - REPORT "Zero crosstalk for SP-" & NATURAL'IMAGE(g_sp) SEVERITY NOTE; + IF NOT g_use_cross_weight THEN + -- The other WPFB input WG at c_cross_sp is not used, so it should have ~ zero power. + -- The sp_subband_sst_crosstalk shows how much power from one WPFB input cross talks + -- into the other output, due to quantization cross talk in the complex FFT. The power + -- ration indicates the suppression, provided that the other input was zero. + v_power := sp_subband_sst_sum_arr(not_int(c_pol_index)); -- not_int(0) = 1, not_int(/= 0) = 0 + sp_subband_sst_crosstalk <= v_power; + IF sp_subband_sst > c_eps AND v_power > c_eps THEN + sp_subband_sst_crosstalk_snr_dB <= 10.0 * LOG10(sp_subband_sst / v_power); + ELSIF g_read_all_SST THEN + REPORT "Zero crosstalk for SP-" & NATURAL'IMAGE(g_sp) SEVERITY NOTE; + END IF; END IF; proc_common_wait_some_cycles(tb_clk, 10); @@ -466,6 +545,10 @@ BEGIN print_str("Subband weight:"); print_str(". sp_subband_weight_gain = " & real_to_str(sp_subband_weight_gain, 20, 6)); print_str(". sp_subband_weight_phase = " & real_to_str(sp_subband_weight_phase, 20, 6)); + IF g_use_cross_weight THEN + print_str(". cross_subband_weight_gain = " & real_to_str(cross_subband_weight_gain, 20, 6)); + print_str(". cross_subband_weight_phase = " & real_to_str(cross_subband_weight_phase, 20, 6)); + END IF; print_str(""); print_str("SST results:"); @@ -490,9 +573,16 @@ BEGIN --------------------------------------------------------------------------- -- Verify SST --------------------------------------------------------------------------- - -- verify expected subband power based on WG power + -- Verify expected subband power based on WG power for g_sp ASSERT sp_subband_sst > c_lo_factor * exp_subband_sst REPORT "Wrong subband power for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; ASSERT sp_subband_sst < c_hi_factor * exp_subband_sst REPORT "Wrong subband power for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + IF g_use_cross_weight THEN + -- Verify expected subband power based on WG power for c_cross_sp + -- The other WPFB input WG at c_cross_sp is used as cross polarization input, with default + -- unit co-polarization subband weight and zero cross-polarization subband weight. + ASSERT sp_subband_sst_cross > c_lo_factor * c_exp_subband_sst_raw REPORT "Wrong subband power for cross SP " & NATURAL'IMAGE(c_cross_sp) SEVERITY ERROR; + ASSERT sp_subband_sst_cross < c_hi_factor * c_exp_subband_sst_raw REPORT "Wrong subband power for cross SP " & NATURAL'IMAGE(c_cross_sp) SEVERITY ERROR; + END IF; IF g_read_all_SST THEN -- Verify expected SNR quality measures