From 465d9a1c267d23a8e09deedfa6a4a314a6396807 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Thu, 3 Feb 2022 22:18:24 +0100 Subject: [PATCH] main: restructure state management; evaluate a found preamble --- impl/src/main.c | 188 +++++++++++++++++++++++++++++------------------- 1 file changed, 114 insertions(+), 74 deletions(-) diff --git a/impl/src/main.c b/impl/src/main.c index dcef535..9630e61 100644 --- a/impl/src/main.c +++ b/impl/src/main.c @@ -18,6 +18,17 @@ typedef enum { RX_STATE_DATA, } rx_state_t; + +void print_complex_array(const char *varname, float complex const *array, size_t len) +{ + printf("%s=np.array([%f%+fj", varname, crealf(array[0]), cimagf(array[0])); + for(size_t k = 1; k < len; k++) { + printf(", %f%+fj", crealf(array[k]), cimagf(array[k])); + } + printf("])\n"); +} + + int main(void) { uint8_t msg_org[] = "Hello Liquid! This is the message to transmit. Hopefully it can be decoded correctly..."; @@ -28,7 +39,7 @@ int main(void) channel_cccf channel = channel_cccf_create(); - float snr = 50.0f; + float snr = 20.0f; channel_cccf_add_awgn(channel, -snr, snr); channel_cccf_add_carrier_offset(channel, 0.20f, 1.00f); @@ -119,81 +130,110 @@ int main(void) unsigned int out_len; symsync_crcf_execute(symsync, &mixed_sample, 1, symsync_out + symsync_out_len, &out_len); - switch(rx_state) { - case RX_STATE_ACQUISITION: - if(out_len != 0) { - // for all the output samples produced, run the frequency - // estimator. This is an implementation that works with unknown - // BPSK symbols and therefore can be used during ramp-up and - // preamble. - - if(out_len < FREQ_EST_L) { - memmove(phase_history, - phase_history + out_len, - (FREQ_EST_L-out_len) * sizeof(phase_history[0])); - } - - for(unsigned int j = 0; j < out_len; j++) { - float complex *psymbol = symsync_out + symsync_out_len + j; - - // square the symbol to remove BPSK ambiguity - float phase = cargf((*psymbol) * (*psymbol)); - - phase_history[FREQ_EST_L - out_len + j] = phase; - } - - // update the frequency estimate - if(((i/RRC_SPS) % FREQ_EST_L) == 0) { - float unwrapped_phase_history[FREQ_EST_L]; - memcpy(unwrapped_phase_history, phase_history, sizeof(unwrapped_phase_history)); - liquid_unwrap_phase(unwrapped_phase_history, FREQ_EST_L); - - // calculate slope of LMS-fitted line - float mean_index = (FREQ_EST_L-1) / 2.0f; - float mean_phase = 0.0f; - for(unsigned int j = 0; j < FREQ_EST_L; j++) { - mean_phase += unwrapped_phase_history[j]; - } - mean_phase /= FREQ_EST_L; - - float numerator = 0.0f; - float denominator = 0.0f; - for(unsigned int j = 0; j < FREQ_EST_L; j++) { - float delta_index = j - mean_index; - numerator += delta_index * (unwrapped_phase_history[j] - mean_phase); - denominator += delta_index*delta_index; - } - - float lms_phase_change = numerator / denominator; - - float freq_adjustment = (lms_phase_change / RRC_SPS / 2) * 0.3f; - nco_crcf_adjust_frequency(carrier_nco, freq_adjustment); - - printf("Frequency adjustment: %.6f - carrier frequency: %.6f\n", freq_adjustment, nco_crcf_get_frequency(carrier_nco)); - - if(i/RRC_SPS == 2*FREQ_EST_L) { - float complex tmp[FREQ_EST_L]; - for(unsigned int j = 0; j < FREQ_EST_L; j++) { - tmp[j] = unwrapped_phase_history[j]; - } - dump_array_cf(tmp, FREQ_EST_L, 1.0f, "/tmp/freq_est.cpx"); - printf("MARK\n"); - } - } - } - break; - - case RX_STATE_HEADER: - case RX_STATE_DATA: - break; - } - - // preamble search if(out_len != 0) { - float complex corr_out = correlator_step(&preamble_correlator, symsync_out[symsync_out_len]); + float complex corr_out; + switch(rx_state) { + // Try to acquire packets by synchronizing the frequency + // (symbol-independent search) and correlating the preamble. + case RX_STATE_ACQUISITION: + // preamble search + corr_out = correlator_step(&preamble_correlator, symsync_out[symsync_out_len]); - if(cabsf(corr_out) > 0.5f * preamble_get_symbol_count()) { - printf("Preamble found at sample %u: %.3f > %.3f\n", i/RRC_SPS, cabsf(corr_out), 0.5f * preamble_get_symbol_count()); + if(cabsf(corr_out) > 0.5f * preamble_get_symbol_count()) { + // Preamble found! + printf("Preamble found at symbol %u: %.3f > %.3f\n", i/RRC_SPS, cabsf(corr_out), 0.5f * preamble_get_symbol_count()); + + float mean_phase_error = correlator_get_mean_phase_deviation(&preamble_correlator); + float mean_frequency_error = correlator_get_mean_frequency_deviation(&preamble_correlator); + + printf("Preamble phase deviation: %.6f rad\n", mean_phase_error); + printf("Preamble frequency deviation: %.6f rad/symbol\n", mean_frequency_error); + + // adjust the frequency and phase of the NCO with the estimations from the preamble + nco_crcf_adjust_frequency(carrier_nco, -mean_frequency_error / RRC_SPS); + nco_crcf_adjust_phase(carrier_nco, mean_phase_error); + + printf("New estimated carrier frequency: %.6f\n", nco_crcf_get_frequency(carrier_nco)); + + float complex input_history[preamble_get_symbol_count()]; + correlator_get_input_history(&preamble_correlator, input_history); + + printf("import numpy as np\n"); + printf("import matplotlib.pyplot as pp\n"); + print_complex_array("pre", preamble_get_symbols(), preamble_get_symbol_count()); + print_complex_array("recv", input_history, preamble_get_symbol_count()); + printf("pp.plot(recv * pre.conj())\n"); + printf("pp.show()\n"); + + // receive and decode the header + rx_state = RX_STATE_HEADER; + } else { + // preamble not found. + + // for all the output samples produced, run the frequency + // estimator. This is an implementation that works with unknown + // BPSK symbols and therefore can be used during ramp-up and + // preamble. + + if(out_len < FREQ_EST_L) { + memmove(phase_history, + phase_history + out_len, + (FREQ_EST_L-out_len) * sizeof(phase_history[0])); + } + + for(unsigned int j = 0; j < out_len; j++) { + float complex *psymbol = symsync_out + symsync_out_len + j; + + // square the symbol to remove BPSK ambiguity + float phase = cargf((*psymbol) * (*psymbol)); + + phase_history[FREQ_EST_L - out_len + j] = phase; + } + + // update the frequency estimate + if(((i/RRC_SPS) % FREQ_EST_L) == 0) { + float unwrapped_phase_history[FREQ_EST_L]; + memcpy(unwrapped_phase_history, phase_history, sizeof(unwrapped_phase_history)); + liquid_unwrap_phase(unwrapped_phase_history, FREQ_EST_L); + + // calculate slope of LMS-fitted line + float mean_index = (FREQ_EST_L-1) / 2.0f; + float mean_phase = 0.0f; + for(unsigned int j = 0; j < FREQ_EST_L; j++) { + mean_phase += unwrapped_phase_history[j]; + } + mean_phase /= FREQ_EST_L; + + float numerator = 0.0f; + float denominator = 0.0f; + for(unsigned int j = 0; j < FREQ_EST_L; j++) { + float delta_index = j - mean_index; + numerator += delta_index * (unwrapped_phase_history[j] - mean_phase); + denominator += delta_index*delta_index; + } + + float lms_phase_change = numerator / denominator; + + float freq_adjustment = (lms_phase_change / RRC_SPS / 2) * 0.5f; + nco_crcf_adjust_frequency(carrier_nco, freq_adjustment); + + printf("Frequency adjustment: %.6f - carrier frequency: %.6f\n", freq_adjustment, nco_crcf_get_frequency(carrier_nco)); + + if(i/RRC_SPS == 2*FREQ_EST_L) { + float complex tmp[FREQ_EST_L]; + for(unsigned int j = 0; j < FREQ_EST_L; j++) { + tmp[j] = unwrapped_phase_history[j]; + } + dump_array_cf(tmp, FREQ_EST_L, 1.0f, "/tmp/freq_est.cpx"); + printf("MARK\n"); + } + } + } + break; + + case RX_STATE_HEADER: + case RX_STATE_DATA: + break; } }