From 43f096a5f7dc205754f7bb9ca101876ec038507c Mon Sep 17 00:00:00 2001
From: Eric Kooistra <kooistra@astron.nl>
Date: Thu, 10 Mar 2022 09:09:45 +0100
Subject: [PATCH] Added remnant signal input settings to also verify the BF
 summator.

---
 .../tb_lofar2_unb2c_sdp_station_bf.vhd        | 267 ++++++++++++------
 1 file changed, 179 insertions(+), 88 deletions(-)

diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd
index 890adcf128..c641685358 100644
--- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd
+++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd
@@ -26,22 +26,29 @@
 --
 -- Description:
 --   This tb is a balance between verification coverage and keeping it simple:
---   - Use only one signal input (g_sp), put small unused signal on the other
---     signal inputs.
---   - Use different BF weight for the two beamlet polarizations (g_bf_*_gain,
---     and g_bf_*_phase) of signal input g_sp. Keep BF weight for the other
---     signal inputs = 0 to block them from the beamlet.
---   - Select one beamlet for the subband (g_beamlet).
+--   - Use only one signal input (g_sp). Put same remnant WG signal on the
+--     other signal inputs.
+--   - Use different BF weight for the two beamlet polarizations (g_bf_x_gain,
+--     g_bf_x_phase and g_bf_y_phase, g_bf_y_phase) of signal input g_sp.
+--     Using different BF weights for the N_pol_bf = 2 BF polarizations allows
+--     verification of the dual polarization beamlet.
+--   - Use same remnant BF weight for the other S_pn - 1 = 11 signal inputs.
+--     The remnant signal inputs and BF weights allow verifying the BF sum if
+--     they are not 0. Using the same settings for all remnant SP simplyfies
+--     the tb, while still testing the BF sum.
+--   - Select one beamlet for the subband (g_beamlet). Selecting one beamlet
+--     other than the default beamlet for the subband is sufficient to verify
+--     the beamlet subband select.
 --   - Use same stimuli for both beamsets.
 --
 --   MM control actions:
 --
 --   1) Enable calc mode for WG on signal input (si) g_sp via reg_diag_wg with:
 --        g_subband = 102 --> 102 * f_sub = 19.921875 MHz
---        g_wg_ampl = 1.0 --> 1.0 yield WG ampl = 2**13
---        g_wg_phase --> subband phase
---      Use g_unused_ampl = 0.1 and g_unused_phase = 0.0 for the other signal
---      inputs, that are not used in the BF.
+--        g_sp_ampl = 1.0 --> 1.0 yield WG ampl = 2**13
+--        g_sp_phase --> subband phase
+--      Use g_sp_remnant_ampl = 0.1 and g_sp_remnant_phase = 0.0 for the other
+--      S_pn-1 = 11 signal inputs, than g_sp, that are not used in the BF.
 --   
 --   2) Read current BSN from reg_bsn_scheduler_wg and write
 --      reg_bsn_scheduler_wg to trigger start of WG at BSN.
@@ -95,6 +102,10 @@
 --        View rx_beamlet_sosi
 --        View rx_beamlet_cnt (in analog format)
 --
+-- Remark:
+-- . The c_wg_phase_offset and c_subband_phase_offset are used to tune the WG
+--   phase reference to 0.0 degrees at the start (sop)
+--
 -- Usage:
 --   > as 7    # default
 --   > as 12   # for detailed debugging
