rx: integrate AGC

This commit is contained in:
Thomas Kolb 2022-02-27 16:59:14 +01:00
parent a60b8b1f87
commit 8a8ddc5ea3
4 changed files with 43 additions and 3 deletions

View file

@ -1,3 +1,4 @@
#include <liquid/liquid.h>
#include <math.h> #include <math.h>
#include "correlator.h" #include "correlator.h"
@ -12,6 +13,9 @@
#define HEADER_SIZE_BYTES 4 #define HEADER_SIZE_BYTES 4
#define FREQ_EST_L 8 #define FREQ_EST_L 8
#define AGC_BW_ACQUISITION 2e-2
#define AGC_BW_TRACKING 1e-4
#define SHOW_DEBUG_LOG 1 #define SHOW_DEBUG_LOG 1
#if SHOW_DEBUG_LOG #if SHOW_DEBUG_LOG
@ -22,7 +26,7 @@
static void update_nco_pll(nco_crcf nco, float phase_error) static void update_nco_pll(nco_crcf nco, float phase_error)
{ {
static const float pll_alpha = 0.05f; // phase adjustment factor static const float pll_alpha = 0.20f; // phase adjustment factor
static const float pll_beta = (pll_alpha * pll_alpha) / 2.0f; // frequency adjustment factor static const float pll_beta = (pll_alpha * pll_alpha) / 2.0f; // frequency adjustment factor
nco_crcf_adjust_phase(nco, pll_alpha * phase_error); nco_crcf_adjust_phase(nco, pll_alpha * phase_error);
@ -98,11 +102,17 @@ result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t
static uint8_t symbols_int[1 << 12]; static uint8_t symbols_int[1 << 12];
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;
// Apply the AGC.
float complex agc_out;
agc_crcf_execute(rx->agc, 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.
float complex mixed_sample; float complex mixed_sample;
nco_crcf_step(rx->carrier_coarse_nco); nco_crcf_step(rx->carrier_coarse_nco);
nco_crcf_mix_down(rx->carrier_coarse_nco, samples[i], &mixed_sample); nco_crcf_mix_down(rx->carrier_coarse_nco, agc_out, &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;
@ -118,6 +128,8 @@ result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t
// 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);
agc_crcf_set_bandwidth(rx->agc, AGC_BW_TRACKING);
// go on with decoding the header // go on with decoding the header
rx->state = RX_STATE_HEADER; rx->state = RX_STATE_HEADER;
symbol_counter = 0; symbol_counter = 0;
@ -226,6 +238,14 @@ result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t
break; break;
} }
} }
if(rx->state != last_state) {
if(rx->state == RX_STATE_ACQUISITION) {
// ensure the AGC is in acquisition mode again when
// RX_STATE_ACQUISITION is entered.
agc_crcf_set_bandwidth(rx->agc, AGC_BW_ACQUISITION);
}
}
} }
return OK; return OK;
@ -238,6 +258,10 @@ result_t layer1_rx_init(layer1_rx_t *rx, rx_callback_t callback)
rx->state = RX_STATE_ACQUISITION; rx->state = RX_STATE_ACQUISITION;
// create the AGC
rx->agc = agc_crcf_create();
agc_crcf_set_bandwidth(rx->agc, AGC_BW_ACQUISITION);
// create NCOs for carrier frequency compensation // create NCOs for carrier frequency compensation
rx->carrier_coarse_nco = nco_crcf_create(LIQUID_NCO); rx->carrier_coarse_nco = nco_crcf_create(LIQUID_NCO);
nco_crcf_set_frequency(rx->carrier_coarse_nco, 0.00f); nco_crcf_set_frequency(rx->carrier_coarse_nco, 0.00f);
@ -270,6 +294,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)
{ {
agc_crcf_destroy(rx->agc);
nco_crcf_destroy(rx->carrier_coarse_nco); nco_crcf_destroy(rx->carrier_coarse_nco);
nco_crcf_destroy(rx->carrier_fine_nco); nco_crcf_destroy(rx->carrier_fine_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
{ {
// AGC
agc_crcf agc;
// NCOs for carrier frequency offset correction // NCOs for carrier frequency offset correction
nco_crcf carrier_coarse_nco; nco_crcf carrier_coarse_nco;
nco_crcf carrier_fine_nco; nco_crcf carrier_fine_nco;

View file

@ -32,6 +32,9 @@ void cb_rx(rx_evt_t evt, uint8_t *packet_data, size_t packet_len)
{ {
case RX_EVT_CHECKSUM_ERROR: case RX_EVT_CHECKSUM_ERROR:
fprintf(stderr, "Received a message of %zu bytes, but decoding failed.\n", packet_len); fprintf(stderr, "Received a message of %zu bytes, but decoding failed.\n", packet_len);
fprintf(stderr, "=== FAILED PAYLOAD ===\n");
fprintf(stderr, "%s\n", packet_data);
fprintf(stderr, "=======================\n");
break; break;
case RX_EVT_PACKET_RECEIVED: case RX_EVT_PACKET_RECEIVED:
@ -68,9 +71,10 @@ int main(void)
channel_cccf channel = channel_cccf_create(); channel_cccf channel = channel_cccf_create();
float snr = 8.0f; float snr = 10.0f;
channel_cccf_add_awgn(channel, -snr, snr); channel_cccf_add_awgn(channel, -snr, snr);
channel_cccf_add_carrier_offset(channel, 0.20f, 1.00f); channel_cccf_add_carrier_offset(channel, 0.20f, 1.00f);
channel_cccf_add_shadowing(channel, 1.00f, 0.1f);
// channel // channel
float complex msg_received[burst_len]; float complex msg_received[burst_len];
@ -78,6 +82,12 @@ int main(void)
//memcpy(msg_received, whole_burst, sizeof(whole_burst)); // no noise in channel //memcpy(msg_received, whole_burst, sizeof(whole_burst)); // no noise in channel
channel_cccf_execute_block(channel, whole_burst, burst_len, msg_received); channel_cccf_execute_block(channel, whole_burst, burst_len, msg_received);
// scale the entire signal to give the AGC something to do
for(size_t i = 0; i < burst_len; i++) {
msg_received[i] *= 0.02f;
}
dump_array_cf(msg_received, burst_len, 1.0f, "/tmp/rx.cpx"); dump_array_cf(msg_received, burst_len, 1.0f, "/tmp/rx.cpx");
// ** RX starts here ** // ** RX starts here **

View file

@ -7,6 +7,7 @@ typedef enum {
ERR_NO_MEM, ERR_NO_MEM,
ERR_SIZE, ERR_SIZE,
ERR_LIQUID, ERR_LIQUID,
ERR_SYSCALL // a syscall failed. Use errno to determine the cause.
} result_t; } result_t;
#ifdef DEBUG_LIQUID #ifdef DEBUG_LIQUID