From 91db4e1f757c8245dfe2c56d6db713817298809a Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Mon, 8 Apr 2024 22:03:09 +0200 Subject: [PATCH] rx: implement squelch + symsync reset Whenever the squelch opens, the symsync is reset to prevent lock-up in that module due to noise. --- impl/src/layer1/rx.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ impl/src/layer1/rx.h | 2 ++ 2 files changed, 64 insertions(+) diff --git a/impl/src/layer1/rx.c b/impl/src/layer1/rx.c index e0c503b..802251c 100644 --- a/impl/src/layer1/rx.c +++ b/impl/src/layer1/rx.c @@ -148,6 +148,49 @@ static bool acquire_preamble(layer1_rx_t *rx, const float complex sample, bool d } +typedef enum squelch_state_t { + SQUELCH_CLOSED, + SQUELCH_OPEN, + SQUELCH_JUST_OPENED, +}; + +static enum squelch_state_t update_and_check_squelch(layer1_rx_t *rx, unsigned int sample_idx) +{ + float level = agc_crcf_get_rssi(rx->agc); + enum squelch_state_t result = SQUELCH_CLOSED; + + if((sample_idx & 0xFF) == 0) { // every 256 samples + if(level < rx->noise_floor_level) { + rx->noise_floor_level = level; + } else { + level += 1e-3; // slowly increase the measured noise floor level to compensate for drift + } + agc_crcf_squelch_set_threshold(rx->agc, rx->noise_floor_level + 3.0f); // in dB + } + + switch(agc_crcf_squelch_get_status(rx->agc)) { + case LIQUID_AGC_SQUELCH_RISE: + DEBUG_LOG("Squelch disabled at RSSI = %.3f dB\n", level); + result = SQUELCH_JUST_OPENED; + break; + + case LIQUID_AGC_SQUELCH_SIGNALHI: + result = SQUELCH_OPEN; + break; + + case LIQUID_AGC_SQUELCH_FALL: + DEBUG_LOG("Squelch enabled at RSSI = %.3f dB\n", level); + case LIQUID_AGC_SQUELCH_SIGNALLO: + case LIQUID_AGC_SQUELCH_ENABLED: + case LIQUID_AGC_SQUELCH_TIMEOUT: + result = SQUELCH_CLOSED; + break; + } + + return result; +} + + result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t sample_count) { static size_t symbol_counter = 0; @@ -174,6 +217,20 @@ result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t float complex agc_out; agc_crcf_execute(rx->agc, filtered_samples[i], &agc_out); + switch(update_and_check_squelch(rx, i)) { + case SQUELCH_CLOSED: + // ignore this sample + continue; + + case SQUELCH_JUST_OPENED: + symsync_crcf_reset(rx->symsync); + // fall through + case SQUELCH_OPEN: + // sample processing continues + break; + } + + // Mix the input signal with the carrier NCO, which oscillates at the // frequency coarsly estimated so far. float complex mixed_sample; @@ -396,6 +453,11 @@ result_t layer1_rx_init(layer1_rx_t *rx, rx_callback_t callback) rx->agc = agc_crcf_create(); agc_crcf_set_bandwidth(rx->agc, AGC_BW_ACQUISITION); + // set up squelch + rx->noise_floor_level = 0.0f; + agc_crcf_squelch_set_threshold(rx->agc, rx->noise_floor_level + 3.0f); // in dB + agc_crcf_squelch_enable(rx->agc); + // create NCOs for carrier frequency compensation rx->carrier_coarse_nco = nco_crcf_create(LIQUID_NCO); nco_crcf_set_frequency(rx->carrier_coarse_nco, 0.00f); diff --git a/impl/src/layer1/rx.h b/impl/src/layer1/rx.h index 38f1cb1..cb6230a 100644 --- a/impl/src/layer1/rx.h +++ b/impl/src/layer1/rx.h @@ -34,6 +34,8 @@ typedef struct // AGC agc_crcf agc; + float noise_floor_level; + // NCOs for carrier frequency offset correction nco_crcf carrier_coarse_nco; nco_crcf carrier_fine_nco;