@@ -129,37 +140,41 @@ USE tech_pll_lib.tech_pll_component_pkg.ALL;
 
 ENTITY tb_lofar2_unb2c_sdp_station_bf IS
   GENERIC (
-    g_sp                : NATURAL := 3;     -- WG signal path index in range(S_pn = 12)
-    g_wg_ampl           : REAL := 1.0;      -- WG normalized amplitude
-    g_wg_phase          : REAL := 0.0;      -- WG phase in degrees = subband phase
-    g_unused_ampl       : REAL := 0.1;      -- WG normalized amplitude for unused sp
-    g_unused_phase      : REAL := 0.0;      -- WG phase in degrees for unused sp
-    g_subband           : NATURAL := 102;   -- select g_subband at index 102 = 102/1024 * 200MHz = 19.921875 MHz
-    g_beamlet           : NATURAL := 10;    -- map g_subband to g_beamlet index in beamset in range(c_sdp_S_sub_bf = 488)
-    g_beamlet_scale     : REAL := 1.0 / 2.0**9;  -- g_beamlet output scale factor
-    g_bf_x_gain         : REAL := 0.7;       -- g_beamlet X BF weight normalized gain
-    g_bf_y_gain         : REAL := 0.6;       -- g_beamlet Y BF weight normalized gain
-    g_bf_x_phase        : REAL := 30.0;      -- g_beamlet X BF weight phase rotation in degrees
-    g_bf_y_phase        : REAL := 40.0;      -- g_beamlet Y BF weight phase rotation in degrees
-    g_read_all_SST      : BOOLEAN := FALSE;  -- when FALSE only read SST for g_subband, to save sim time
-    g_read_all_BST      : BOOLEAN := FALSE   -- when FALSE only read BST for g_beamlet, to save sim time
+    g_sp                 : NATURAL := 3;      -- WG signal path (SP) index in range(S_pn = 12)
+    g_sp_ampl            : REAL := 0.5;       -- WG normalized amplitude
+    g_sp_phase           : REAL := -110.0;      -- WG phase in degrees = subband phase
+    g_sp_remnant_ampl    : REAL := 0.1;       -- WG normalized amplitude for remnant sp
+    g_sp_remnant_phase   : REAL := 15.0;      -- WG phase in degrees for remnant sp
+    g_subband            : NATURAL := 102;    -- select g_subband at index 102 = 102/1024 * 200MHz = 19.921875 MHz
+    g_beamlet            : NATURAL := 10;     -- map g_subband to g_beamlet index in beamset in range(c_sdp_S_sub_bf = 488)
+    g_beamlet_scale      : REAL := 1.0 / 2.0**9;  -- g_beamlet output scale factor
+    g_bf_x_gain          : REAL := 0.7;       -- g_beamlet X BF weight normalized gain for g_sp
+    g_bf_y_gain          : REAL := 0.6;       -- g_beamlet Y BF weight normalized gain for g_sp
+    g_bf_x_phase         : REAL := 30.0;      -- g_beamlet X BF weight phase rotation in degrees for g_sp
+    g_bf_y_phase         : REAL := 40.0;      -- g_beamlet Y BF weight phase rotation in degrees for g_sp
+    g_bf_remnant_x_gain  : REAL := 0.05;       -- g_beamlet X BF weight normalized gain for remnant sp
+    g_bf_remnant_y_gain  : REAL := 0.04;       -- g_beamlet Y BF weight normalized gain for remnant sp
+    g_bf_remnant_x_phase : REAL := 170.0;       -- g_beamlet X BF weight phase rotation in degrees for g_sp
+    g_bf_remnant_y_phase : REAL := -135.0;       -- g_beamlet Y BF weight phase rotation in degrees for g_sp
+    g_read_all_SST       : BOOLEAN := FALSE;  -- when FALSE only read SST for g_subband, to save sim time
+    g_read_all_BST       : BOOLEAN := FALSE   -- when FALSE only read BST for g_beamlet, to save sim time
   );
 END tb_lofar2_unb2c_sdp_station_bf;
 
 ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf IS
 
-  CONSTANT c_sim             : BOOLEAN := TRUE;
-  CONSTANT c_unb_nr          : NATURAL := 0; -- UniBoard 0
-  CONSTANT c_node_nr         : NATURAL := 0; 
-  CONSTANT c_gn_index        : NATURAL := c_unb_nr * 4 + c_node_nr;           -- this node GN
-  CONSTANT c_init_bsn        : NATURAL := 17;  -- some recognizable value >= 0
+  CONSTANT c_sim                 : BOOLEAN := TRUE;
+  CONSTANT c_unb_nr              : NATURAL := 0; -- UniBoard 0
+  CONSTANT c_node_nr             : NATURAL := 0;
+  CONSTANT c_gn_index            : NATURAL := c_unb_nr * 4 + c_node_nr;           -- this node GN
+  CONSTANT c_init_bsn            : NATURAL := 17;  -- some recognizable value >= 0
 
