From 69c6b23717d46e32e232bc6f20b612f6335d5ef8 Mon Sep 17 00:00:00 2001
From: Eric Kooistra <kooistra@astron.nl>
Date: Thu, 3 Feb 2022 08:18:27 +0100
Subject: [PATCH] Clarified reading one WPFB unit into sp_subband_powers_arr2.
 Updated comments. No functional change. Improved release of pps_rst to reduce
 sim time.

---
 .../tb_lofar2_unb2b_sdp_station_fsub.vhd      | 257 +++++++++++-------
 1 file changed, 156 insertions(+), 101 deletions(-)

diff --git a/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_fsub/tb_lofar2_unb2b_sdp_station_fsub.vhd b/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_fsub/tb_lofar2_unb2b_sdp_station_fsub.vhd
index 89a6b269fc..49fb425c86 100644
--- a/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_fsub/tb_lofar2_unb2b_sdp_station_fsub.vhd
+++ b/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_fsub/tb_lofar2_unb2b_sdp_station_fsub.vhd
@@ -20,7 +20,7 @@
 
 -------------------------------------------------------------------------------
 --
--- Author: R. van der Walle
+-- Author: R. van der Walle (original), E. Kooistra (updates)
 -- Purpose: Self-checking testbench for simulating lofar2_unb2b_sdp_station_fsub using WG data.
 --
 -- Description:
@@ -34,39 +34,46 @@
 --      to trigger start of WG at BSN.
 --     
 --   3) Read subband statistics (SST) via ram_st_sst and verify with 
---      c_exp_subband_power_sp_0 at c_subband_sp_0.
---      View sp_subband_power_0  in Wave window
+--      c_exp_subband_power at g_subband.
+--      View sp_subband_power in Wave window
 --   
 --
 -- Usage:
 --   > as 7    # default
 --   > as 12   # for detailed debugging
---   > run -a  
+--   > run -a
+--   # Takes about 40 m
 --
 -------------------------------------------------------------------------------
 LIBRARY IEEE, common_lib, unb2b_board_lib, i2c_lib, mm_lib, dp_lib, diag_lib, lofar2_sdp_lib, wpfb_lib, lofar2_unb2b_sdp_station_lib;
 USE IEEE.std_logic_1164.ALL;
 USE IEEE.numeric_std.ALL;
-USE IEEE.MATH_REAL.ALL;
+USE IEEE.math_real.ALL;
 USE common_lib.common_pkg.ALL;
-USE unb2b_board_lib.unb2b_board_pkg.ALL;
 USE common_lib.tb_common_pkg.ALL;
 USE common_lib.common_str_pkg.ALL;
 USE mm_lib.mm_file_pkg.ALL;
-USE dp_lib.dp_stream_pkg.ALL;
 USE mm_lib.mm_file_unb_pkg.ALL;
+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 unb2b_board_lib.unb2b_board_pkg.ALL;
 
 ENTITY tb_lofar2_unb2b_sdp_station_fsub IS
+  GENERIC (
+    g_sp           : NATURAL := 3;    -- signal path index in range(S_pn = 12)
+    g_subband      : NATURAL := 102   -- select subband at index 102 = 102/1024 * 200MHz = 19.921875 MHz
+  );
 END tb_lofar2_unb2b_sdp_station_fsub;
 
 ARCHITECTURE tb OF tb_lofar2_unb2b_sdp_station_fsub IS
 
   CONSTANT c_sim             : BOOLEAN := TRUE;
   CONSTANT c_unb_nr          : NATURAL := 0; -- UniBoard 0
-  CONSTANT c_node_nr         : NATURAL := 0; 
+  CONSTANT c_node_nr         : NATURAL := 0;
+  CONSTANT c_init_bsn        : NATURAL := 17;  -- some recognizable value >= 0
+
   CONSTANT c_id              : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
   CONSTANT c_version         : STD_LOGIC_VECTOR(1 DOWNTO 0) := "00";
   CONSTANT c_fw_version      : t_unb2b_board_fw_version := (1, 0);
