2021-10-17 19:26:38 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
2022-01-30 20:05:20 +01:00
|
|
|
#include <math.h>
|
2021-10-17 19:26:38 +02:00
|
|
|
#include <liquid/liquid.h>
|
|
|
|
|
|
|
|
#include "utils.h"
|
|
|
|
#include "packet_mod.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "preamble.h"
|
2022-01-29 22:05:17 +01:00
|
|
|
#include "transmission.h"
|
2021-10-17 19:26:38 +02:00
|
|
|
|
|
|
|
int main(void)
|
|
|
|
{
|
|
|
|
uint8_t msg_org[] = "Hello Liquid! This is the message to transmit. Hopefully it can be decoded correctly...";
|
|
|
|
|
|
|
|
fec q = fec_create(CHANNEL_CODE, NULL);
|
|
|
|
|
|
|
|
modem demod = modem_create(MODULATION);
|
|
|
|
|
|
|
|
channel_cccf channel = channel_cccf_create();
|
|
|
|
|
2022-01-30 20:05:20 +01:00
|
|
|
float snr = 50.0f;
|
2021-10-17 19:26:38 +02:00
|
|
|
channel_cccf_add_awgn(channel, -snr, snr);
|
2022-01-30 20:23:41 +01:00
|
|
|
channel_cccf_add_carrier_offset(channel, 0.20f, 1.00f);
|
2021-10-17 19:26:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
packet_mod_ctx_t pmod;
|
|
|
|
packet_mod_init(&pmod);
|
|
|
|
|
|
|
|
packet_mod_set_data(&pmod, msg_org, sizeof(msg_org));
|
|
|
|
packet_mod_encode(&pmod);
|
|
|
|
packet_mod_modulate(&pmod);
|
|
|
|
packet_mod_add_header(&pmod);
|
|
|
|
packet_mod_add_preamble(&pmod);
|
|
|
|
|
|
|
|
size_t nsyms;
|
|
|
|
packet_mod_get_result_cf(&pmod, NULL, &nsyms); // determine number of symbols for allocation
|
|
|
|
|
|
|
|
float complex msg_mod[nsyms];
|
|
|
|
packet_mod_get_result_cf(&pmod, msg_mod, &nsyms); // get the data
|
|
|
|
|
2022-01-29 22:05:17 +01:00
|
|
|
size_t burst_len = 0;
|
|
|
|
float complex whole_burst[65536];
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
transmission_ctx_t transm;
|
|
|
|
transmission_init(&transm);
|
|
|
|
|
|
|
|
len = 65536-burst_len;
|
|
|
|
if(transmission_ramp_up(&transm, whole_burst+burst_len, &len) != OK) {
|
|
|
|
printf("Ramp-up requires %zd symbols at offset %zd.\n", len, burst_len);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
burst_len += len;
|
|
|
|
|
|
|
|
len = 65536-burst_len;
|
|
|
|
if(transmission_filter_packet(&transm, msg_mod, nsyms, whole_burst+burst_len, &len) != OK) {
|
|
|
|
printf("Packet requires %zd symbols at offset %zd.\n", len, burst_len);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
burst_len += len;
|
|
|
|
|
|
|
|
len = 65536-burst_len;
|
|
|
|
if(transmission_ramp_down(&transm, whole_burst+burst_len, &len) != OK) {
|
|
|
|
printf("Ramp-down requires %zd symbols at offset %zd.\n", len, burst_len);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
burst_len += len;
|
|
|
|
|
|
|
|
dump_array_cf(whole_burst, burst_len, 1.0f, "/tmp/tx.cpx");
|
|
|
|
|
2021-10-17 19:26:38 +02:00
|
|
|
// channel
|
2022-01-29 22:36:41 +01:00
|
|
|
float complex msg_received[burst_len];
|
2021-10-17 19:26:38 +02:00
|
|
|
|
2022-01-29 22:36:41 +01:00
|
|
|
//memcpy(msg_received, whole_burst, sizeof(whole_burst)); // no noise in channel
|
2021-10-17 19:26:38 +02:00
|
|
|
|
2022-01-29 22:36:41 +01:00
|
|
|
channel_cccf_execute_block(channel, whole_burst, burst_len, msg_received);
|
|
|
|
dump_array_cf(msg_received, burst_len, 1.0f, "/tmp/rx.cpx");
|
2021-10-17 19:26:38 +02:00
|
|
|
|
2022-01-30 20:05:20 +01:00
|
|
|
// create NCO for carrier frequency compensation
|
|
|
|
nco_crcf carrier_nco = nco_crcf_create(LIQUID_NCO);
|
|
|
|
nco_crcf_set_frequency(carrier_nco, 0.00f);
|
|
|
|
nco_crcf_set_phase(carrier_nco, 0.0f);
|
|
|
|
|
2022-01-29 22:36:41 +01:00
|
|
|
// create symbol synchronizer
|
|
|
|
symsync_crcf symsync = symsync_crcf_create_rnyquist(LIQUID_FIRFILT_RRC, RRC_SPS, RRC_DELAY, RRC_BETA, 32);
|
2021-10-17 19:26:38 +02:00
|
|
|
|
2022-01-29 22:36:41 +01:00
|
|
|
float complex symsync_out[burst_len];
|
2022-01-30 20:05:20 +01:00
|
|
|
unsigned int symsync_out_len = 0;
|
|
|
|
|
2022-01-30 20:23:41 +01:00
|
|
|
#define FREQ_EST_L 8
|
2022-01-30 20:05:20 +01:00
|
|
|
float phase_history[FREQ_EST_L];
|
|
|
|
memset(phase_history, 0, sizeof(phase_history));
|
|
|
|
|
|
|
|
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.
|
|
|
|
float complex mixed_sample;
|
|
|
|
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
|
|
|
|
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.
|
|
|
|
|
|
|
|
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
|
2022-01-30 20:23:41 +01:00
|
|
|
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;
|
2022-01-30 20:05:20 +01:00
|
|
|
|
2022-01-30 20:23:41 +01:00
|
|
|
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;
|
|
|
|
}
|
2022-01-30 20:05:20 +01:00
|
|
|
|
2022-01-30 20:23:41 +01:00
|
|
|
float lms_phase_change = numerator / denominator;
|
2022-01-30 20:05:20 +01:00
|
|
|
|
2022-01-30 20:23:41 +01:00
|
|
|
float freq_adjustment = (lms_phase_change / RRC_SPS / 2) * 0.3f;
|
|
|
|
nco_crcf_adjust_frequency(carrier_nco, freq_adjustment);
|
2022-01-30 20:05:20 +01:00
|
|
|
|
2022-01-30 20:23:41 +01:00
|
|
|
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");
|
2022-01-30 20:05:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
symsync_out_len += out_len;
|
|
|
|
}
|
|
|
|
|
2022-01-30 20:23:41 +01:00
|
|
|
dump_array_cf(symsync_out, symsync_out_len, 1.0f, "/tmp/synced.cpx");
|
2022-01-29 22:36:41 +01:00
|
|
|
|
|
|
|
#if 0
|
2021-10-17 19:26:38 +02:00
|
|
|
// demodulate
|
|
|
|
unsigned int bps = modem_get_bps(demod);
|
|
|
|
|
|
|
|
unsigned char msg_demod_syms[nsyms];
|
|
|
|
unsigned char msg_demod[k+1];
|
|
|
|
|
|
|
|
for(size_t i = 0; i < nsyms; i++) {
|
|
|
|
unsigned int symbol;
|
|
|
|
|
|
|
|
modem_demodulate(demod, msg_received[i], &symbol);
|
|
|
|
msg_demod_syms[i] = symbol;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int received_bytes;
|
2021-10-17 19:45:54 +02:00
|
|
|
liquid_repack_bytes(msg_demod_syms, bps, nsyms, msg_demod, 8, sizeof(msg_demod), &received_bytes);
|
2021-10-17 19:26:38 +02:00
|
|
|
|
|
|
|
//assert(received_bytes == k);
|
|
|
|
|
|
|
|
// decode
|
|
|
|
uint8_t msg_dec[sizeof(msg_org)];
|
|
|
|
//memcpy(msg_dec, msg_enc, sizeof(msg_dec));
|
|
|
|
fec_decode(q, sizeof(msg_dec), msg_demod, msg_dec);
|
|
|
|
|
|
|
|
// compare original to decoded message
|
|
|
|
for(size_t i = 0; i < sizeof(msg_org); i++)
|
|
|
|
{
|
|
|
|
printf("%02x => %02x", msg_org[i], msg_dec[i]);
|
|
|
|
if(msg_org[i] != msg_dec[i]) {
|
|
|
|
printf(" <<< !!!\n");
|
|
|
|
} else {
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int bit_errors = count_bit_errors_array(msg_org, msg_dec, sizeof(msg_org));
|
|
|
|
printf("%u bit errors detected.\n", bit_errors);
|
2022-01-29 22:05:17 +01:00
|
|
|
#endif
|
2021-10-17 19:26:38 +02:00
|
|
|
|
2022-01-30 20:05:20 +01:00
|
|
|
nco_crcf_destroy(carrier_nco);
|
|
|
|
|
|
|
|
symsync_crcf_destroy(symsync);
|
|
|
|
|
2021-10-17 19:26:38 +02:00
|
|
|
fec_destroy(q);
|
|
|
|
|
|
|
|
modem_destroy(demod);
|
|
|
|
|
|
|
|
channel_cccf_destroy(channel);
|
|
|
|
|
|
|
|
printf("Done.\n");
|
|
|
|
}
|