-  CONSTANT c_id              : STD_LOGIC_VECTOR(7 DOWNTO 0) := TO_UVEC(c_gn_index, 8);
-  CONSTANT c_version         : STD_LOGIC_VECTOR(1 DOWNTO 0) := "00";
-  CONSTANT c_fw_version      : t_unb2c_board_fw_version := (1, 0);
+  CONSTANT c_id                  : STD_LOGIC_VECTOR(7 DOWNTO 0) := TO_UVEC(c_gn_index, 8);
+  CONSTANT c_version             : STD_LOGIC_VECTOR(1 DOWNTO 0) := "00";
+  CONSTANT c_fw_version          : t_unb2c_board_fw_version := (1, 0);
 
-  CONSTANT c_mac_15_0        : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(c_unb_nr, 8) & TO_UVEC(c_node_nr, 8);
-  CONSTANT c_ip_15_0         : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(c_unb_nr, 8) & TO_UVEC(c_node_nr+1, 8);  -- +1 to avoid IP = *.*.*.0
+  CONSTANT c_mac_15_0            : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(c_unb_nr, 8) & TO_UVEC(c_node_nr, 8);
+  CONSTANT c_ip_15_0             : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(c_unb_nr, 8) & TO_UVEC(c_node_nr+1, 8);  -- +1 to avoid IP = *.*.*.0
 
   CONSTANT c_eth_clk_period      : TIME := 8 ns;  -- 125 MHz XO on UniBoard
   CONSTANT c_ext_clk_period      : TIME := 5 ns;
@@ -212,67 +227,106 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf IS
   -- .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 := NATURAL(g_wg_ampl * REAL(c_wg_ampl_full_scale));  -- in number of lsb
-  CONSTANT c_wg_unused_ampl       : NATURAL := NATURAL(g_unused_ampl * REAL(c_wg_ampl_full_scale));  -- in number of lsb
+  CONSTANT c_wg_ampl              : NATURAL := NATURAL(g_sp_ampl * REAL(c_wg_ampl_full_scale));  -- in number of lsb
+  CONSTANT c_wg_remnant_ampl      : NATURAL := NATURAL(g_sp_remnant_ampl * REAL(c_wg_ampl_full_scale));  -- in number of lsb
   CONSTANT c_exp_sp_power         : REAL := REAL(c_wg_ampl**2) / 2.0;
   CONSTANT c_exp_sp_ast           : REAL := c_exp_sp_power * REAL(c_nof_clk_per_sync);
   -- . phase
   CONSTANT c_subband_freq         : REAL := REAL(g_subband) / REAL(c_sdp_N_fft);  -- normalized by fs = f_adc = 200 MHz = dp_clk rate
   CONSTANT c_wg_latency           : INTEGER := c_diag_wg_latency - 0;  -- -0 to account for BSN scheduler start trigger latency
   CONSTANT c_wg_phase_offset      : REAL := 360.0 * REAL(c_wg_latency) * c_subband_freq;  -- c_diag_wg_latency is in dp_clk cycles
-  CONSTANT c_wg_phase             : REAL := g_wg_phase + c_wg_phase_offset;  -- WG phase in degrees
-  CONSTANT c_wg_unused_phase      : REAL := g_unused_phase + c_wg_phase_offset;  -- WG phase in degrees
+  CONSTANT c_wg_phase             : REAL := g_sp_phase + c_wg_phase_offset;  -- WG phase in degrees
+  CONSTANT c_wg_remnant_phase     : REAL := g_sp_remnant_phase + c_wg_phase_offset;  -- WG phase 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
 
   -- 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_subband_phase                  : REAL := g_wg_phase;  -- wanted subband phase in degrees = WG phase at sop