@@ -81,32 +88,39 @@ ARCHITECTURE tb OF tb_lofar2_unb2b_sdp_station_fsub IS
   CONSTANT c_nof_clk_per_sync    : NATURAL := c_nof_block_per_sync*c_sdp_N_fft - (c_sdp_N_fft/2); --15.5 block per sync
   CONSTANT c_pps_period          : NATURAL := c_nof_clk_per_sync;
   CONSTANT c_wpfb_sim            : t_wpfb := func_wpfb_set_nof_block_per_sync(c_sdp_wpfb_subbands, c_nof_block_per_sync);
-   
+  CONSTANT c_stat_data_sz        : NATURAL := c_wpfb_sim.stat_data_sz;  -- = 2
+
   CONSTANT c_percentage          : REAL := 0.05;  -- percentage that actual value may differ from expected value
   CONSTANT c_lo_factor           : REAL := 1.0 - c_percentage;  -- lower boundary  
   CONSTANT c_hi_factor           : REAL := 1.0 + c_percentage;  -- higher boundary
 
   -- WG
-  CONSTANT c_full_scale_ampl      : REAL := REAL(2**(14-1)-1);  -- = full scale of WG
-  CONSTANT c_bsn_start_wg         : NATURAL := 2;  -- start WG at this BSN to instead of some BSN, to avoid mismatches in exact expected data values
-  CONSTANT c_ampl_sp_0            : NATURAL := 2**(c_sdp_W_adc-1)/1;  -- in number of lsb
+  CONSTANT c_bsn_start_wg         : NATURAL := c_init_bsn + 2;  -- start WG at this BSN to instead of some BSN, to avoid mismatches in exact expected data values
+  -- .ampl
+  CONSTANT c_wg_ampl_full_scale   : NATURAL := 2**(c_sdp_W_adc-1);  -- full scale (FS) of WG, will just cause clipping of +FS to +FS-1
+  CONSTANT c_wg_ampl_lsb          : REAL := c_diag_wg_ampl_unit / REAL(c_wg_ampl_full_scale);  -- amplitude in number of LSbit resolution steps
+  CONSTANT c_wg_ampl              : NATURAL := c_wg_ampl_full_scale / 1;  -- in number of lsb
+  CONSTANT c_exp_wg_power_sp      : REAL := REAL(c_wg_ampl**2)/2.0 * REAL(c_nof_clk_per_sync);
+   -- . phase
+  CONSTANT c_wg_phase             : REAL := 0.0;  -- phase offset in degrees
+  -- . freq
   CONSTANT c_wg_subband_freq_unit : REAL := c_diag_wg_freq_unit/REAL(c_sdp_N_fft);  -- subband freq = Fs/1024 = 200 MSps/1024 = 195312.5 Hz sinus
-  CONSTANT c_wg_freq_offset       : REAL := 0.0/11.0; -- in freq_unit
-  CONSTANT c_subband_sp_0         : REAL := 102.0;  -- Select subband at index 102 = 102/1024 * 200MHz = 19.921875 MHz 
-  CONSTANT c_wg_ampl_lsb          : REAL := c_diag_wg_ampl_unit / c_full_scale_ampl;  -- amplitude in number of LSbit resolution steps
-  CONSTANT c_exp_wg_power_sp_0    : REAL := REAL(c_ampl_sp_0**2)/2.0 * REAL(c_nof_clk_per_sync);
 
   -- WPFB
-  CONSTANT c_nof_pfb                        : NATURAL := 1; -- Verifying 1 of c_sdp_P_pfb = 6 pfb to speed up simulation.
-  CONSTANT c_wb_leakage_bin                 : NATURAL := c_wpfb_sim.nof_points / c_wpfb_sim.wb_factor;   -- = 256, leakage will occur in this bin if FIR wb_factor is reversed 
-  CONSTANT c_exp_sp_subband_power_ratio     : REAL := 1.0/8.0;   -- depends on internal WPFB quantization and FIR coefficients
-  CONSTANT c_exp_sp_subband_power_sum_ratio : REAL := c_exp_sp_subband_power_ratio;   -- because all sinus power is expected in one subband
-  CONSTANT c_exp_subband_power_sp_0         : REAL := c_exp_wg_power_sp_0 * c_exp_sp_subband_power_ratio;
+  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_sp_power_ratio     : REAL := 1.0/8.0;   -- subband power / SP power, depends on internal WPFB quantization and FIR coefficients
+  CONSTANT c_exp_subband_power              : REAL := c_exp_wg_power_sp * c_exp_subband_sp_power_ratio;
 
   TYPE t_real_arr IS ARRAY (INTEGER RANGE <>) OF REAL; 
