NRF54L15 DK channel sounding (RTT ONLY) improvements confusion?

SETUP:

2 x NRF54L15 DK
initiator/reflector sample (as of 4/8/2025)
Major RTT settings below - RTT (BT_CONN_LE_CS_MAIN_MODE_1) with 1M phy, 32 bit random RTT (will add settings and prj.conf below)

QUESTIONS:

1. 1phy data is OK but a lot of negative TOF values which is confusing me. Is there an issue with the hex conversion of this data or something im missing as to why? (obfuscated in bt_ras_rreq_rd_subevent_data_parse "helper for parsing ranging data-formatted buffer"). I'm reminded of the 4-3 byte conversion from the early AOA days...

2. the 2M phy data is consistent, but always shifted about -7m.Is this just the the current state of the parse helper not accounting for the 2m phy mode? ( changed the .cs_sync_phy & .phy to 2M and enabled 2M in the prj.conf of the initiator, then enabled 2M in prj.conf on refl)

3. Any suggestions on more levers to pull to improve this setup? Not using channel switching or a subevent confused me in the setup quite a bit.

2M PHY data example (each data point from multiple events)

n	delta TOF (uS)	toa_tod_initiator (uS)	tod_toa_reflector(uS)
E: 0	6.5	70	44
E: 1	-5	42	62
E: 2	-22	21	109
E: 4	7	77	49
E: 5	5.5	70	48
E: 7	-0.75	59	62
E: 8	23.5	118	24
E: 9	10.25	91	50
E: 10	4.75	72	53
E: 18	0.25	66	65
E: 22	2.75	79	68
E: 32	-29	36	152
E: 33	-1.75	64	71
E: 35	-11.75	38	85
E: 38	3	71	59
E: 44	-17.75	42	113
E: 45	-27.75	4	115
E: 47	17.5	90	20
E: 48	8	85	53
E: 50	-22.5	23	113
E: 51	-14.5	49	107
E: 52	-8.75	68	103
E: 54	1.25	71	66
E: 56	1.25	82	77
E: 58	-15.75	52	115
E: 59	-20.5	39	121
E: 60	-11.5	49	95
E: 61	-12.25	45	94
E: 62	-10.25	67	108
E: 63	-12.5	57	107
E: 64	10.25	94	53
E: 65	-0.5	83	85
E: 0	-0.5	-36	-34
E: 1	-3	-32	-20
E: 2	2.75	-18	-29
E: 3	4.25	-14	-31
E: 4	4.5	-16	-34
E: 5	3.25	-12	-25
E: 6	-9.25	-35	2
E: 7	-1	-20	-16
E: 8	-11	-50	-6
E: 9	4.25	-12	-29
E: 10	-12.5	-47	3
E: 11	-13.5	-46	8
E: 12	11.25	-12	-57
E: 14	8.75	4	-31
E: 15	-6.5	-32	-6
E: 16	1.25	-14	-19
E: 17	1.25	-31	-36
E: 18	-15.75	-53	10
E: 19	-24.5	-68	30
E: 21	7	-9	-37
E: 22	-9.25	-26	11
E: 23	7	-3	-31
E: 24	-25	-75	25
E: 25	-17.25	-51	18
E: 26	0.25	-16	-17
E: 27	-1.25	-30	-25
E: 28	-17.75	-59	12
E: 29	-17.75	-64	7
E: 30	-10	-42	-2
E: 31	-2.75	-15	-4
E: 32	5	6	-14
E: 33	-11.75	-39	8
E: 34	-7.25	-27	2
E: 35	1.25	-8	-13
E: 36	0.5	-19	-21
E: 37	-11.25	-38	7
E: 38	1	-18	-22
E: 39	7	4	-24
E: 40	18.25	12	-61
E: 41	-3	-14	-2
E: 42	-20.5	-65	17
E: 43	-15.75	-50	13
E: 44	13	12	-40
E: 45	4.25	-6	-23
E: 46	-5.5	-22	0
E: 47	-2	-20	-12
E: 48	-6	-24	0
E: 49	3	-5	-17
E: 50	-0.5	-19	-17
E: 51	3	-12	-24
E: 52	13.5	25	-29
E: 53	0.5	-6	-8
E: 54	-2.25	-11	-2
E: 55	-19	-48	28
E: 56	14.75	23	-36
E: 57	9.75	6	-33
E: 59	-4.75	-17	2
E: 60	-27	-51	57
E: 61	6.75	5	-22
E: 62	0.75	-4	-7
E: 63	-6	-11	13
E: 64	-11.75	-30	17
E: 65	1	-10	-14
E: 0	0.75	-18	-21
E: 1	0.25	-19	-20
E: 2	-4.75	-33	-14
E: 3	5.25	-9	-30
E: 4	11.75	7	-40
E: 5	-11	-37	7
E: 6	-7.5	-34	-4
E: 7	-1	-19	-15
E: 8	5.5	-5	-27
E: 9	8.25	-3	-36
E: 10	-7	-36	-8
E: 11	-14	-49	7