-  CONSTANT c_subband_phase_offset           : REAL := -90.0;  -- WG with zero phase sinues yields subband with -90 degrees phase (negative Im, zero Re)
-  CONSTANT c_subband_weight_gain            : REAL := 1.0;  -- use default unit subband weights
-  CONSTANT c_subband_weight_phase           : REAL := 0.0;  -- use default unit subband weights
-  CONSTANT c_exp_subband_sp_ampl_ratio      : REAL := 8.0 * c_sdp_wpfb_fir_filter_dc_gain;  -- ~= 8 for unit FIR DC gain, depends on internal WPFB quantization and FIR coefficients
-  CONSTANT c_exp_subband_ampl               : REAL := REAL(c_wg_ampl) * c_exp_subband_sp_ampl_ratio * c_subband_weight_gain;
-  CONSTANT c_exp_subband_power              : REAL := c_exp_subband_ampl**2.0;  -- complex, so no divide by 2
-  CONSTANT c_exp_subband_sst                : REAL := c_exp_subband_power * REAL(c_nof_block_per_sync);
-
-  TYPE t_real_arr IS ARRAY (INTEGER RANGE <>) OF REAL; 
+  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_subband_phase_offset         : REAL := -90.0;  -- WG with zero phase sinus yields subband with -90 degrees phase (negative Im, zero Re)
+  CONSTANT c_subband_weight_gain          : REAL := 1.0;  -- use default unit subband weights
+  CONSTANT c_subband_weight_phase         : REAL := 0.0;  -- use default unit subband weights
+  CONSTANT c_exp_subband_phase            : REAL := g_sp_phase + c_subband_phase_offset + c_subband_weight_phase;
+  CONSTANT c_exp_subband_ampl             : REAL := REAL(c_wg_ampl) * c_sdp_wpfb_subband_sp_ampl_ratio * c_subband_weight_gain;
+  CONSTANT c_exp_subband_power            : REAL := c_exp_subband_ampl**2.0;  -- complex signal ampl, so no divide by 2
+  CONSTANT c_exp_subband_sst              : REAL := c_exp_subband_power * REAL(c_nof_block_per_sync);
+
+  CONSTANT c_exp_remnant_subband_phase    : REAL := g_sp_remnant_phase + c_subband_phase_offset + c_subband_weight_phase;
+  CONSTANT c_exp_remnant_subband_ampl     : REAL := REAL(c_wg_remnant_ampl) * c_sdp_wpfb_subband_sp_ampl_ratio * c_subband_weight_gain;
+
+  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-1);           -- 512
   TYPE t_slv_64_beamlets_arr IS ARRAY (INTEGER RANGE <>) OF t_slv_64_arr(0 TO c_sdp_N_beamlets_sdp-1);  -- 2*488 = 976
 
   -- BF X-pol and Y-pol
   -- . select
-  CONSTANT c_exp_beamlet_x_index        : NATURAL := g_beamlet * c_sdp_N_pol_bf;      -- in beamset 0
-  CONSTANT c_exp_beamlet_y_index        : NATURAL := g_beamlet * c_sdp_N_pol_bf + 1;  -- in beamset 0
+  CONSTANT c_exp_beamlet_x_index          : NATURAL := g_beamlet * c_sdp_N_pol_bf;      -- X index in beamset 0
+  CONSTANT c_exp_beamlet_y_index          : NATURAL := g_beamlet * c_sdp_N_pol_bf + 1;  -- Y index in beamset 0
   -- . Beamlet weights for selected g_sp
