Skip to content

Commit 68440e9

Browse files
jhirsinordicjm
authored andcommitted
samples: dect_phy: dect_shell: rf_tool: add RSSI/SNR averaging
Add 1-tap IIR low-pass filter for RSSI and SNR measurements to show smoothed average values.Uses Q3 fixed-point for precision in ISR context. Added also --rx_show_min_max_values option to optionally display min/max values (disabled by default, only average shown). SNR to use dB scale, not as received from modem. Jira: DECT-1202 Signed-off-by: Jani Hirsimäki <[email protected]>
1 parent fc86c3e commit 68440e9

File tree

4 files changed

+115
-14
lines changed

4 files changed

+115
-14
lines changed

doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,13 @@ Debug samples
272272
DECT NR+ samples
273273
----------------
274274

275-
|no_changes_yet_note|
275+
* :ref:`dect_shell_application` sample:
276+
277+
* Updated:
278+
279+
* The ``dect rf_tool`` command - Major updates to improve usage for RX and TX testing.
280+
* Scheduler - Dynamic flow control based on load tier to prevent modem out-of-memory errors.
281+
* Settings - Continuous Wave (CW) support and possibility to disable Synchronization Training Field (STF) on TX and RX.
276282

277283
Edge Impulse samples
278284
--------------------

samples/dect/dect_phy/dect_shell/src/dect/dect_phy_shell.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ enum {
421421
DECT_SHELL_CERT_TX_FRAME_START_OFFSET_SUBSLOTS,
422422
DECT_SHELL_CERT_TX_SUBSLOT_COUNT,
423423
DECT_SHELL_CERT_TX_POST_IDLE_SUBSLOT_COUNT,
424+
DECT_SHELL_CERT_RX_SHOW_MIN_MAX_VALUES,
424425
};
425426

426427
static const char dect_phy_rf_tool_cmd_usage_str[] =
@@ -455,6 +456,8 @@ static const char dect_phy_rf_tool_cmd_usage_str[] =
455456
" band #9 1703-1711, band #22 1691-1711.\n"
456457
" -e --rx_exp_rssi_level <int>, Set expected RSSI level on RX (dBm).\n"
457458
" Default: from common rx settings.\n"
459+
" --rx_show_min_max_values, Show min/max RX RSSI/SNR values in results.\n"
460+
" Default: disabled (only average shown).\n"
458461
" -p --tx_pwr <int>, TX power (dBm),\n"
459462
" [-40,-30,-20,-16,-12,-8,-4,0,4,7,10,13,16,19,21,23]\n"
460463
" See supported max for the used band by using\n"
@@ -536,6 +539,7 @@ static struct option long_options_cert[] = {
536539
DECT_SHELL_CERT_TX_FRAME_START_OFFSET_SUBSLOTS},
537540
{"tx_subslot_count", required_argument, 0, DECT_SHELL_CERT_TX_SUBSLOT_COUNT},
538541
{"tx_idle_subslot_count", required_argument, 0, DECT_SHELL_CERT_TX_POST_IDLE_SUBSLOT_COUNT},
542+
{"rx_show_min_max_values", no_argument, 0, DECT_SHELL_CERT_RX_SHOW_MIN_MAX_VALUES},
539543
{0, 0, 0, 0}};
540544

541545
static int dect_phy_rf_tool_cmd(const struct shell *shell, size_t argc, char **argv)
@@ -586,6 +590,7 @@ static int dect_phy_rf_tool_cmd(const struct shell *shell, size_t argc, char **a
586590
params.rx_post_idle_subslot_count;
587591
params.tx_subslot_count = 4;
588592
params.tx_post_idle_subslot_count = 6;
593+
params.rx_show_min_max_values = false;
589594

590595
while ((opt = getopt_long(argc, argv, "m:t:c:e:p:sh", long_options_cert, &long_index)) !=
591596
-1) {
@@ -749,6 +754,10 @@ static int dect_phy_rf_tool_cmd(const struct shell *shell, size_t argc, char **a
749754
params.tx_post_idle_subslot_count = ret;
750755
break;
751756
}
757+
case DECT_SHELL_CERT_RX_SHOW_MIN_MAX_VALUES: {
758+
params.rx_show_min_max_values = true;
759+
break;
760+
}
752761
case 'h':
753762
goto show_usage;
754763
case '?':

samples/dect/dect_phy/dect_shell/src/dect/dect_phy_shell.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ struct dect_phy_rf_tool_params {
102102
uint8_t tx_frame_start_offset;
103103
uint8_t tx_subslot_count;
104104
uint8_t tx_post_idle_subslot_count;
105+
106+
bool rx_show_min_max_values; /* Show min/max RSSI/SNR values in results */
105107
};
106108

107109
struct dect_phy_ping_params {

samples/dect/dect_phy/dect_shell/src/dect/rf_tool/dect_phy_rf_tool.c

Lines changed: 97 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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
/**************************************************************************************************/
110158
static int dect_phy_rf_tool_msgq_data_op_add(uint16_t event_id, const void *data, size_t data_size);
111159
static 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

Comments
 (0)