SETTINGS

		struct bt_scan_init_param param = {
		.scan_param = NULL,
		.conn_param = BT_LE_CONN_PARAM(20, 20, 0, 400),  // 30–50 ms
		.connect_if_match = 1
	};
	struct bt_le_cs_create_config_params config_params = {
		.id = CS_CONFIG_ID,
		.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_1,
		.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_UNUSED,
		.min_main_mode_steps = 1,
		.max_main_mode_steps = 1,
		.main_mode_repetition = 0,
		.mode_0_steps = NUM_MODE_0_STEPS,
		.role = BT_CONN_LE_CS_ROLE_INITIATOR,
		.rtt_type = BT_CONN_LE_CS_RTT_TYPE_32_BIT_RANDOM,
		.cs_sync_phy = BT_CONN_LE_CS_SYNC_1M_PHY,
		.channel_map_repetition = 5,
		.channel_selection_type = BT_CONN_LE_CS_CHSEL_TYPE_3B,
		.ch3c_shape = BT_CONN_LE_CS_CH3C_SHAPE_HAT,
		.ch3c_jump = 2,

	};
		const struct bt_le_cs_set_procedure_parameters_param procedure_params = {
		.config_id = CS_CONFIG_ID,
		.max_procedure_len = 50,
		.min_procedure_interval = 60,
		.max_procedure_interval = 60,
		.max_procedure_count = 0,
		.min_subevent_len = 15000,
		.max_subevent_len = 15000,
		.tone_antenna_config_selection = BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_ONE,
		.phy = BT_LE_CS_PROCEDURE_PHY_1M,
		.tx_power_delta = 0x80,
		.preferred_peer_antenna = BT_LE_CS_PROCEDURE_PREFERRED_PEER_ANTENNA_1,
		.snr_control_initiator = BT_LE_CS_INITIATOR_SNR_CONTROL_NOT_USED,
		.snr_control_reflector = BT_LE_CS_REFLECTOR_SNR_CONTROL_NOT_USED,
	};

PRJ.conf

CONFIG_NCS_SAMPLES_DEFAULTS=y
CONFIG_DK_LIBRARY=y

CONFIG_BT=y
CONFIG_BT_SMP=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_MAX_CONN=1
CONFIG_BT_BONDABLE=n

CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_GATT_DYNAMIC_DB=y

CONFIG_BT_CHANNEL_SOUNDING=y
CONFIG_BT_RAS=y
CONFIG_BT_RAS_RREQ=y

CONFIG_BT_SCAN=y
CONFIG_BT_SCAN_FILTER_ENABLE=y
CONFIG_BT_SCAN_UUID_CNT=1
CONFIG_BT_CTLR_PHY_2M=n
# The Ranging Profile recommends a MTU of at least 247 octets.
CONFIG_BT_L2CAP_TX_MTU=498
CONFIG_BT_BUF_ACL_TX_SIZE=502
CONFIG_BT_BUF_ACL_RX_SIZE=502
CONFIG_BT_ATT_PREPARE_COUNT=3
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251

# This allows CS and ACL to use different PHYs
# CONFIG_BT_TRANSMIT_POWER_CONTROL=y

# This improves the performance of floating-point operations
CONFIG_FPU=y
CONFIG_FPU_SHARING=y

CONFIG_CBPRINTF_FP_SUPPORT=y
CONFIG_BT_CTLR_TX_PWR_PLUS_4=y

# Enable basic logging
CONFIG_LOG=y
CONFIG_LOG_MODE_DEFERRED=n

# Use RTT as the console backend
CONFIG_USE_SEGGER_RTT=y
CONFIG_RTT_CONSOLE=y
CONFIG_LOG_BACKEND_RTT=y

# Disable UART console and UART logging to avoid conflicts
CONFIG_UART_CONSOLE=n
CONFIG_LOG_BACKEND_UART=n
CONFIG_LOG_DEFAULT_LEVEL=1 
CONFIG_LOG_MAX_LEVEL=1
# Optional: Increase RTT buffer size for lots of logging
CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=1024
CONFIG_SEGGER_RTT_BUFFER_SIZE_DOWN=16
CONFIG_LOG_BUFFER_SIZE=2048

in .config
CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y
CONFIG_CLOCK_CONTROL_NRF_K32SRC_50PPM=y

Parents
  • (updated)

    Hi, 

    1. 1phy data is OK but a lot of negative TOF values which is confusing me. Is there an issue with the hex conversion of this data or something im missing as to why? (obfuscated in bt_ras_rreq_rd_subevent_data_parse "helper for parsing ranging data-formatted buffer"). I'm reminded of the 4-3 byte conversion from the early AOA days...

    2. the 2M phy data is consistent, but always shifted about -7m.Is this just the the current state of the parse helper not accounting for the 2m phy mode? ( changed the .cs_sync_phy & .phy to 2M and enabled 2M in the prj.conf of the initiator, then enabled 2M in prj.conf on refl)

    Firstly, when using RTT-measurements, we highly recommend using 2M phy for syncing, which can be done by setting bt_le_cs_create_config_params.cs_sync_phy = BT_CONN_LE_CS_SYNC_2M_PHY. We see better performance with this internally, which is probably also the reason they say that 2M phy is consistent. 

    When it comes to the -7m shift, it is a little trickier. We've experienced the differences between DKs in terms of internal delays, meaning that the time from the packet enters the antenna until it enters the radio varies. The time for each DK is consistent, but it varies between different DKs. Since RTT is very sensitive, small differences create big differences in the final result. The fact that the delays in the DKs vary sort of adds the need to do a "calibration-routine", where you put the DKs next to each other and measure the default offset. We currently do not have any other good solutions to this.. 

     

    Also, a negative ToF value is not wrong in the sense that some conversion has gone wrong or something. It's just because our measurements are not accurate enough.

      3. Any suggestions on more levers to pull to improve this setup? Not using channel switching or a subevent confused me in the setup quite a bit.

      I don't understand the question. The devices will use channel switching and subevents when running the Channel Sounding procedures, but the order of the channels and when the subevents are run is not exposed to the user. The channels are shuffled with a common seed, and the subevents are scheduled according to other activities in the radio.

      Regards,
      Amanda H.

    Reply Children
    No Data
    Related