-  CONSTANT c_bf_x_weight_re             : INTEGER := INTEGER(g_bf_x_gain * REAL(c_sdp_unit_bf_weight) * COS(g_bf_x_phase * MATH_2_PI / 360.0));
-  CONSTANT c_bf_x_weight_im             : INTEGER := INTEGER(g_bf_x_gain * REAL(c_sdp_unit_bf_weight) * SIN(g_bf_x_phase * MATH_2_PI / 360.0));
-  CONSTANT c_bf_y_weight_re             : INTEGER := INTEGER(g_bf_y_gain * REAL(c_sdp_unit_bf_weight) * COS(g_bf_y_phase * MATH_2_PI / 360.0));
-  CONSTANT c_bf_y_weight_im             : INTEGER := INTEGER(g_bf_y_gain * REAL(c_sdp_unit_bf_weight) * SIN(g_bf_y_phase * MATH_2_PI / 360.0));
+  CONSTANT c_bf_x_weight_re               : INTEGER := INTEGER(COMPLEX_RE(g_bf_x_gain * REAL(c_sdp_unit_bf_weight), g_bf_x_phase));
+  CONSTANT c_bf_x_weight_im               : INTEGER := INTEGER(COMPLEX_IM(g_bf_x_gain * REAL(c_sdp_unit_bf_weight), g_bf_x_phase));
+  CONSTANT c_bf_y_weight_re               : INTEGER := INTEGER(COMPLEX_RE(g_bf_y_gain * REAL(c_sdp_unit_bf_weight), g_bf_y_phase));
+  CONSTANT c_bf_y_weight_im               : INTEGER := INTEGER(COMPLEX_IM(g_bf_y_gain * REAL(c_sdp_unit_bf_weight), g_bf_y_phase));
+  CONSTANT c_bf_remnant_x_weight_re       : INTEGER := INTEGER(COMPLEX_RE(g_bf_remnant_x_gain * REAL(c_sdp_unit_bf_weight), g_bf_remnant_x_phase));
+  CONSTANT c_bf_remnant_x_weight_im       : INTEGER := INTEGER(COMPLEX_IM(g_bf_remnant_x_gain * REAL(c_sdp_unit_bf_weight), g_bf_remnant_x_phase));
+  CONSTANT c_bf_remnant_y_weight_re       : INTEGER := INTEGER(COMPLEX_RE(g_bf_remnant_y_gain * REAL(c_sdp_unit_bf_weight), g_bf_remnant_y_phase));
+  CONSTANT c_bf_remnant_y_weight_im       : INTEGER := INTEGER(COMPLEX_IM(g_bf_remnant_y_gain * REAL(c_sdp_unit_bf_weight), g_bf_remnant_y_phase));
+
+  -- Model the SDP beamformer for one g_sp and S_pn-1 = 11 remnant signal inputs
+  FUNCTION bf_calculate_expected_beamlet(sp_subband_ampl, sp_subband_phase, sp_bf_gain, sp_bf_phase,
+                                         rem_subband_ampl, rem_subband_phase, rem_bf_gain, rem_bf_phase : REAL) RETURN t_real_arr IS  -- 0:3 = ampl, phase, re, im
+    CONSTANT c_nof_rem : REAL := REAL(c_sdp_S_pn - 1);  -- BF for one g_sp and 11 remnant signal inputs
+    VARIABLE v_sp_ampl, v_sp_phase, v_sp_re, v_sp_im     : REAL;
+    VARIABLE v_rem_ampl, v_rem_phase, v_rem_re, v_rem_im : REAL;
+    VARIABLE v_sum_ampl, v_sum_phase, v_sum_re, v_sum_im : REAL;
+    VARIABLE v_tuple                                     : t_real_arr(0 TO 3);
+  BEGIN
+    v_sp_ampl   := sp_subband_ampl * sp_bf_gain;
+    v_sp_phase  := sp_subband_phase + sp_bf_phase;
+    v_sp_re     := COMPLEX_RE(v_sp_ampl, v_sp_phase);
+    v_sp_im     := COMPLEX_IM(v_sp_ampl, v_sp_phase);
+    v_rem_ampl  := rem_subband_ampl * rem_bf_gain;
+    v_rem_phase := rem_subband_phase + rem_bf_phase;
+    v_rem_re    := COMPLEX_RE(v_rem_ampl, v_rem_phase);
+    v_rem_im    := COMPLEX_IM(v_rem_ampl, v_rem_phase);
+    v_sum_re    := v_sp_re + c_nof_rem * v_rem_re;  -- BF sum re
+    v_sum_im    := v_sp_im + c_nof_rem * v_rem_im;  -- BF sum im
+    v_sum_ampl  := COMPLEX_RADIUS(v_sum_re, v_sum_im);
+    v_sum_phase := COMPLEX_PHASE(v_sum_re, v_sum_im);
+    v_tuple     := (0 => v_sum_ampl, 1 => v_sum_phase, 2 => v_sum_re, 3 => v_sum_im);
+    RETURN v_tuple;
+  END;
+
   -- . Beamlet internal
