rx: improvements made during on-air testing

- limit frequency adjustment range
- pre-filter the baseband signal to remove out-of-band interference
- reset the frequency acquisition periodically (every 30s) if no preamble is found
This commit is contained in:
Thomas Kolb 2022-04-10 21:58:32 +02:00
parent 2d0bf7eeda
commit ec99cedaf4
2 changed files with 43 additions and 3 deletions

View file

@ -10,11 +10,15 @@
#include "rx.h" #include "rx.h"
#include "utils.h"
#define HEADER_SIZE_BYTES 4 #define HEADER_SIZE_BYTES 4
#define FREQ_EST_L 8 #define FREQ_EST_L 8
#define AGC_BW_ACQUISITION 5e-2 #define AGC_BW_ACQUISITION 5e-2f
#define AGC_BW_TRACKING 1e-4 #define AGC_BW_TRACKING 1e-4f
#define MAX_COARSE_FREQ_OFFSET 0.20f
#define SHOW_DEBUG_LOG 0 #define SHOW_DEBUG_LOG 0
@ -83,6 +87,15 @@ static bool acquire_preamble(layer1_rx_t *rx, const float complex sample)
float freq_adjustment = (freq_est / RRC_SPS) * 0.3f; float freq_adjustment = (freq_est / RRC_SPS) * 0.3f;
nco_crcf_adjust_frequency(rx->carrier_coarse_nco, freq_adjustment); nco_crcf_adjust_frequency(rx->carrier_coarse_nco, freq_adjustment);
float actual_freq = nco_crcf_get_frequency(rx->carrier_coarse_nco);
if(actual_freq > MAX_COARSE_FREQ_OFFSET) {
fprintf(stderr, ">");
nco_crcf_set_frequency(rx->carrier_coarse_nco, MAX_COARSE_FREQ_OFFSET);
} else if(actual_freq < -MAX_COARSE_FREQ_OFFSET) {
fprintf(stderr, "<");
nco_crcf_set_frequency(rx->carrier_coarse_nco, -MAX_COARSE_FREQ_OFFSET);
}
DEBUG_LOG("Frequency adjustment: %.6f - carrier frequency: %.6f\n", freq_adjustment, nco_crcf_get_frequency(rx->carrier_coarse_nco)); DEBUG_LOG("Frequency adjustment: %.6f - carrier frequency: %.6f\n", freq_adjustment, nco_crcf_get_frequency(rx->carrier_coarse_nco));
freq_est_history_write_idx = 0; freq_est_history_write_idx = 0;
@ -101,12 +114,19 @@ result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t
static size_t symbol_counter = 0; static size_t symbol_counter = 0;
static uint8_t symbols_int[1 << 12]; static uint8_t symbols_int[1 << 12];
float complex samples2dump[sample_count];
size_t nsamples2dump = 0;
// filter the input
float complex filtered_samples[sample_count];
firfilt_crcf_execute_block(rx->channel_filter, (float complex *)samples, sample_count, filtered_samples);
for(unsigned int i = 0; i < sample_count; i++) { for(unsigned int i = 0; i < sample_count; i++) {
rx_state_t last_state = rx->state; rx_state_t last_state = rx->state;
// Apply the AGC. // Apply the AGC.
float complex agc_out; float complex agc_out;
agc_crcf_execute(rx->agc, samples[i], &agc_out); agc_crcf_execute(rx->agc, filtered_samples[i], &agc_out);
// Mix the input signal with the carrier NCO, which oscillates at the // Mix the input signal with the carrier NCO, which oscillates at the
// frequency coarsly estimated so far. // frequency coarsly estimated so far.
@ -114,6 +134,8 @@ result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t
nco_crcf_step(rx->carrier_coarse_nco); nco_crcf_step(rx->carrier_coarse_nco);
nco_crcf_mix_down(rx->carrier_coarse_nco, agc_out, &mixed_sample); nco_crcf_mix_down(rx->carrier_coarse_nco, agc_out, &mixed_sample);
samples2dump[nsamples2dump++] = mixed_sample;
// run the timing synchronizer (works even with shifted frequency) // run the timing synchronizer (works even with shifted frequency)
unsigned int out_len; unsigned int out_len;
float complex symsync_out; float complex symsync_out;
@ -124,6 +146,14 @@ result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t
// Try to acquire packets by synchronizing the frequency // Try to acquire packets by synchronizing the frequency
// (symbol-independent search) and correlating the preamble. // (symbol-independent search) and correlating the preamble.
case RX_STATE_ACQUISITION: case RX_STATE_ACQUISITION:
// reset the acquisition periodically if the preamble is not found.
symbol_counter++;
if(symbol_counter == 30 * SYMBOL_RATE) {
symbol_counter = 0;
nco_crcf_set_frequency(rx->carrier_coarse_nco, 0.0f);
nco_crcf_set_phase(rx->carrier_coarse_nco, 0.0f);
}
if(acquire_preamble(rx, symsync_out)) { if(acquire_preamble(rx, symsync_out)) {
// Preamble found and frequency corrected! // Preamble found and frequency corrected!
rx->callback(RX_EVT_PREAMBLE_FOUND, NULL, 0); rx->callback(RX_EVT_PREAMBLE_FOUND, NULL, 0);
@ -250,6 +280,8 @@ result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t
} }
} }
dump_array_cf(samples2dump, nsamples2dump, 1.0f, "/tmp/rx_dbg.cpx64");
return OK; return OK;
} }
@ -260,6 +292,9 @@ result_t layer1_rx_init(layer1_rx_t *rx, rx_callback_t callback)
rx->state = RX_STATE_ACQUISITION; rx->state = RX_STATE_ACQUISITION;
// create channel FIR filter to remove out-of-band interferers
rx->channel_filter = firfilt_crcf_create_kaiser(21, 0.28f * RRC_SPS / 4, 60.0f, 0.0f);
// create the AGC // create the AGC
rx->agc = agc_crcf_create(); rx->agc = agc_crcf_create();
agc_crcf_set_bandwidth(rx->agc, AGC_BW_ACQUISITION); agc_crcf_set_bandwidth(rx->agc, AGC_BW_ACQUISITION);
@ -296,6 +331,8 @@ result_t layer1_rx_init(layer1_rx_t *rx, rx_callback_t callback)
result_t layer1_rx_shutdown(layer1_rx_t *rx) result_t layer1_rx_shutdown(layer1_rx_t *rx)
{ {
firfilt_crcf_destroy(rx->channel_filter);
agc_crcf_destroy(rx->agc); agc_crcf_destroy(rx->agc);
nco_crcf_destroy(rx->carrier_coarse_nco); nco_crcf_destroy(rx->carrier_coarse_nco);

View file

@ -27,6 +27,9 @@ typedef void (*rx_callback_t)(rx_evt_t evt, uint8_t *packet_data, size_t packet_
typedef struct typedef struct
{ {
// Input channel filter
firfilt_crcf channel_filter;
// AGC // AGC
agc_crcf agc; agc_crcf agc;