Skip to content

Commit b75f85e

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 b75f85e

File tree

1 file changed

+93
-13
lines changed

1 file changed

+93
-13
lines changed

samples/bluetooth/channel_sounding_ras_initiator/src/distance_estimation.c

+93-13
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,66 @@ 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+
uint8_t antenna_path_lut_n_ap_2[2][3] =
35+
{
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+
uint8_t antenna_path_lut_n_ap_3[6][4] =
43+
{
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+
uint8_t antenna_path_lut_n_ap_4[24][5] =
55+
{
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;
3085
uint8_t antenna_permutation;
86+
uint8_t antenna_path;
3187
struct bt_le_cs_iq_sample local_iq_sample;
3288
struct bt_le_cs_iq_sample peer_iq_sample;
3389
};
@@ -48,6 +104,20 @@ struct processing_context {
48104
enum bt_conn_le_cs_role role;
49105
};
50106

107+
static uint8_t get_antenna_path(uint8_t n_ap, uint8_t antenna_path_permutation, uint8_t i)
108+
{
109+
if (n_ap == 2) {
110+
return antenna_path_lut_n_ap_2[antenna_path_permutation][i];
111+
}
112+
if (n_ap == 3) {
113+
return antenna_path_lut_n_ap_3[antenna_path_permutation][i];
114+
}
115+
if (n_ap == 4) {
116+
return antenna_path_lut_n_ap_4[antenna_path_permutation][i];
117+
}
118+
return 0;
119+
}
120+
51121
static void calc_complex_product(int32_t z_a_real, int32_t z_a_imag, int32_t z_b_real,
52122
int32_t z_b_imag, int32_t *z_out_real, int32_t *z_out_imag)
53123
{
@@ -107,7 +177,7 @@ static void bubblesort_2(float *array1, float *array2, uint16_t len)
107177
}
108178
}
109179

110-
static float estimate_distance_using_phase_slope(struct iq_sample_and_channel *data, uint8_t len)
180+
static float estimate_distance_using_phase_slope(struct iq_sample_and_channel *data, uint8_t len, uint8_t ant_path, uint8_t *samples_cnt)
111181
{
112182
int32_t combined_i;
113183
int32_t combined_q;
@@ -116,14 +186,15 @@ static float estimate_distance_using_phase_slope(struct iq_sample_and_channel *d
116186
static float frequencies[MAX_NUM_IQ_SAMPLES];
117187

118188
for (uint8_t i = 0; i < len; i++) {
119-
if (!data[i].failed) {
189+
if (!data[i].failed && data[i].antenna_path == ant_path) {
120190
calc_complex_product(data[i].local_iq_sample.i, data[i].local_iq_sample.q,
121191
data[i].peer_iq_sample.i, data[i].peer_iq_sample.q,
122192
&combined_i, &combined_q);
123193

124194
theta[num_angles] = atan2(1.0 * combined_q, 1.0 * combined_i);
125195
frequencies[num_angles] = 1.0 * CS_FREQUENCY_MHZ(data[i].channel);
126196
num_angles++;
197+
*samples_cnt += 1;
127198
}
128199
}
129200

@@ -195,6 +266,8 @@ static void process_tone_info_data(struct processing_context *context,
195266
iq_sample_channel_data[context->iq_sample_channel_data_index].channel = channel;
196267
iq_sample_channel_data[context->iq_sample_channel_data_index].antenna_permutation =
197268
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,30 @@ 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, context.iq_sample_channel_data_index, i, &samples_cnt);
394+
395+
if (phase_slope_based_distance != 0.0f) {
396+
LOG_INF("- Phase-Based Ranging method: %f meters (derived on antenna path %d from %d samples)",
397+
(double)phase_slope_based_distance,
398+
i,
399+
samples_cnt);
400+
distance_measurement_failed = false;
401+
}
321402
}
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);
403+
if (distance_measurement_failed) {
404+
LOG_INF("- A reliable distance estimate could not be computed.");
325405
}
326406
}

0 commit comments

Comments
 (0)