Skip to content

Commit 6acb707

Browse files
committed
samples: bluetooth: distance measurement multiantenna improvements
added better handling of multiple antenna path in Channel Sounding Initiator distance estimation algorithm. Now distance is calculated and printed separately for each antenna path Signed-off-by: Ivan Iushkov <ivan.iushkov@nordicsemi.no>
1 parent 76259e0 commit 6acb707

File tree

2 files changed

+103
-17
lines changed

2 files changed

+103
-17
lines changed

samples/bluetooth/channel_sounding_ras_initiator/README.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ After programming the sample to your development kit, you can test it by connect
6666
I: Ranging data get completed for ranging counter 0
6767
I: Estimated distance to reflector:
6868
I: - Round-Trip Timing method: X.XXXXX meters (derived from X samples)
69-
I: - Phase-Based Ranging method: X.XXXXX meters (derived from X samples)
69+
I: - Phase-Based Ranging method: X.XXXXX meters (derived on antenna path A from X samples)
7070

7171
Dependencies
7272
************

samples/bluetooth/channel_sounding_ras_initiator/src/distance_estimation.c

+102-16
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,65 @@ LOG_MODULE_DECLARE(app_main, LOG_LEVEL_INF);
2424
#define MAX_NUM_RTT_SAMPLES 256
2525
#define MAX_NUM_IQ_SAMPLES 256 * CONFIG_BT_RAS_MAX_ANTENNA_PATHS
2626

27+
#define A1 (0)
28+
#define A2 (1)
29+
#define A3 (2)
30+
#define A4 (3)
31+
32+
/* Bluetooth Core Specification 6.0, Table 4.13, Antenna Path Permutation for N_AP=2.
33+
* The last element corresponds to extension slot
34+
*/
35+
static uint8_t antenna_path_lut_n_ap_2[2][3] = {
36+
{A1, A2, A2},
37+
{A2, A1, A1},
38+
};
39+
40+
/* Bluetooth Core Specification 6.0, Table 4.14, Antenna Path Permutation for N_AP=3.
41+
* The last element corresponds to extension slot
42+
*/
43+
static uint8_t antenna_path_lut_n_ap_3[6][4] = {
44+
{A1, A2, A3, A3},
45+
{A2, A1, A3, A3},
46+
{A1, A3, A2, A2},
47+
{A3, A1, A2, A2},
48+
{A3, A2, A1, A1},
49+
{A2, A3, A1, A1},
50+
};
51+
52+
/* Bluetooth Core Specification 6.0, Table 4.15, Antenna Path Permutation for N_AP=4.
53+
* The last element corresponds to extension slot
54+
*/
55+
static uint8_t antenna_path_lut_n_ap_4[24][5] = {
56+
{A1, A2, A3, A4, A4},
57+
{A2, A1, A3, A4, A4},
58+
{A1, A3, A2, A4, A4},
59+
{A3, A1, A2, A4, A4},
60+
{A3, A2, A1, A4, A4},
61+
{A2, A3, A1, A4, A4},
62+
{A1, A2, A4, A3, A3},
63+
{A2, A1, A4, A3, A3},
64+
{A1, A4, A2, A3, A3},
65+
{A4, A1, A2, A3, A3},
66+
{A4, A2, A1, A3, A3},
67+
{A2, A4, A1, A3, A3},
68+
{A1, A4, A3, A2, A2},
69+
{A4, A1, A3, A2, A2},
70+
{A1, A3, A4, A2, A2},
71+
{A3, A1, A4, A2, A2},
72+
{A3, A4, A1, A2, A2},
73+
{A4, A3, A1, A2, A2},
74+
{A4, A2, A3, A1, A1},
75+
{A2, A4, A3, A1, A1},
76+
{A4, A3, A2, A1, A1},
77+
{A3, A4, A2, A1, A1},
78+
{A3, A2, A4, A1, A1},
79+
{A2, A3, A4, A1, A1},
80+
};
81+
2782
struct iq_sample_and_channel {
2883
bool failed;
2984
uint8_t channel;
30-
uint8_t antenna_permutation;
85+
uint8_t antenna_path;
3186
struct bt_le_cs_iq_sample local_iq_sample;
3287
struct bt_le_cs_iq_sample peer_iq_sample;
3388
};
@@ -48,6 +103,22 @@ struct processing_context {
48103
enum bt_conn_le_cs_role role;
49104
};
50105

106+
static uint8_t get_antenna_path(uint8_t n_ap,
107+
uint8_t antenna_path_permutation_index,
108+
uint8_t antenna_index)
109+
{
110+
if (n_ap == 2) {
111+
return antenna_path_lut_n_ap_2[antenna_path_permutation_index][antenna_index];
112+
}
113+
if (n_ap == 3) {
114+
return antenna_path_lut_n_ap_3[antenna_path_permutation_index][antenna_index];
115+
}
116+
if (n_ap == 4) {
117+
return antenna_path_lut_n_ap_4[antenna_path_permutation_index][antenna_index];
118+
}
119+
return 0;
120+
}
121+
51122
static void calc_complex_product(int32_t z_a_real, int32_t z_a_imag, int32_t z_b_real,
52123
int32_t z_b_imag, int32_t *z_out_real, int32_t *z_out_imag)
53124
{
@@ -107,7 +178,10 @@ static void bubblesort_2(float *array1, float *array2, uint16_t len)
107178
}
108179
}
109180