-  TyPE t_slv_64_subbands_arr IS ARRAY (INTEGER RANGE <>) OF t_slv_64_arr(0 TO c_sdp_N_sub);
+  TyPE t_slv_64_subbands_arr IS ARRAY (INTEGER RANGE <>) OF t_slv_64_arr(0 TO c_sdp_N_sub-1);
 
   -- MM  
+  -- . Address widths of a single MM instance
+  CONSTANT c_addr_w_reg_diag_wg           : NATURAL := 2;
+  -- . Address spans of a single MM instance
+  CONSTANT c_mm_span_reg_diag_wg          : NATURAL := 2**c_addr_w_reg_diag_wg;
+
   CONSTANT c_mm_file_reg_bsn_source_v2    : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SOURCE_V2";
   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";
@@ -118,23 +132,28 @@ ARCHITECTURE tb OF tb_lofar2_unb2b_sdp_station_fsub IS
   SIGNAL tb_clk              : STD_LOGIC := '0';  
   SIGNAL rd_data             : STD_LOGIC_VECTOR(c_32-1 DOWNTO 0) := (OTHERS => '0');
 
+  SIGNAL pps_rst             : STD_LOGIC := '1';
+  SIGNAL gen_pps             : STD_LOGIC := '0';
+
   -- WG
-  SIGNAL current_bsn_wg          : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
+  SIGNAL current_bsn_wg      : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
 
   -- WPFB
-  SIGNAL sp_subband_powers_arr2         : t_slv_64_subbands_arr(c_nof_pfb*c_nof_complex-1 DOWNTO 0);   -- [sp][sub]
-  SIGNAL sp_subband_power_0             : REAL;
-  SIGNAL sp_subband_power_sum           : t_real_arr(c_nof_pfb*c_nof_complex-1 DOWNTO 0) := (OTHERS=>0.0);
-  SIGNAL sp_subband_power_sum_0         : REAL;
-  SIGNAL sp_subband_power_ratio_0       : REAL;
-  SIGNAL sp_subband_power_sum_ratio_0   : REAL;
-  SIGNAL sp_subband_power_leakage_sum_0 : REAL;
-  
+  SIGNAL sp_subband_powers_arr2            : t_slv_64_subbands_arr(c_sdp_N_pol-1 DOWNTO 0);   -- [pol][sub]
+  SIGNAL sp_subband_power_sum_arr          : t_real_arr(c_sdp_N_pol-1 DOWNTO 0) := (OTHERS => 0.0);
+  SIGNAL sp_subband_power                  : REAL := 0.0;
+  SIGNAL sp_subband_power_leakage          : REAL := 0.0;
+  SIGNAL sp_subband_power_leakage_snr_dB   : REAL := 0.0;  -- signal to noise (leakage) ratio
+  SIGNAL sp_subband_power_crosstalk        : REAL := 0.0;
+  SIGNAL sp_subband_power_crosstalk_snr_dB : REAL := 0.0;  -- signal to noise (crosstalk) ration
+
+  -- . expected limit values, obtained with print_str() for g_subband = 102
+  CONSTANT c_exp_subband_power_leakage_snr_dB   : REAL := 75.0;  -- < 76.372
+  CONSTANT c_exp_subband_power_crosstalk_snr_dB : REAL := 95.0;  -- < 96.284
+
   -- DUT
   SIGNAL ext_clk             : STD_LOGIC := '0';
-  SIGNAL pps                 : STD_LOGIC := '0';
-  SIGNAL ext_pps             : STD_LOGIC := '0'; 
-  SIGNAL pps_rst             : STD_LOGIC := '0';
+  SIGNAL ext_pps             : STD_LOGIC := '0';
 
   SIGNAL WDI                 : STD_LOGIC;
   SIGNAL INTA                : STD_LOGIC;