-  CONSTANT c_exp_beamlet_x_ampl         : REAL := c_exp_subband_ampl * g_bf_x_gain;
-  CONSTANT c_exp_beamlet_x_phase        : REAL := c_subband_phase_offset + c_subband_weight_phase + g_bf_x_phase;
-  CONSTANT c_exp_beamlet_x_re           : REAL := c_exp_beamlet_x_ampl * COS(c_exp_beamlet_x_phase * MATH_2_PI / 360.0);
-  CONSTANT c_exp_beamlet_x_im           : REAL := c_exp_beamlet_x_ampl * SIN(c_exp_beamlet_x_phase * MATH_2_PI / 360.0);
-  CONSTANT c_exp_beamlet_y_ampl         : REAL := c_exp_subband_ampl * g_bf_y_gain;
-  CONSTANT c_exp_beamlet_y_phase        : REAL := c_subband_phase_offset + c_subband_weight_phase + g_bf_y_phase;
-  CONSTANT c_exp_beamlet_y_re           : REAL := c_exp_beamlet_y_ampl * COS(c_exp_beamlet_y_phase * MATH_2_PI / 360.0);
-  CONSTANT c_exp_beamlet_y_im           : REAL := c_exp_beamlet_y_ampl * SIN(c_exp_beamlet_y_phase * MATH_2_PI / 360.0);
+  CONSTANT c_exp_beamlet_x_tuple          : t_real_arr(0 TO 3) := bf_calculate_expected_beamlet(
+                                              c_exp_subband_ampl, c_exp_subband_phase, g_bf_x_gain, g_bf_x_phase,
+                                              c_exp_remnant_subband_ampl, c_exp_remnant_subband_phase, g_bf_remnant_x_gain, g_bf_remnant_x_phase);
+  CONSTANT c_exp_beamlet_x_ampl           : REAL := c_exp_beamlet_x_tuple(0);
+  CONSTANT c_exp_beamlet_x_phase          : REAL := c_exp_beamlet_x_tuple(1);
+  CONSTANT c_exp_beamlet_x_re             : REAL := c_exp_beamlet_x_tuple(2);
+  CONSTANT c_exp_beamlet_x_im             : REAL := c_exp_beamlet_x_tuple(3);
+
+  CONSTANT c_exp_beamlet_y_tuple          : t_real_arr(0 TO 3) := bf_calculate_expected_beamlet(
+                                              c_exp_subband_ampl, c_exp_subband_phase, g_bf_y_gain, g_bf_y_phase,
+                                              c_exp_remnant_subband_ampl, c_exp_remnant_subband_phase, g_bf_remnant_y_gain, g_bf_remnant_y_phase);
+  CONSTANT c_exp_beamlet_y_ampl           : REAL := c_exp_beamlet_y_tuple(0);
+  CONSTANT c_exp_beamlet_y_phase          : REAL := c_exp_beamlet_y_tuple(1);
+  CONSTANT c_exp_beamlet_y_re             : REAL := c_exp_beamlet_y_tuple(2);
+  CONSTANT c_exp_beamlet_y_im             : REAL := c_exp_beamlet_y_tuple(3);
   -- . BST
-  CONSTANT c_exp_beamlet_x_power        : REAL := c_exp_beamlet_x_ampl**2.0;  -- complex, so no divide by 2
-  CONSTANT c_exp_beamlet_x_bst          : REAL := c_exp_subband_sst * g_bf_x_gain**2.0;  -- = c_exp_beamlet_x_power *  REAL(c_nof_block_per_sync)
-  CONSTANT c_exp_beamlet_y_power        : REAL := c_exp_beamlet_y_ampl**2.0;  -- complex, so no divide by 2
-  CONSTANT c_exp_beamlet_y_bst          : REAL := c_exp_subband_sst * g_bf_y_gain**2.0;  -- = c_exp_beamlet_y_power *  REAL(c_nof_block_per_sync)
+  CONSTANT c_exp_beamlet_x_power          : REAL := c_exp_beamlet_x_ampl**2.0;  -- complex signal ampl, so no divide by 2
+  CONSTANT c_exp_beamlet_x_bst            : REAL := c_exp_beamlet_x_power * REAL(c_nof_block_per_sync);
+  CONSTANT c_exp_beamlet_y_power          : REAL := c_exp_beamlet_y_ampl**2.0;  -- complex signal ampl, so no divide by 2
+  CONSTANT c_exp_beamlet_y_bst            : REAL := c_exp_beamlet_y_power * REAL(c_nof_block_per_sync);
   -- . Beamlet output
