@@ -62,12 +62,16 @@ struct dect_phy_rf_tool_rx_metrics {
6262
6363 uint32_t rx_pdc_crc_error_count ;
6464
65+ int32_t rx_rssi_avg_q3 ; /* Q3 fixed-point RSSI average (value * 8) */
66+ bool rx_rssi_avg_initialized ;
6567 int8_t rx_rssi_high_level ;
6668 int8_t rx_rssi_low_level ;
6769 uint8_t rx_phy_transmit_pwr_low ;
6870 uint8_t rx_phy_transmit_pwr_high ;
6971 int16_t rx_snr_low ;
7072 int16_t rx_snr_high ;
73+ int32_t rx_snr_avg_q3 ; /* Q3 fixed-point SNR average (value * 8), in 1/4 dB units */
74+ bool rx_snr_avg_initialized ;
7175 uint8_t rx_latest_mcs ;
7276};
7377
@@ -106,6 +110,50 @@ static struct dect_phy_rf_tool_tool_data {
106110
107111#define DECT_PHY_RF_TOOL_RESTART_SCHEDULING_DELAY_SECS 2
108112
113+ /* IIR low-pass filter for RSSI and SNR averaging.
114+ *
115+ * Raw RSSI/SNR measurements fluctuate due to multipath fading, interference,
116+ * and measurement noise. The low-pass filter smooths these variations to show
117+ * the overall signal trend while rejecting sudden spikes.
118+ * Larger shift means more smoothing (less sensitivity to short-term fluctuations).
119+ * Smaller shift means more sensitivity to short-term fluctuations.
120+ *
121+ * The shift value determines both the filter alpha (alpha = 1 / (1 << shift)) and the
122+ * Q fixed-point precision (value * (1 << shift)). Using the same shift for both is
123+ * intentional: it allows the alpha scaling and Q scaling to cancel out in the update
124+ * formula, simplifying "alpha * input * Q_scale" to just "input". This avoids extra
125+ * shift operations and keeps the code efficient for ISR context.
126+ *
127+ * shift = 3 means alpha = 0.125, so An = 0.875 * An-1 + 0.125 * input
128+ */
129+ #define DECT_PHY_RF_TOOL_IIR_SHIFT 3
130+
131+ /**
132+ * @brief 1-tap IIR low-pass filter (exponential moving average) using fixed-point.
133+ *
134+ * Implements: An = (1 - alpha) * An-1 + alpha * input
135+ * where alpha = 1 / (1 << DECT_PHY_RF_TOOL_IIR_SHIFT).
136+ */
137+ static inline void dect_phy_rf_tool_iir_lpf_update (int32_t * avg_q , bool * initialized ,
138+ int16_t input )
139+ {
140+ if (!* initialized ) {
141+ * avg_q = (int32_t )input << DECT_PHY_RF_TOOL_IIR_SHIFT ;
142+ * initialized = true;
143+ } else {
144+ /* An = An-1 - alpha*An-1 + alpha*input (alpha terms cancel with Q scaling) */
145+ * avg_q = * avg_q - (* avg_q >> DECT_PHY_RF_TOOL_IIR_SHIFT ) + input ;
146+ }
147+ }
148+
149+ /**
150+ * @brief Get the filtered value from Q fixed-point average.
151+ */
152+ static inline int16_t dect_phy_rf_tool_iir_lpf_value_get (int32_t avg_q )
153+ {
154+ return (int16_t )(avg_q >> DECT_PHY_RF_TOOL_IIR_SHIFT );
155+ }
156+
109157/**************************************************************************************************/
110158static int dect_phy_rf_tool_msgq_data_op_add (uint16_t event_id , const void * data , size_t data_size );
111159static int dect_phy_rf_tool_msgq_non_data_op_add (uint16_t event_id );
@@ -201,6 +249,12 @@ static void dect_phy_rf_tool_mdm_pcc_cb(const struct nrf_modem_dect_phy_pcc_even
201249 rf_tool_data .rx_metrics .rx_rssi_low_level = rssi_level ;
202250 }
203251
252+ /* Update RSSI exponential moving average (1-tap IIR low-pass filter) */
253+ dect_phy_rf_tool_iir_lpf_update (
254+ & rf_tool_data .rx_metrics .rx_rssi_avg_q3 ,
255+ & rf_tool_data .rx_metrics .rx_rssi_avg_initialized ,
256+ rssi_level );
257+
204258 /* Update transmit power min/max */
205259 if (phy_h -> transmit_power > rf_tool_data .rx_metrics .rx_phy_transmit_pwr_high ) {
206260 rf_tool_data .rx_metrics .rx_phy_transmit_pwr_high = phy_h -> transmit_power ;
@@ -209,14 +263,22 @@ static void dect_phy_rf_tool_mdm_pcc_cb(const struct nrf_modem_dect_phy_pcc_even
209263 rf_tool_data .rx_metrics .rx_phy_transmit_pwr_low = phy_h -> transmit_power ;
210264 }
211265
212- /* Update SNR min/max */
213- if (evt -> snr > rf_tool_data .rx_metrics .rx_snr_high ) {
214- rf_tool_data .rx_metrics .rx_snr_high = evt -> snr ;
266+ /* Update SNR min/max/avg (convert to dB by dividing by 4) */
267+ int16_t snr_db = evt -> snr / 4 ;
268+
269+ if (snr_db > rf_tool_data .rx_metrics .rx_snr_high ) {
270+ rf_tool_data .rx_metrics .rx_snr_high = snr_db ;
215271 }
216- if (evt -> snr < rf_tool_data .rx_metrics .rx_snr_low ) {
217- rf_tool_data .rx_metrics .rx_snr_low = evt -> snr ;
272+ if (snr_db < rf_tool_data .rx_metrics .rx_snr_low ) {
273+ rf_tool_data .rx_metrics .rx_snr_low = snr_db ;
218274 }
219275
276+ /* Update SNR exponential moving average (1-tap IIR low-pass filter) */
277+ dect_phy_rf_tool_iir_lpf_update (
278+ & rf_tool_data .rx_metrics .rx_snr_avg_q3 ,
279+ & rf_tool_data .rx_metrics .rx_snr_avg_initialized ,
280+ snr_db );
281+
220282 /* Update MCS and STF time */
221283 rf_tool_data .rx_metrics .rx_latest_mcs = phy_h -> df_mcs ;
222284 rf_tool_data .rx_metrics .last_pcc_stf_time = evt -> stf_start_time ;
@@ -502,10 +564,19 @@ void dect_phy_rf_tool_print_results(void)
502564 rf_tool_data .rx_metrics .rx_pdc_crc_error_count );
503565 }
504566
505- desh_print (" - RX: RSSI high level: %d" ,
506- rf_tool_data .rx_metrics .rx_rssi_high_level );
507- desh_print (" - RX: RSSI low level: %d" ,
508- rf_tool_data .rx_metrics .rx_rssi_low_level );
567+ if (cmd_params -> rx_show_min_max_values ) {
568+ desh_print (" - RX: RSSI high level: %d" ,
569+ rf_tool_data .rx_metrics .rx_rssi_high_level );
570+ desh_print (" - RX: RSSI low level: %d" ,
571+ rf_tool_data .rx_metrics .rx_rssi_low_level );
572+ }
573+ if (rf_tool_data .rx_metrics .rx_rssi_avg_initialized ) {
574+ desh_print (" - RX: RSSI average: %d" ,
575+ dect_phy_rf_tool_iir_lpf_value_get (
576+ rf_tool_data .rx_metrics .rx_rssi_avg_q3 ));
577+ } else {
578+ desh_print (" - RX: RSSI average: N/A" );
579+ }
509580
510581 desh_print (" - RX: transmit power high: %d dbm" ,
511582 dect_common_utils_phy_tx_power_to_dbm (
@@ -514,10 +585,19 @@ void dect_phy_rf_tool_print_results(void)
514585 dect_common_utils_phy_tx_power_to_dbm (
515586 rf_tool_data .rx_metrics .rx_phy_transmit_pwr_low ));
516587
517- desh_print (" - RX SNR high: %d" ,
518- rf_tool_data .rx_metrics .rx_snr_high );
519- desh_print (" - RX SNR low: %d" ,
520- rf_tool_data .rx_metrics .rx_snr_low );
588+ if (cmd_params -> rx_show_min_max_values ) {
589+ desh_print (" - RX SNR high: %d" ,
590+ rf_tool_data .rx_metrics .rx_snr_high );
591+ desh_print (" - RX SNR low: %d" ,
592+ rf_tool_data .rx_metrics .rx_snr_low );
593+ }
594+ if (rf_tool_data .rx_metrics .rx_snr_avg_initialized ) {
595+ desh_print (" - RX SNR average: %d" ,
596+ dect_phy_rf_tool_iir_lpf_value_get (
597+ rf_tool_data .rx_metrics .rx_snr_avg_q3 ));
598+ } else {
599+ desh_print (" - RX SNR average: N/A" );
600+ }
521601 desh_print (" - RX latest MCS: %d" ,
522602 rf_tool_data .rx_metrics .rx_latest_mcs );
523603 }
@@ -1165,12 +1245,16 @@ static int dect_phy_rf_tool_start(struct dect_phy_rf_tool_params *params, bool r
11651245 memset (& rf_tool_data .rx_metrics , 0 , sizeof (rf_tool_data .rx_metrics ));
11661246 atomic_set (& rf_tool_data .rx_metrics .rx_total_pkt_count , 0 );
11671247 atomic_set (& rf_tool_data .rx_metrics .rx_wait_for_synch , 0 );
1248+ rf_tool_data .rx_metrics .rx_rssi_avg_q3 = 0 ;
1249+ rf_tool_data .rx_metrics .rx_rssi_avg_initialized = false;
11681250 rf_tool_data .rx_metrics .rx_rssi_high_level = -127 ;
11691251 rf_tool_data .rx_metrics .rx_rssi_low_level = 1 ;
11701252 rf_tool_data .rx_metrics .rx_phy_transmit_pwr_high = 0 ;
11711253 rf_tool_data .rx_metrics .rx_phy_transmit_pwr_low = 15 ;
11721254 rf_tool_data .rx_metrics .rx_snr_low = 9999 ;
11731255 rf_tool_data .rx_metrics .rx_snr_high = -9999 ;
1256+ rf_tool_data .rx_metrics .rx_snr_avg_q3 = 0 ;
1257+ rf_tool_data .rx_metrics .rx_snr_avg_initialized = false;
11741258
11751259 atomic_set (& rf_tool_data .on_going , 1 );
11761260 rf_tool_data .cmd_params = * params ;
0 commit comments