@@ -176,9 +195,9 @@ BEGIN
   ------------------------------------------------------------------------------
   -- External PPS
   ------------------------------------------------------------------------------  
-  proc_common_gen_pulse(5, c_pps_period, '1', pps_rst, ext_clk, pps);
-  jesd204b_sysref <= pps;
-  ext_pps <= pps;
+  proc_common_gen_pulse(5, c_pps_period, '1', pps_rst, ext_clk, gen_pps);
+  jesd204b_sysref <= gen_pps;
+  ext_pps <= gen_pps;
 
   ------------------------------------------------------------------------------
   -- DUT
@@ -192,12 +211,12 @@ BEGIN
     g_sim_node_nr            => c_node_nr,
     g_wpfb                   => c_wpfb_sim,
     g_bsn_nof_clk_per_sync   => c_nof_clk_per_sync,
-    g_scope_selected_subband => NATURAL(c_subband_sp_0)
+    g_scope_selected_subband => g_subband
   )
   PORT MAP (
     -- GENERAL
     CLK          => ext_clk,
-    PPS          => pps,
+    PPS          => ext_pps,
     WDI          => WDI,
     INTA         => INTA,
     INTB         => INTB,
@@ -238,36 +257,41 @@ BEGIN
   tb_clk  <= NOT tb_clk AFTER c_tb_clk_period/2;    -- Testbench MM clock
   
   p_mm_stimuli : PROCESS
-    VARIABLE v_bsn                   : NATURAL;
-    VARIABLE v_sp_subband_power      : REAL;
-    VARIABLE v_W, v_T, v_U, v_S, v_B : NATURAL;  -- array indicies
+    VARIABLE v_bsn                        : NATURAL;
+    VARIABLE v_data_lo, v_data_hi         : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+    VARIABLE v_stat_data                  : STD_LOGIC_VECTOR(c_longword_w-1 DOWNTO 0);
+    VARIABLE v_len, v_span, v_offset, v_A : NATURAL;  -- address ranges, indices
+    VARIABLE v_W, v_P, v_U, v_S, v_B      : NATURAL;  -- array indicies
+    VARIABLE v_power                      : REAL;
   BEGIN
     -- Wait for DUT power up after reset
     WAIT FOR 1 us;
 
-    -- wait for pps
-    proc_common_wait_until_hi_lo(ext_clk, ext_pps);
- 
     ----------------------------------------------------------------------------
     -- Enable BSN
     ----------------------------------------------------------------------------
-    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 3,                    0, tb_clk);
-    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 2,                    0, tb_clk);  -- Init BSN = 0
-    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 1,   c_nof_clk_per_sync, tb_clk);  -- nof_block_per_sync
-    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 0,         16#00000003#, tb_clk);  -- Enable BSN at PPS
-    
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 2,         c_init_bsn, tb_clk);  -- Init BSN
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 3,                  0, tb_clk);  -- Write high part activates the init BSN
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 1, c_nof_clk_per_sync, tb_clk);  -- nof_block_per_sync
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 0,       16#00000003#, tb_clk);  -- Enable BSN at PPS
+
+    -- Release PPS pulser, to get first PPS now and to start BSN source
+    WAIT FOR 1 us;
+    pps_rst <= '0';
+
     ----------------------------------------------------------------------------
-    -- Enable WG
+    -- Enable and start WG
     ----------------------------------------------------------------------------
     --   0 : mode[7:0]           --> off=0, calc=1, repeat=2, single=3)
     --       nof_samples[31:16]  --> <= c_ram_wg_size=1024
     --   1 : phase[15:0]
     --   2 : freq[30:0]
     --   3 : ampl[16:0]
-    mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 0, 1024*2**16 + 1, tb_clk);  -- nof_samples, mode calc
-    mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 1, INTEGER(  0.0 * c_diag_wg_phase_unit), tb_clk);  -- phase offset in degrees
-    mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 2, INTEGER((c_subband_sp_0+c_wg_freq_offset) * c_wg_subband_freq_unit), tb_clk);  -- freq
-    mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 3, INTEGER(REAL(c_ampl_sp_0) * c_wg_ampl_lsb), tb_clk);  -- ampl
+    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_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_wg_ampl_lsb), tb_clk);  -- ampl
 
     -- Read current BSN
     mmf_mm_bus_rd(c_mm_file_reg_bsn_scheduler_wg, 0, current_bsn_wg(31 DOWNTO  0), tb_clk);
