rx: integrate AGC
This commit is contained in:
parent
a60b8b1f87
commit
8a8ddc5ea3
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 **
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue