Skip to content

Commit 9da4622

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 9da4622

File tree

2 files changed

+101
-17
lines changed

2 files changed

+101
-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

+100-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,20 @@ struct processing_context {
48103
enum bt_conn_le_cs_role role;
49104
};
50105

106+
static uint8_t get_antenna_path(uint8_t n_ap, uint8_t antenna_path_permutation, uint8_t i)
107+
{
108+
if (n_ap == 2) {
109+
return antenna_path_lut_n_ap_2[antenna_path_permutation][i];
110+
}
111+
if (n_ap == 3) {
112+
return antenna_path_lut_n_ap_3[antenna_path_permutation][i];
113+
}
114+
if (n_ap == 4) {
115+
return antenna_path_lut_n_ap_4[antenna_path_permutation][i];
116+
}
117+
return 0;
118+
}
119+
51120
static void calc_complex_product(int32_t z_a_real, int32_t z_a_imag, int32_t z_b_real,
52121
int32_t z_b_imag, int32_t *z_out_real, int32_t *z_out_imag)
53122
{
@@ -107,7 +176,10 @@ static void bubblesort_2(float *array1, float *array2, uint16_t len)
107176
}
108177
}
109178

110-
static float estimate_distance_using_phase_slope(struct iq_sample_and_channel *data, uint8_t len)
179+
static float estimate_distance_using_phase_slope(struct iq_sample_and_channel *data,
180+
uint8_t len,
181+
uint8_t ant_path,
182+
uint8_t *samples_cnt)
111183
{
112184
int32_t combined_i;
113185
int32_t combined_q;
@@ -116,14 +188,15 @@ static float estimate_distance_using_phase_slope(struct iq_sample_and_channel *d
116188
static float frequencies[MAX_NUM_IQ_SAMPLES];
117189

118190
for (uint8_t i = 0; i < len; i++) {
119-
if (!data[i].failed) {
191+
if (!data[i].failed && data[i].antenna_path == ant_path) {
120192
calc_complex_product(data[i].local_iq_sample.i, data[i].local_iq_sample.q,
121193
data[i].peer_iq_sample.i, data[i].peer_iq_sample.q,
122194
&combined_i, &combined_q);
123195

124196
theta[num_angles] = atan2(1.0 * combined_q, 1.0 * combined_i);
125197
frequencies[num_angles] = 1.0 * CS_FREQUENCY_MHZ(data[i].channel);
126198
num_angles++;
199+
*samples_cnt += 1;
127200
}
128201
}
129202

@@ -193,8 +266,8 @@ static void process_tone_info_data(struct processing_context *context,
193266
}
194267

195268
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;
269+
iq_sample_channel_data[context->iq_sample_channel_data_index].antenna_path =
270+
get_antenna_path(context->n_ap, antenna_permutation_index, i);
198271
iq_sample_channel_data[context->iq_sample_channel_data_index].local_iq_sample =
199272
bt_le_cs_parse_pct(local_tone_info[i].phase_correction_term);
200273
iq_sample_channel_data[context->iq_sample_channel_data_index].peer_iq_sample =
@@ -290,6 +363,7 @@ static bool process_step_data(struct bt_le_cs_subevent_step *local_step,
290363
void estimate_distance(struct net_buf_simple *local_steps, struct net_buf_simple *peer_steps,
291364
uint8_t n_ap, enum bt_conn_le_cs_role role)
292365
{
366+
bool distance_measurement_failed = true;
293367
struct processing_context context = {
294368
.rtt_timing_data_index = 0,
295369
.iq_sample_channel_data_index = 0,
@@ -303,24 +377,34 @@ void estimate_distance(struct net_buf_simple *local_steps, struct net_buf_simple
303377
bt_ras_rreq_rd_subevent_data_parse(peer_steps, local_steps, context.role, NULL,
304378
process_step_data, &context);
305379

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

309382
float rtt_based_distance =
310383
estimate_distance_using_time_of_flight(context.rtt_timing_data_index);
311384

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-
318385
if (rtt_based_distance != 0.0f) {
319386
LOG_INF("- Round-Trip Timing method: %f meters (derived from %d samples)",
320387
(double)rtt_based_distance, context.rtt_timing_data_index);
388+
distance_measurement_failed = false;
389+
}
390+
for (int i = 0; i < n_ap; i++) {
391+
uint8_t samples_cnt = 0;
392+
float phase_slope_based_distance = estimate_distance_using_phase_slope(
393+
iq_sample_channel_data,
394+
context.iq_sample_channel_data_index,
395+
i,
396+
&samples_cnt);
397+
398+
if (phase_slope_based_distance != 0.0f) {
399+
LOG_INF("- Phase-Based Ranging method: %f meters" \
400+
"(derived on antenna path %d from %d samples)",
401+
(double)phase_slope_based_distance,
402+
i,
403+
samples_cnt);
404+
distance_measurement_failed = false;
405+
}
321406
}
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);
407+
if (distance_measurement_failed) {
408+
LOG_INF("- A reliable distance estimate could not be computed.");
325409
}
326410
}

0 commit comments

Comments
 (0)