-  CONSTANT c_exp_beamlet_x_output_ampl  : REAL := c_exp_beamlet_x_ampl * g_beamlet_scale;
-  CONSTANT c_exp_beamlet_x_output_phase : REAL := c_exp_beamlet_x_phase;
-  CONSTANT c_exp_beamlet_x_output_re    : REAL := c_exp_beamlet_x_re * g_beamlet_scale;
-  CONSTANT c_exp_beamlet_x_output_im    : REAL := c_exp_beamlet_x_im * g_beamlet_scale;
-  CONSTANT c_exp_beamlet_y_output_ampl  : REAL := c_exp_beamlet_y_ampl * g_beamlet_scale;
-  CONSTANT c_exp_beamlet_y_output_phase : REAL := c_exp_beamlet_y_phase;
-  CONSTANT c_exp_beamlet_y_output_re    : REAL := c_exp_beamlet_y_re * g_beamlet_scale;
-  CONSTANT c_exp_beamlet_y_output_im    : REAL := c_exp_beamlet_y_im * g_beamlet_scale;
+  CONSTANT c_exp_beamlet_x_output_ampl    : REAL := c_exp_beamlet_x_ampl * g_beamlet_scale;
+  CONSTANT c_exp_beamlet_x_output_phase   : REAL := c_exp_beamlet_x_phase;
+  CONSTANT c_exp_beamlet_x_output_re      : REAL := c_exp_beamlet_x_re * g_beamlet_scale;
+  CONSTANT c_exp_beamlet_x_output_im      : REAL := c_exp_beamlet_x_im * g_beamlet_scale;
+  CONSTANT c_exp_beamlet_y_output_ampl    : REAL := c_exp_beamlet_y_ampl * g_beamlet_scale;
+  CONSTANT c_exp_beamlet_y_output_phase   : REAL := c_exp_beamlet_y_phase;
+  CONSTANT c_exp_beamlet_y_output_re      : REAL := c_exp_beamlet_y_re * g_beamlet_scale;
+  CONSTANT c_exp_beamlet_y_output_im      : REAL := c_exp_beamlet_y_im * g_beamlet_scale;
 
   -- MM
   -- . Address widths of a single MM instance
@@ -588,7 +642,40 @@ BEGIN
   BEGIN
     -- Wait for DUT power up after reset
     WAIT FOR 1 us;
-    
+
+    print_str("");
+    print_str("WG:");
+    print_str(". c_wg_ampl                            = " & int_to_str(c_wg_ampl));
+    print_str(". c_exp_sp_power                       = " & real_to_str(c_exp_sp_power, 20, 1));
+    print_str(". c_exp_sp_ast                         = " & real_to_str(c_exp_sp_ast, 20, 1));
+
+    print_str("");
+    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));
+
+    print_str("");
+    print_str("SST results:");
+    print_str(". sst_weighted_subbands_flag           = " & sl_to_str(sst_weighted_subbands_flag));
+    print_str("");
+    print_str(". c_exp_subband_ampl                   = " & int_to_str(NATURAL(c_exp_subband_ampl)));
+    print_str(". c_exp_subband_power                  = " & real_to_str(c_exp_subband_power, 20, 1));
+    print_str(". c_exp_subband_sst                    = " & real_to_str(c_exp_subband_sst, 20, 1));
+    print_str("");
+    print_str(". sp_sst                               = " & real_to_str(sp_sst, 20, 1));
+    print_str(". sp_sst / c_exp_subband_sst           = " & real_to_str(sp_sst / c_exp_subband_sst, 20, 6));
+
+    print_str("");
+    print_str("BST results:");
+    print_str(". c_exp_beamlet_x_ampl                   = " & int_to_str(NATURAL(c_exp_beamlet_x_ampl)));
+    print_str(". c_exp_beamlet_x_power                  = " & real_to_str(c_exp_beamlet_x_power, 20, 1));
+    print_str(". c_exp_beamlet_x_bst                    = " & real_to_str(c_exp_beamlet_x_bst, 20, 1));
+    print_str("");
+    print_str(". c_exp_beamlet_y_ampl                   = " & int_to_str(NATURAL(c_exp_beamlet_y_ampl)));
+    print_str(". c_exp_beamlet_y_power                  = " & real_to_str(c_exp_beamlet_y_power, 20, 1));
+    print_str(". c_exp_beamlet_y_bst                    = " & real_to_str(c_exp_beamlet_y_bst, 20, 1));
+    print_str("");
+
     ----------------------------------------------------------------------------
     -- Set and check SDP info
     ----------------------------------------------------------------------------