110-
static float estimate_distance_using_phase_slope(struct iq_sample_and_channel *data, uint8_t len)
181+
static float estimate_distance_using_phase_slope(struct iq_sample_and_channel *data,
182+
uint8_t len,
183+
uint8_t ant_path,
184+
uint8_t *samples_cnt)
111185
{
112186
int32_t combined_i;
113187
int32_t combined_q;
@@ -116,14 +190,15 @@ static float estimate_distance_using_phase_slope(struct iq_sample_and_channel *d
116190
static float frequencies[MAX_NUM_IQ_SAMPLES];
117191

118192
for (uint8_t i = 0; i < len; i++) {
119-
if (!data[i].failed) {
193+
if (!data[i].failed && data[i].antenna_path == ant_path) {
120194
calc_complex_product(data[i].local_iq_sample.i, data[i].local_iq_sample.q,
121195
data[i].peer_iq_sample.i, data[i].peer_iq_sample.q,
122196
&combined_i, &combined_q);
123197

124198
theta[num_angles] = atan2(1.0 * combined_q, 1.0 * combined_i);
125199
frequencies[num_angles] = 1.0 * CS_FREQUENCY_MHZ(data[i].channel);
126200
num_angles++;
201+
*samples_cnt += 1;
127202
}
128203
}
129204

@@ -193,8 +268,8 @@ static void process_tone_info_data(struct processing_context *context,
193268
}
194269

195270
iq_sample_channel_data[context->iq_sample_channel_data_index].channel = channel;
196-
iq_sample_channel_data[context->iq_sample_channel_data_index].antenna_permutation =
197-
antenna_permutation_index;
271+
iq_sample_channel_data[context->iq_sample_channel_data_index].antenna_path =
272+
get_antenna_path(context->n_ap, antenna_permutation_index, i);
198273
iq_sample_channel_data[context->iq_sample_channel_data_index].local_iq_sample =
199274
bt_le_cs_parse_pct(local_tone_info[i].phase_correction_term);
200275
iq_sample_channel_data[context->iq_sample_channel_data_index].peer_iq_sample =
@@ -290,6 +365,7 @@ static bool process_step_data(struct bt_le_cs_subevent_step *local_step,
290365
void estimate_distance(struct net_buf_simple *local_steps, struct net_buf_simple *peer_steps,
291366
uint8_t n_ap, enum bt_conn_le_cs_role role)
292367
{
368+
bool distance_measurement_failed = true;
293369
struct processing_context context = {
294370
.rtt_timing_data_index = 0,
295371
.iq_sample_channel_data_index = 0,
@@ -303,24 +379,34 @@ void estimate_distance(struct net_buf_simple *local_steps, struct net_buf_simple
303379
bt_ras_rreq_rd_subevent_data_parse(peer_steps, local_steps, context.role, NULL,
304380
process_step_data, &context);
305381

306-
float phase_slope_based_distance = estimate_distance_using_phase_slope(
307-
iq_sample_channel_data, context.iq_sample_channel_data_index);
382+
LOG_INF("Estimated distance to reflector:");
308383

309384
float rtt_based_distance =
310385
estimate_distance_using_time_of_flight(context.rtt_timing_data_index);
311386

312-
if (rtt_based_distance == 0.0f && phase_slope_based_distance == 0.0f) {
313-
LOG_INF("A reliable distance estimate could not be computed.");
314-
} else {
315-
LOG_INF("Estimated distance to reflector:");
316-
}
317-
318387
if (rtt_based_distance != 0.0f) {
319388
LOG_INF("- Round-Trip Timing method: %f meters (derived from %d samples)",
320389
(double)rtt_based_distance, context.rtt_timing_data_index);
390+
distance_measurement_failed = false;
391+
}
392+
for (int i = 0; i < n_ap; i++) {
393+
uint8_t samples_cnt = 0;
394+
float phase_slope_based_distance = estimate_distance_using_phase_slope(
395+
iq_sample_channel_data,
396+
context.iq_sample_channel_data_index,
397+
i,
398+
&samples_cnt);
399+
400+
if (phase_slope_based_distance != 0.0f) {
401+
LOG_INF("- Phase-Based Ranging method: %f meters "
402+
"(derived on antenna path %d from %d samples)",
403+
(double)phase_slope_based_distance,
404+
i,
405+
samples_cnt);
406+
distance_measurement_failed = false;
407+
}
321408
}
322-
if (phase_slope_based_distance != 0.0f) {
323-
LOG_INF("- Phase-Based Ranging method: %f meters (derived from %d samples)",
324-
(double)phase_slope_based_distance, context.iq_sample_channel_data_index);
409+
if (distance_measurement_failed) {
410+
LOG_INF("- A reliable distance estimate could not be computed.");
325411
}
326412
}

0 commit comments

Comments
 (0)