@@ -278,75 +302,106 @@ BEGIN
     v_bsn := TO_UINT(current_bsn_wg) + 2;
     ASSERT v_bsn <= c_bsn_start_wg REPORT "Too late to start WG: " & int_to_str(v_bsn) & " > " & int_to_str(c_bsn_start_wg) SEVERITY ERROR;
     mmf_mm_bus_wr(c_mm_file_reg_bsn_scheduler_wg, 0, c_bsn_start_wg, tb_clk);  -- first write low then high part
-    mmf_mm_bus_wr(c_mm_file_reg_bsn_scheduler_wg, 1,     0, tb_clk);  -- assume v_bsn < 2**31-1
+    mmf_mm_bus_wr(c_mm_file_reg_bsn_scheduler_wg, 1,              0, tb_clk);  -- assume v_bsn < 2**31-1
 
+    ----------------------------------------------------------------------------
     -- Wait for enough WG data and start of sync interval
-    
-    mmf_mm_wait_until_value(c_mm_file_reg_bsn_scheduler_wg, 0,                   -- read BSN low
-                            "UNSIGNED", rd_data, ">=", c_nof_block_per_sync * 3,   -- this is the wait until condition
+    ----------------------------------------------------------------------------
+    mmf_mm_wait_until_value(c_mm_file_reg_bsn_scheduler_wg, 0,                                 -- read BSN low
+                            "UNSIGNED", rd_data, ">=", c_init_bsn + c_nof_block_per_sync * 3,  -- this is the wait until condition
                             c_sdp_T_sub, tb_clk);
 
     ---------------------------------------------------------------------------
     -- Read subband statistics
     ---------------------------------------------------------------------------
-    -- . the subband statistics are c_wpfb_sim.stat_data_sz = 2 word power values.
-    -- . there are c_sdp_N_sub = 512 subbands per signal path
-    -- . one complex WPFB can process two real inputs A, B
+    -- . the subband statistics are c_stat_data_sz = 2 word power values.
+    -- . there are c_sdp_S_pn = 12 signal inputs A, B, C, D, E, F, G, H, I, J, K, L
+    -- . there are c_sdp_N_sub = 512 subbands per signal input (SI, = signal path, SP)
+    -- . one complex WPFB can process two real inputs A, B, so there are c_sdp_P_pfb = 6 WPFB units,
+    --   but only read for the 1 WPFB unit of the selected g_sp, to speed up simulation
+    -- . the outputs for A, B are time multiplexed, c_sdp_Q_fft = 2, assume that they
+    --   correspond to the c_sdp_N_pol = 2 signal polarizations
     -- . the subbands are output alternately so A0 B0 A1 B1 ... A511 B511 for input A, B
     -- . the subband statistics multiple WPFB units appear in order in the ram_st_sst address map
     -- . the subband statistics are stored first lo word 0 then hi word 1
-    
-    FOR I IN 0 TO c_nof_pfb*c_nof_complex*c_sdp_N_sub*c_wpfb_sim.stat_data_sz-1 LOOP
-      v_W := I MOD c_wpfb_sim.stat_data_sz;
-      v_T := (I / c_wpfb_sim.stat_data_sz) MOD c_nof_complex;
-      v_U := I / (c_nof_complex*c_wpfb_sim.stat_data_sz*c_sdp_N_sub);
-      v_S := v_T + v_U * c_nof_complex;
-      v_B := (I / (c_nof_complex*c_wpfb_sim.stat_data_sz)) MOD c_sdp_N_sub;
-      IF v_W=0 THEN
+    v_len := c_sdp_N_sub * c_sdp_N_pol * c_stat_data_sz;  -- 2048 = 512 * 2 * 64/32
+    v_span := true_log_pow2(v_len);                       -- = 2048
+    FOR I IN 0 TO v_len - 1 LOOP
+      v_W := I MOD c_stat_data_sz;                   -- 0, 1 per statistics word, word index
+      v_P := (I / c_stat_data_sz) MOD c_sdp_N_pol;   -- 0, 1 per SP pol, polarization index
+      v_B := I / (c_sdp_N_pol * c_stat_data_sz);     -- subband index, range(N_sub = 512) per dual pol
+      v_A := I + c_pfb_index * v_span;               -- MM address for WPFB unit of selected g_sp
+      IF v_W = 0 THEN
         -- low part
-        mmf_mm_bus_rd(c_mm_file_ram_st_sst, I, rd_data, tb_clk);
-        sp_subband_powers_arr2(v_S)(v_B)(31 DOWNTO 0) <= rd_data;
-      ELSE      
+        mmf_mm_bus_rd(c_mm_file_ram_st_sst, v_A, rd_data, tb_clk);
+        v_data_lo := rd_data;
+      ELSE
         -- high part
-        mmf_mm_bus_rd(c_mm_file_ram_st_sst, I, rd_data, tb_clk);
-        sp_subband_powers_arr2(v_S)(v_B)(63 DOWNTO 32) <= rd_data;
-
-        -- Convert STD_LOGIC_VECTOR to REAL
-        v_sp_subband_power := REAL(TO_UINT(rd_data(29 DOWNTO 0) & 
-            sp_subband_powers_arr2(v_S)(v_B)(31 DOWNTO 30)))*2.0**30 + 
-            REAL(TO_UINT(sp_subband_powers_arr2(v_S)(v_B)(29 DOWNTO 0)));
-        -- sum
-        sp_subband_power_sum(v_S) <= sp_subband_power_sum(v_S) + v_sp_subband_power;
+        mmf_mm_bus_rd(c_mm_file_ram_st_sst, v_A, rd_data, tb_clk);
+        v_data_hi := rd_data;
+        v_stat_data := v_data_hi & v_data_lo;
+
+        sp_subband_powers_arr2(v_P)(v_B) <= v_stat_data;
+
+        -- sum of all subband powers per pol
+        sp_subband_power_sum_arr(v_P) <= sp_subband_power_sum_arr(v_P) + TO_UREAL(v_stat_data);
       END IF;
     END LOOP;
 
-    -- sp_subband_power_sum is the sum of all subband powers per SP, this value will be close to sp_subband_power
-    -- because the input is a sinus, so most power will be in 1 subband. The sp_subband_power_leakage_sum shows
-    -- how much power from the input sinus at a specific subband has leaked into the 511 other subbands.
-    sp_subband_power_0 <= REAL(TO_UINT(sp_subband_powers_arr2(0)(INTEGER(ROUND(c_subband_sp_0)))(61 DOWNTO 30)))*2.0**30 + 
-        REAL(TO_UINT(sp_subband_powers_arr2(0)(INTEGER(ROUND(c_subband_sp_0)))(29 DOWNTO 0)));
+    -- Subband power of g_subband in g_sp
+    -- . For the selected g_subband in g_sp the sp_subband_power will be close
+    --   to sp_subband_power_sum_arr(c_pol_index), because the input is a
+    --   sinus, so most power will be in 1 subband.
+    sp_subband_power <= TO_UREAL(sp_subband_powers_arr2(c_pol_index)(g_subband));
+    proc_common_wait_some_cycles(tb_clk, 1);
+
+    -- The sp_subband_power_leakage shows how much power from the input sinus at a specific
+    -- subband has leaked into the N_sub - 1 = 511 other subbands. The power ratio yields an
+    -- indication of the SNR, although that also depends on the SNR of the WG sinus.
+    v_power := sp_subband_power_sum_arr(c_pol_index) - sp_subband_power;
+    sp_subband_power_leakage <= v_power;
+    IF v_power > 0.0 THEN
+      sp_subband_power_leakage_snr_dB <= 10.0 * LOG10(sp_subband_power / v_power);
+    ELSE
+      REPORT "Wrong, zero leakage is unexpected for SP-" & NATURAL'IMAGE(g_sp) SEVERITY ERROR;
+    END IF;
+
+    -- The sp_subband_power_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_power_sum_arr(not_int(c_pol_index));
+    sp_subband_power_crosstalk <= v_power;
+    IF v_power > 0.0 THEN
+      sp_subband_power_crosstalk_snr_dB <= 10.0 * LOG10(sp_subband_power / v_power);
+    ELSE
+      REPORT "Wrong, zero crosstalk is unexpected for SP-" & NATURAL'IMAGE(g_sp) SEVERITY ERROR;
+    END IF;
 
-    sp_subband_power_sum_0 <= sp_subband_power_sum(0);
-    
     proc_common_wait_some_cycles(tb_clk, 1);
 
+    ---------------------------------------------------------------------------
+    -- Print subband statistics
+    ---------------------------------------------------------------------------
+    print_str("sp_subband_power                   = " & real_to_str(sp_subband_power, 20, 0));
+
+    -- WPFB details are allready verified in tb of wpfb_unit_dev.vhd, so here
+    -- quality indicators like leakage and crosstalk are also reported out of
+    -- interest.
+    print_str("sp_subband_power_leakage           = " & real_to_str(sp_subband_power_leakage, 20, 0));
+    print_str("sp_subband_power_leakage_snr_dB    = " & real_to_str(sp_subband_power_leakage_snr_dB, 20, 3));
+    print_str("sp_subband_power_crosstalk         = " & real_to_str(sp_subband_power_crosstalk, 20, 0));
+    print_str("sp_subband_power_crosstalk_snr_db  = " & real_to_str(sp_subband_power_crosstalk_snr_db, 20, 3));
+
     ---------------------------------------------------------------------------
     -- Verify subband statistics
     ---------------------------------------------------------------------------  
     -- verify expected subband power based on WG power
-    IF sp_subband_power_sum_0>0.0 THEN ASSERT sp_subband_power_0 > c_lo_factor * c_exp_subband_power_sp_0 REPORT "Wrong subband power for SP 0" SEVERITY ERROR; END IF;
-    IF sp_subband_power_sum_0>0.0 THEN ASSERT sp_subband_power_0 < c_hi_factor * c_exp_subband_power_sp_0 REPORT "Wrong subband power for SP 0" SEVERITY ERROR; END IF;
-    
-    -- view c_exp_sp_subband_power_ratio in Wave window
-    IF sp_subband_power_sum_0>0.0 THEN sp_subband_power_ratio_0 <= sp_subband_power_0/sp_subband_power_sum_0; END IF;
-    
-    -- view c_exp_sp_subband_power_sum_ratio in Wave window
-    -- The sp_subband_power_sum_ratio show similar information as sp_subband_power_leakage_sum, because when
-    -- sp_subband_power_leakage_sum is small then sp_subband_power_sum_ratio ~= sp_subband_power_ratio.
-    IF sp_subband_power_sum_0>0.0 THEN sp_subband_power_sum_ratio_0 <= sp_subband_power_sum_0/sp_subband_power_0; END IF;
+    ASSERT sp_subband_power > c_lo_factor * c_exp_subband_power REPORT "Wrong subband power for SP-" & NATURAL'IMAGE(g_sp) SEVERITY ERROR;
+    ASSERT sp_subband_power < c_hi_factor * c_exp_subband_power REPORT "Wrong subband power for SP-" & NATURAL'IMAGE(g_sp) SEVERITY ERROR;
 
-    -- View sp_subband_power_leakage_sum in Wave window
-    IF sp_subband_power_sum_0>0.0 THEN sp_subband_power_leakage_sum_0 <= sp_subband_power_sum_0 - sp_subband_power_0; END IF;
+    -- Verify expected SNR quality measures
+    ASSERT sp_subband_power_leakage_snr_dB   > c_exp_subband_power_leakage_snr_dB   REPORT "Wrong to much leakage for SP-" & NATURAL'IMAGE(g_sp) SEVERITY ERROR;
+    ASSERT sp_subband_power_crosstalk_snr_dB > c_exp_subband_power_crosstalk_snr_dB REPORT "Wrong to much crosstalk for SP-" & NATURAL'IMAGE(g_sp) SEVERITY ERROR;
 
     ---------------------------------------------------------------------------
     -- End Simulation 
-- 
GitLab