@@ -722,7 +809,7 @@ BEGIN
     --   1 : phase[15:0]
     --   2 : freq[30:0]
     --   3 : ampl[16:0]
-    -- . Put wanted signal on g_sp input and unused signal on the other inputs
+    -- . Put wanted signal on g_sp input and remnant signal on the other inputs
     FOR S IN 0 TO c_sdp_S_pn-1 LOOP
       v_offset := S * c_mm_span_reg_diag_wg;
       IF s = g_sp THEN
@@ -732,9 +819,9 @@ BEGIN
         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
       ELSE
         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_unused_phase * c_diag_wg_phase_unit), tb_clk);  -- phase offset in degrees
+        mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 1, INTEGER(c_wg_remnant_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_unused_ampl) * c_wg_ampl_lsb), tb_clk);  -- ampl
+        mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 3, INTEGER(REAL(c_wg_remnant_ampl) * c_wg_ampl_lsb), tb_clk);  -- ampl
       END IF;
     END LOOP;
 
@@ -769,8 +856,8 @@ BEGIN
     v_im := unpack_complex_im(rd_data, c_sdp_W_sub_weight);
     sp_subband_weight_re <= v_re;
     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_gain <= COMPLEX_RADIUS(v_re, v_im) / REAL(c_sdp_unit_sub_weight);
+    sp_subband_weight_phase <= COMPLEX_PHASE(v_re, v_im);
 
     -- No need to write subband weight, because default it is unit weight
 
@@ -833,8 +920,12 @@ BEGIN
                 v_weight := pack_complex(re => c_bf_y_weight_re, im => c_bf_y_weight_im, w => c_sdp_W_bf_weight);
               END IF;
             ELSE
-              -- default set all weights to zero
-              v_weight := 0;
+              -- use the remnant BF weights for the other SP
+              IF PB = 0 THEN
+                v_weight := pack_complex(re => c_bf_remnant_x_weight_re, im => c_bf_remnant_x_weight_im, w => c_sdp_W_bf_weight);
+              ELSE
+                v_weight := pack_complex(re => c_bf_remnant_y_weight_re, im => c_bf_remnant_y_weight_im, w => c_sdp_W_bf_weight);
+              END IF;
             END IF;
             v_addr := g_beamlet;                              -- beamlet index
             v_addr := v_addr + P * c_sdp_S_sub_bf;            -- antenna input polarization address offset
@@ -866,13 +957,13 @@ BEGIN
             IF PB = 0 THEN
               sp_bf_x_weights_re_arr(v_S) <= v_re;
               sp_bf_x_weights_im_arr(v_S) <= v_im;
-              sp_bf_x_weights_gain_arr(v_S) <= SQRT(REAL(v_re)**2.0 + REAL(v_im)**2.0) / REAL(c_sdp_unit_bf_weight);
-              sp_bf_x_weights_phase_arr(v_S) <= atan2(Y => REAL(v_im), X => REAL(v_re)) * 360.0 / MATH_2_PI;
+              sp_bf_x_weights_gain_arr(v_S) <= COMPLEX_RADIUS(v_re, v_im) / REAL(c_sdp_unit_bf_weight);
+              sp_bf_x_weights_phase_arr(v_S) <= COMPLEX_PHASE(v_re, v_im);
             ELSE
               sp_bf_y_weights_re_arr(v_S) <= v_re;
               sp_bf_y_weights_im_arr(v_S) <= v_im;
-              sp_bf_y_weights_gain_arr(v_S) <= SQRT(REAL(v_re)**2.0 + REAL(v_im)**2.0) / REAL(c_sdp_unit_bf_weight);
-              sp_bf_y_weights_phase_arr(v_S) <= atan2(Y => REAL(v_im), X => REAL(v_re)) * 360.0 / MATH_2_PI;
+              sp_bf_y_weights_gain_arr(v_S) <= COMPLEX_RADIUS(v_re, v_im) / REAL(c_sdp_unit_bf_weight);
+              sp_bf_y_weights_phase_arr(v_S) <= COMPLEX_PHASE(v_re, v_im);
             END IF;
           END LOOP;
         END LOOP;
-- 
GitLab