diff --git a/impl/CMakeLists.txt b/impl/CMakeLists.txt index 4d8bab0..23d9227 100644 --- a/impl/CMakeLists.txt +++ b/impl/CMakeLists.txt @@ -19,6 +19,8 @@ set(sources src/preamble.c src/transmission.h src/transmission.c + src/correlator.h + src/correlator.c ) include_directories( diff --git a/impl/src/main.c b/impl/src/main.c index 972539c..dcef535 100644 --- a/impl/src/main.c +++ b/impl/src/main.c @@ -4,11 +4,19 @@ #include #include +#include "results.h" #include "utils.h" #include "packet_mod.h" #include "config.h" #include "preamble.h" #include "transmission.h" +#include "correlator.h" + +typedef enum { + RX_STATE_ACQUISITION, + RX_STATE_HEADER, + RX_STATE_DATA, +} rx_state_t; int main(void) { @@ -93,6 +101,13 @@ int main(void) float phase_history[FREQ_EST_L]; memset(phase_history, 0, sizeof(phase_history)); + // General receiver state + rx_state_t rx_state = RX_STATE_ACQUISITION; + + // Correlator for preamble search + correlator_ctx_t preamble_correlator; + correlator_init(&preamble_correlator, preamble_get_symbols(), preamble_get_symbol_count()); + for(unsigned int i = 0; i < burst_len; i++) { // Mix the input signal with the carrier NCO, which oscillates at the // frequency estimated so far. @@ -100,68 +115,85 @@ int main(void) nco_crcf_step(carrier_nco); nco_crcf_mix_down(carrier_nco, msg_received[i], &mixed_sample); - // run the timing synchronizer (works even with shifted frequency + // run the timing synchronizer (works even with shifted frequency) unsigned int out_len; symsync_crcf_execute(symsync, &mixed_sample, 1, symsync_out + symsync_out_len, &out_len); - 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. + 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]; + 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"); + } } - 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]); + + 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()); } }