@@ -24,10 +24,65 @@ LOG_MODULE_DECLARE(app_main, LOG_LEVEL_INF);
24
24
#define MAX_NUM_RTT_SAMPLES 256
25
25
#define MAX_NUM_IQ_SAMPLES 256 * CONFIG_BT_RAS_MAX_ANTENNA_PATHS
26
26
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
+
27
82
struct iq_sample_and_channel {
28
83
bool failed ;
29
84
uint8_t channel ;
30
- uint8_t antenna_permutation ;
85
+ uint8_t antenna_path ;
31
86
struct bt_le_cs_iq_sample local_iq_sample ;
32
87
struct bt_le_cs_iq_sample peer_iq_sample ;
33
88
};
@@ -48,6 +103,20 @@ struct processing_context {
48
103
enum bt_conn_le_cs_role role ;
49
104
};
50
105
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
+
51
120
static void calc_complex_product (int32_t z_a_real , int32_t z_a_imag , int32_t z_b_real ,
52
121
int32_t z_b_imag , int32_t * z_out_real , int32_t * z_out_imag )
53
122
{
@@ -107,7 +176,10 @@ static void bubblesort_2(float *array1, float *array2, uint16_t len)
107
176
}
108
177
}
109
178
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 )
111
183
{
112
184
int32_t combined_i ;
113
185
int32_t combined_q ;
@@ -116,14 +188,15 @@ static float estimate_distance_using_phase_slope(struct iq_sample_and_channel *d
116
188
static float frequencies [MAX_NUM_IQ_SAMPLES ];
117
189
118
190
for (uint8_t i = 0 ; i < len ; i ++ ) {
119
- if (!data [i ].failed ) {
191
+ if (!data [i ].failed && data [ i ]. antenna_path == ant_path ) {
120
192
calc_complex_product (data [i ].local_iq_sample .i , data [i ].local_iq_sample .q ,
121
193
data [i ].peer_iq_sample .i , data [i ].peer_iq_sample .q ,
122
194
& combined_i , & combined_q );
123
195
124
196
theta [num_angles ] = atan2 (1.0 * combined_q , 1.0 * combined_i );
125
197
frequencies [num_angles ] = 1.0 * CS_FREQUENCY_MHZ (data [i ].channel );
126
198
num_angles ++ ;
199
+ * samples_cnt += 1 ;
127
200
}
128
201
}
129
202
@@ -193,8 +266,8 @@ static void process_tone_info_data(struct processing_context *context,
193
266
}
194
267
195
268
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 ) ;
198
271
iq_sample_channel_data [context -> iq_sample_channel_data_index ].local_iq_sample =
199
272
bt_le_cs_parse_pct (local_tone_info [i ].phase_correction_term );
200
273
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,
290
363
void estimate_distance (struct net_buf_simple * local_steps , struct net_buf_simple * peer_steps ,
291
364
uint8_t n_ap , enum bt_conn_le_cs_role role )
292
365
{
366
+ bool distance_measurement_failed = true;
293
367
struct processing_context context = {
294
368
.rtt_timing_data_index = 0 ,
295
369
.iq_sample_channel_data_index = 0 ,
@@ -303,24 +377,34 @@ void estimate_distance(struct net_buf_simple *local_steps, struct net_buf_simple
303
377
bt_ras_rreq_rd_subevent_data_parse (peer_steps , local_steps , context .role , NULL ,
304
378
process_step_data , & context );
305
379
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:" );
308
381
309
382
float rtt_based_distance =
310
383
estimate_distance_using_time_of_flight (context .rtt_timing_data_index );
311
384
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
-
318
385
if (rtt_based_distance != 0.0f ) {
319
386
LOG_INF ("- Round-Trip Timing method: %f meters (derived from %d samples)" ,
320
387
(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
+ }
321
406
}
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." );
325
409
}
326
410
}
0 commit comments