pull/47/merge
drowe67 2024-05-08 16:38:32 +08:00 committed by GitHub
commit fe12189105
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 874 additions and 735 deletions

View File

@ -472,7 +472,7 @@ endif()
add_test(NAME test_OFDM_modem_octave_qam16_uncoded
COMMAND sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/octave;
echo \"ofdm_tx('test_qam16.raw','qam16c1',3,12,'awgn','bursts',3); ofdm_rx('test_qam16.raw','qam16c1', 'passber', 0.05, 'packetsperburst', 1); quit\" |
echo \"ofdm_tx('test_qam16.raw','qam16c2',1,12,'awgn','bursts',3); ofdm_rx('test_qam16.raw','qam16c2', 'passber', 0.05, 'packetsperburst', 1); quit\" |
DISPLAY=\"\" octave-cli")
set_tests_properties(test_OFDM_modem_octave_qam16_uncoded PROPERTIES PASS_REGULAR_EXPRESSION "Pass")
@ -669,6 +669,13 @@ endif()
cd ${CMAKE_CURRENT_BINARY_DIR}/src;
cat test.raw | ./ofdm_demod --mode datac14 --out /dev/null --testframes --ldpc --verbose 2 --packetsperburst 1")
# QAM16C2 Octave Tx, C Rx, burst mode
add_test(NAME test_OFDM_modem_qam16c2_octave
COMMAND sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/octave;
DISPLAY=\"\" octave-cli -qf --eval 'ofdm_ldpc_tx(\"${CMAKE_CURRENT_BINARY_DIR}/src/test.raw\",\"qam16c2\",1,10,\"awgn\",\"bursts\",2)';
cd ${CMAKE_CURRENT_BINARY_DIR}/src;
cat test.raw | ./ofdm_demod --mode qam16c2 --out /dev/null --testframes --ldpc --verbose 2 --packetsperburst 1")
# DATAC4 C Tx, C Rx, burst mode
add_test(NAME test_OFDM_modem_datac4_ldpc_burst
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
@ -690,6 +697,13 @@ endif()
./ch - - --No -17 |
./ofdm_demod --mode datac14 --out /dev/null --testframes --ldpc --verbose 2 --packetsperburst 1")
# QAM16C2 C Tx, C Rx, burst mode
add_test(NAME test_OFDM_modem_qam16c2_ldpc_burst
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
./ofdm_mod --mode qam16c2 --in /dev/zero --testframes 1 --verbose 1 --ldpc --bursts 10 |
./ch - - --No -30 |
./ofdm_demod --mode qam16c2 --out /dev/null --testframes --ldpc --verbose 2 --packetsperburst 1")
# -------------------------------------------------------------------------
# LDPC
# -------------------------------------------------------------------------
@ -1291,6 +1305,12 @@ endif(NOT APPLE)
./freedv_data_raw_rx --framesperburst 2 --testframes DATAC0 - /dev/null --vv")
set_tests_properties(test_freedv_data_raw_ofdm_datac0_burst PROPERTIES PASS_REGULAR_EXPRESSION "Coded FER: 0.0000 Tfrms: 6 Tfers: 0")
add_test(NAME test_freedv_data_raw_ofdm_data_custom
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
./freedv_data_raw_tx --bursts 3 --testframes 3 custom /dev/zero - |
./freedv_data_raw_rx --testframes custom - /dev/null --vv")
set_tests_properties(test_freedv_data_raw_ofdm_data_custom PROPERTIES PASS_REGULAR_EXPRESSION "Coded FER: 0.0000 Tfrms: 3 Tfers: 0")
# Burst mode with data file I/O:
add_test(NAME test_freedv_data_raw_ofdm_datac0_burst_file
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
@ -1334,6 +1354,13 @@ endif(NOT APPLE)
./freedv_data_raw_rx DATAC14 - binaryOut.bin -v;
diff binaryIn.bin binaryOut.bin")
add_test(NAME test_freedv_data_raw_ofdm_qam16c2_burst_file
COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR}/src;
head -c $((1213*10)) </dev/urandom > binaryIn.bin;
./freedv_data_raw_tx qam16c2 binaryIn.bin - --bursts 10 |
./freedv_data_raw_rx qam16c2 - binaryOut.bin -v;
diff binaryIn.bin binaryOut.bin")
# FSK LDPC default 100 bit/s 2FSK, enough noise for several % raw BER to give
# FEC/acquisition a work out, bursts of 1 frame as that stresses acquisition
add_test(NAME test_freedv_data_raw_fsk_ldpc_100
@ -1420,6 +1447,7 @@ endif(NOT APPLE)
test_OFDM_modem_datac4_octave
test_OFDM_modem_datac13_octave
test_OFDM_modem_datac14_octave
test_OFDM_modem_qam16c2_octave
test_fsk_lib_4fsk_ldpc
test_OFDM_modem_datac0_compression
PROPERTIES

View File

@ -147,6 +147,7 @@ These modes use an OFDM modem with powerful LDPC codes and are designed for send
| DATAC4 | 250 | 87 | 56 | (1472,448) | 5.17 | 90/100 at -4dB | Forward link data (low SNR) |
| DATAC13 | 200 | 64 | 14 | (384,128) | 2.0 | 90/100 at -4dB | Reverse link ACK packets (low SNR) |
| DATAC14 | 250 | 58 | 3 | (112,56) | 0.69 | 90/100 at -2dB | Reverse link ACK packets (low SNR) |
| QAM16C2 | 2100 | 3100 | 1213 | (16200,9720) | 3.2 | 90/100 at 15dB | Forward link data (high SNR) |
Notes:
1. 16 bits (2 bytes) per frame are reserved for a 16 bit CRC, e.g. for `datac3` we have 128 byte frames, and 128-2=126 bytes/frame of payload data.

View File

@ -7,18 +7,31 @@
1;
% return 1 if prime
function ret = is_prime(x)
for i=2:x-1
if mod(x,i) == 0
ret = 0;
return;
end
end
ret = 1;
end
function x = next_prime(x)
x++;
while is_prime(x) == 0
x++;
end
end
% Choose b for Golden Prime Interleaver. b is chosen to be the
% closest integer, which is relatively prime to N, to the Golden
% section of N.
function b = choose_interleaver_b(Nbits)
p = primes(Nbits);
i = 1;
while(p(i) < Nbits/1.62)
i++;
end
b = p(i);
b = floor(Nbits/1.62);
b = next_prime(b);
assert(gcd(b,Nbits) == 1, "b and Nbits must be co-prime");
end
@ -36,7 +49,7 @@ endfunction
function frame = gp_deinterleave(interleaved_frame)
Nbits = length(interleaved_frame);
b = choose_interleaver_b(Nbits);
b = choose_interleaver_b(Nbits);
frame = zeros(1,Nbits);
for i=1:Nbits
j = mod((b*(i-1)), Nbits);

View File

@ -52,7 +52,6 @@ function states = ofdm_init(config)
bad_uw_errors = config.bad_uw_errors;
amp_scale = config.amp_scale;
amp_est_mode = config.amp_est_mode;
EsNo_est_all_symbols = config.EsNo_est_all_symbols;
EsNodB = config.EsNodB;
state_machine = config.state_machine;
edge_pilots = config.edge_pilots;
@ -74,10 +73,10 @@ function states = ofdm_init(config)
states.Nsampersymbol = states.M+states.Ncp; % number of samples in a single symbol
states.Nsamperframe = Ns*states.Nsampersymbol; % number of samples in a modem frame
states.qam16 = [
1 + j, 1 + j*3, 3 + j, 3 + j*3;
1 - j, 1 - j*3, 3 - j, 3 - j*3;
-1 + j, -1 + j*3, -3 + j, -3 + j*3;
-1 - j, -1 - j*3, -3 - j, -3 - j*3]/3;
1 + j, 1 + j*3, 3 + j, 3 + j*3, ...
1 - j, 1 - j*3, 3 - j, 3 - j*3, ...
-1 + j, -1 + j*3, -3 + j, -3 + j*3, ...
-1 - j, -1 - j*3, -3 - j, -3 - j*3];
rms = sqrt(states.qam16(:)'*states.qam16(:)/16);% set average Es to 1
states.qam16 /= rms;
states.qam16 *= exp(-j*pi/4); % same rotation as QPSK constellation
@ -128,7 +127,7 @@ function states = ofdm_init(config)
states.uw_ind = [states.uw_ind bps*ind_sym-b]; % bit index
end
end
% how many of the first few frames have UW symbols in them
Nsymsperframe = states.Nbitsperframe/states.bps;
states.Nuwframes = ceil(states.uw_ind_sym(end)/Nsymsperframe);
@ -275,7 +274,6 @@ function states = ofdm_init(config)
% Es/No (SNR) est states
states.EsNo_est_all_symbols = EsNo_est_all_symbols;
states.clock_offset_est = 0;
% pre-amble for data modes

View File

@ -25,7 +25,6 @@ function config = ofdm_init_mode(mode="700D")
config.bad_uw_errors = 3;
config.amp_scale = 245E3;
config.amp_est_mode = 0;
config.EsNo_est_all_symbols = 1;
config.EsNodB = 3;
config.state_machine = "voice1";
config.edge_pilots = 1;
@ -59,12 +58,12 @@ function config = ofdm_init_mode(mode="700D")
config.bps=4; config.Ntxtbits = 0; config.Nuwbits = 15*4; config.bad_uw_errors = 5;
config.state_machine = "data";
config.ftwindow_width = 32; config.amp_scale = 132E3;
config.EsNo_est_all_symbols = 0; config.amp_est_mode = 1; config.EsNodB = 10;
config.amp_est_mode = 1; config.EsNodB = 10;
elseif strcmp(mode,"qam16c2")
Ns=5; config.Np=31; Tcp = 0.004; Ts = 0.016; Nc = 33; config.data_mode = "streaming";
config.bps=4; config.Ntxtbits = 0; config.Nuwbits = 42*4; config.bad_uw_errors = 15;
config.bps=4; config.Ntxtbits = 0; config.Nuwbits = 42*4; config.bad_uw_errors = 50;
config.ftwindow_width = 80; config.amp_scale = 135E3; config.state_machine = "data";
config.EsNo_est_all_symbols = 0; config.amp_est_mode = 1; config.EsNodB = 10;
config.amp_est_mode = 1; config.EsNodB = 10;
config.tx_uw = zeros(1,config.Nuwbits = 42*4);
config.tx_uw(1:24) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
config.tx_uw(end-24+1:end) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];

View File

@ -25,7 +25,7 @@ function test_qam16_mod_demod(constellation)
for decimal=0:15
tx_bits = zeros(1,4);
for i=1:4
tx_bits(1,5-i) = bitand(bitshift(decimal-1,1-i),1);
tx_bits(1,5-i) = bitand(bitshift(decimal,1-i),1);
end
symbol = qam16_mod(constellation, tx_bits);
rx_bits = qam16_demod(constellation,symbol);

View File

@ -229,8 +229,7 @@ int freedv_comprx_2020(struct freedv *f, COMP demod_in[]) {
f->sync = 0;
// TODO: should be higher for 2020?
float EsNo = 3.0;
float EsNo = pow(10.0, ofdm->EsNodB / 10);
/* looking for modem sync */
@ -249,7 +248,7 @@ int freedv_comprx_2020(struct freedv *f, COMP demod_in[]) {
ofdm_demod(ofdm, rx_bits, demod_in);
ofdm_extract_uw(ofdm, ofdm->rx_np, ofdm->rx_amp, rx_uw);
ofdm_disassemble_qpsk_modem_packet_with_text_amps(
ofdm_disassemble_psk_modem_packet_with_text_amps(
ofdm, ofdm->rx_np, ofdm->rx_amp, payload_syms, payload_amps, txt_bits,
&txt_sym_index);
@ -280,14 +279,14 @@ int freedv_comprx_2020(struct freedv *f, COMP demod_in[]) {
uint8_t out_char[coded_bits_per_frame];
if (f->test_frames) {
Nerrs_raw =
count_uncoded_errors(ldpc, &f->ofdm->config, codeword_symbols_de, 0);
Nerrs_raw = count_uncoded_errors(
ldpc, &f->ofdm->config, codeword_symbols_de, codeword_amps_de, 0);
f->total_bit_errors += Nerrs_raw;
f->total_bits += f->ofdm_bitsperframe;
}
symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo,
ofdm->mean_amp, coded_syms_per_frame);
ofdm->mean_amp, ofdm->bps, coded_syms_per_frame);
ldpc_decode_frame(ldpc, &parityCheckCount, &iter, out_char, llr);
if (parityCheckCount != ldpc->NumberParityBits)
rx_status |= FREEDV_RX_BIT_ERRORS;

View File

@ -189,7 +189,7 @@ void freedv_ofdm_voice_open(struct freedv *f, char *mode) {
// open function for OFDM data modes, TODO consider moving to a new
// (freedv_ofdm_data.c) file
void freedv_ofdm_data_open(struct freedv *f) {
void freedv_ofdm_data_open(struct freedv *f, struct freedv_advanced *adv) {
struct OFDM_CONFIG ofdm_config;
char mode[32];
if (f->mode == FREEDV_MODE_DATAC0) strcpy(mode, "datac0");
@ -198,8 +198,15 @@ void freedv_ofdm_data_open(struct freedv *f) {
if (f->mode == FREEDV_MODE_DATAC4) strcpy(mode, "datac4");
if (f->mode == FREEDV_MODE_DATAC13) strcpy(mode, "datac13");
if (f->mode == FREEDV_MODE_DATAC14) strcpy(mode, "datac14");
ofdm_init_mode(mode, &ofdm_config);
if (f->mode == FREEDV_MODE_QAM16C2) strcpy(mode, "qam16c2");
if (f->mode == FREEDV_MODE_DATA_CUSTOM) {
assert(adv != NULL);
assert(adv->config != NULL);
memcpy(&ofdm_config, (struct OFDM_CONFIG *)adv->config,
sizeof(struct OFDM_CONFIG));
} else {
ofdm_init_mode(mode, &ofdm_config);
}
f->ofdm = ofdm_create(&ofdm_config);
assert(f->ofdm != NULL);
@ -219,8 +226,8 @@ void freedv_ofdm_data_open(struct freedv *f) {
f->ofdm_ntxtbits = ofdm_config.txtbits;
/* payload bits per FreeDV API "frame". In OFDM modem nomenclature this is
the number of payload data bits per packet, or the number of data bits in a
LDPC codeword */
the number of payload data bits per packet, or the number of data bits in
a LDPC codeword */
f->bits_per_modem_frame = f->ldpc->data_bits_per_frame;
// buffers for received symbols for one packet/LDPC codeword - may span many
@ -299,8 +306,8 @@ int freedv_comprx_700c(struct freedv *f, COMP demod_in_8kHz[]) {
int rx_status = 0;
// quisk_cfInterpDecim() modifies input data so lets make a copy just in case
// there is no sync and we need to echo input to output
// quisk_cfInterpDecim() modifies input data so lets make a copy just in
// case there is no sync and we need to echo input to output
// freedv_nin(f): input samples at Fs=8000 Hz
// f->nin: input samples at Fs=7500 Hz
@ -332,7 +339,8 @@ int freedv_comprx_700c(struct freedv *f, COMP demod_in_8kHz[]) {
rx_status |= FREEDV_RX_BITS;
} else {
if (f->test_frames_diversity) {
/* normal operation - error pattern on frame after diveristy combination
/* normal operation - error pattern on frame after diveristy
* combination
*/
short error_pattern[COHPSK_BITS_PER_FRAME];
int bit_errors;
@ -440,7 +448,7 @@ int freedv_comp_short_rx_ofdm(struct freedv *f, void *demod_in_8kHz,
assert((demod_in_is_short == 0) || (demod_in_is_short == 1));
int rx_status = 0;
float EsNo = 3.0; /* further work: estimate this properly from signal */
float EsNo = pow(10.0, ofdm->EsNodB / 10);
f->sync = 0;
/* looking for OFDM modem sync */
@ -471,8 +479,8 @@ int freedv_comp_short_rx_ofdm(struct freedv *f, void *demod_in_8kHz,
memcpy(&rx_amps[Nsymsperpacket - Nsymsperframe], ofdm->rx_amp,
sizeof(float) * Nsymsperframe);
/* look for UW as frames enter packet buffer, note UW may span several modem
* frames */
/* look for UW as frames enter packet buffer, note UW may span several
* modem frames */
int st_uw = Nsymsperpacket - ofdm->nuwframes * Nsymsperframe;
ofdm_extract_uw(ofdm, &rx_syms[st_uw], &rx_amps[st_uw], rx_uw);
@ -483,7 +491,7 @@ int freedv_comp_short_rx_ofdm(struct freedv *f, void *demod_in_8kHz,
/* we have received enough modem frames to complete packet and run LDPC
* decoder */
int txt_sym_index = 0;
ofdm_disassemble_qpsk_modem_packet_with_text_amps(
ofdm_disassemble_psk_modem_packet_with_text_amps(
ofdm, rx_syms, rx_amps, payload_syms, payload_amps, txt_bits,
&txt_sym_index);
@ -497,10 +505,8 @@ int freedv_comp_short_rx_ofdm(struct freedv *f, void *demod_in_8kHz,
float llr[Npayloadbitsperpacket];
uint8_t decoded_codeword[Npayloadbitsperpacket];
symbols_to_llrs(llr, payload_syms_de, payload_amps_de, EsNo,
ofdm->mean_amp, Npayloadsymsperpacket);
ofdm->mean_amp, ofdm->bps, Npayloadsymsperpacket);
ldpc_decode_frame(ldpc, &parityCheckCount, &iter, decoded_codeword, llr);
// iter = run_ldpc_decoder(ldpc, decoded_codeword, llr,
// &parityCheckCount);
memcpy(f->rx_payload_bits, decoded_codeword, Ndatabitsperpacket);
if (strlen(ofdm->data_mode)) {
@ -510,8 +516,8 @@ int freedv_comp_short_rx_ofdm(struct freedv *f, void *demod_in_8kHz,
else
rx_status |= FREEDV_RX_BIT_ERRORS;
} else {
// voice modes aren't as strict - pass everything through to the speech
// decoder, but flag frame with possible errors
// voice modes aren't as strict - pass everything through to the
// speech decoder, but flag frame with possible errors
rx_status |= FREEDV_RX_BITS;
if (parityCheckCount != ldpc->NumberParityBits)
rx_status |= FREEDV_RX_BIT_ERRORS;
@ -519,8 +525,9 @@ int freedv_comp_short_rx_ofdm(struct freedv *f, void *demod_in_8kHz,
if (f->test_frames) {
/* est uncoded BER from payload bits */
Nerrs_raw = count_uncoded_errors(
ldpc, &f->ofdm->config, payload_syms_de, strlen(ofdm->data_mode));
Nerrs_raw =
count_uncoded_errors(ldpc, &f->ofdm->config, payload_syms_de,
payload_amps_de, strlen(ofdm->data_mode));
f->total_bit_errors += Nerrs_raw;
f->total_bits += Npayloadbitsperpacket;

View File

@ -60,7 +60,7 @@
/* The API version number. The first version is 10. Increment if the API
changes in a way that would require changes by the API user. */
#define VERSION 15
#define VERSION 16
/*
Version 10 Initial version August 2, 2015.
@ -79,6 +79,9 @@
Version 15 December 2022 Removing rarely used DPSK support which is not
needed given fast fading modes
Version 16 April 2024, added field to struct freedv_advanced to support
FREEDV_MODE_DATA_CUSTOM
*/
char *ofdm_statemode[] = {"search", "trial", "synced"};
@ -101,7 +104,8 @@ char *rx_sync_flags_to_text[] = {"----", "---T", "--S-", "--ST", "-B--", "-B-T",
struct freedv *freedv_open(int mode) {
// defaults for those modes that support the use of adv
struct freedv_advanced adv = {0, 2, 100, 8000, 1000, 200, "H_256_512_4"};
struct freedv_advanced adv = {0, 2, 100, 8000,
1000, 200, "H_256_512_4", NULL};
return freedv_open_advanced(mode, &adv);
}
@ -126,7 +130,9 @@ struct freedv *freedv_open_advanced(int mode, struct freedv_advanced *adv) {
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, mode)) == false)
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATA_CUSTOM, mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_QAM16C2, mode)) == false)
return NULL;
/* set everything to zero just in case */
@ -150,12 +156,18 @@ struct freedv *freedv_open_advanced(int mode, struct freedv_advanced *adv) {
if (FDV_MODE_ACTIVE(FREEDV_MODE_2400B, mode)) freedv_2400b_open(f);
if (FDV_MODE_ACTIVE(FREEDV_MODE_800XA, mode)) freedv_800xa_open(f);
if (FDV_MODE_ACTIVE(FREEDV_MODE_FSK_LDPC, mode)) freedv_fsk_ldpc_open(f, adv);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC0, mode)) freedv_ofdm_data_open(f);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC1, mode)) freedv_ofdm_data_open(f);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, mode)) freedv_ofdm_data_open(f);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, mode)) freedv_ofdm_data_open(f);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, mode)) freedv_ofdm_data_open(f);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, mode)) freedv_ofdm_data_open(f);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC0, mode)) freedv_ofdm_data_open(f, NULL);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC1, mode)) freedv_ofdm_data_open(f, NULL);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, mode)) freedv_ofdm_data_open(f, NULL);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, mode)) freedv_ofdm_data_open(f, NULL);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, mode))
freedv_ofdm_data_open(f, NULL);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, mode))
freedv_ofdm_data_open(f, NULL);
if (FDV_MODE_ACTIVE(FREEDV_MODE_DATA_CUSTOM, mode))
freedv_ofdm_data_open(f, adv);
if (FDV_MODE_ACTIVE(FREEDV_MODE_QAM16C2, mode))
freedv_ofdm_data_open(f, NULL);
varicode_decode_init(&f->varicode_dec_states, 1);
@ -238,7 +250,9 @@ void freedv_close(struct freedv *freedv) {
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, freedv->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, freedv->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, freedv->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, freedv->mode)) {
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, freedv->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_QAM16C2, freedv->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATA_CUSTOM, freedv->mode)) {
FREE(freedv->rx_syms);
FREE(freedv->rx_amps);
FREE(freedv->ldpc);
@ -270,7 +284,9 @@ static int is_ofdm_mode(struct freedv *f) {
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode);
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_QAM16C2, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATA_CUSTOM, f->mode);
}
static int is_ofdm_data_mode(struct freedv *f) {
@ -279,7 +295,9 @@ static int is_ofdm_data_mode(struct freedv *f) {
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode);
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_QAM16C2, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATA_CUSTOM, f->mode);
}
/*---------------------------------------------------------------------------*\
@ -470,7 +488,9 @@ void freedv_rawdatacomptx(struct freedv *f, COMP mod_out[],
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode))
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_QAM16C2, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATA_CUSTOM, f->mode))
freedv_comptx_ofdm(f, mod_out);
if (FDV_MODE_ACTIVE(FREEDV_MODE_FSK_LDPC, f->mode)) {
@ -1070,7 +1090,9 @@ int freedv_rawdatacomprx(struct freedv *f, unsigned char *packed_payload_bits,
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC3, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC4, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC13, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode))
FDV_MODE_ACTIVE(FREEDV_MODE_DATAC14, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_QAM16C2, f->mode) ||
FDV_MODE_ACTIVE(FREEDV_MODE_DATA_CUSTOM, f->mode))
rx_status = freedv_comp_short_rx_ofdm(f, (void *)demod_in, 0, 1.0f);
if (FDV_MODE_ACTIVE(FREEDV_MODE_FSK_LDPC, f->mode)) {
rx_status = freedv_rx_fsk_ldpc_data(f, demod_in);

View File

@ -62,6 +62,8 @@ extern "C" {
#define FREEDV_MODE_DATAC4 18
#define FREEDV_MODE_DATAC13 19
#define FREEDV_MODE_DATAC14 20
#define FREEDV_MODE_DATA_CUSTOM 21
#define FREEDV_MODE_QAM16C2 22
// Sample rates used
#define FREEDV_FS_8000 8000
@ -144,6 +146,12 @@ extern "C" {
#if !defined(FREEDV_MODE_DATAC14_EN)
#define FREEDV_MODE_DATAC14_EN FREEDV_MODE_EN_DEFAULT
#endif
#if !defined(FREEDV_MODE_DATA_CUSTOM_EN)
#define FREEDV_MODE_DATA_CUSTOM_EN FREEDV_MODE_EN_DEFAULT
#endif
#if !defined(FREEDV_MODE_QAM16C2_EN)
#define FREEDV_MODE_QAM16C2_EN FREEDV_MODE_EN_DEFAULT
#endif
#define FDV_MODE_ACTIVE(mode_name, var) \
((mode_name##_EN) == 0 ? 0 : (var) == mode_name)
@ -163,6 +171,9 @@ struct freedv_advanced {
int first_tone; // Freq of first tone Hz
int tone_spacing; // Spacing between tones Hz
char *codename; // LDPC codename, from codes listed in ldpc_codes.c
// parameters for FREEDV_MODE_DATA_CUSTOM
void *config; // ptr to struct OFDM_CONFIG
};
// Called when text message char is decoded

View File

@ -221,7 +221,7 @@ void freedv_2400a_open(struct freedv *f);
void freedv_2400b_open(struct freedv *f);
void freedv_800xa_open(struct freedv *f);
void freedv_fsk_ldpc_open(struct freedv *f, struct freedv_advanced *adv);
void freedv_ofdm_data_open(struct freedv *f);
void freedv_ofdm_data_open(struct freedv *f, struct freedv_advanced *adv);
// each mode has tx and rx functions in various flavours for real and complex
// valued samples

View File

@ -39,6 +39,7 @@
#include "ldpc_codes.h"
#include "modem_stats.h"
#include "octave.h"
#include "ofdm_internal.h"
/* other processes can end this program using signals */
@ -216,6 +217,10 @@ int main(int argc, char *argv[]) {
mode = FREEDV_MODE_DATAC13;
if (!strcmp(argv[dx], "DATAC14") || !strcmp(argv[dx], "datac14"))
mode = FREEDV_MODE_DATAC14;
if (!strcmp(argv[dx], "QAM16C2") || !strcmp(argv[dx], "qam16c2"))
mode = FREEDV_MODE_QAM16C2;
if (!strcmp(argv[dx], "CUSTOM") || !strcmp(argv[dx], "custom"))
mode = FREEDV_MODE_DATA_CUSTOM;
if (mode == -1) {
fprintf(stderr, "Error in mode: %s\n", argv[dx]);
exit(1);
@ -248,6 +253,23 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "Setting estimator limits to %d to %d Hz.\n", fsk_lower,
fsk_upper);
fsk_set_freq_est_limits(fsk, fsk_lower, fsk_upper);
} else if (mode == FREEDV_MODE_DATA_CUSTOM) {
// demonstrate custom OFDM raw data modes
struct OFDM_CONFIG ofdm_config;
ofdm_init_mode("datac14", &ofdm_config);
// modify datac14 to have 3 carriers instead of 4, which means
// we have to tweak Np, and the number of unique word bits
ofdm_config.nc = 3;
ofdm_config.np = 6;
ofdm_config.nuwbits = 48;
ofdm_config.bad_uw_errors = 18;
uint8_t uw[] = {1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1,
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0};
memcpy(ofdm_config.tx_uw, uw, sizeof(uw));
memcpy(&ofdm_config.tx_uw[ofdm_config.nuwbits - sizeof(uw)], uw,
sizeof(uw));
adv.config = (void *)&ofdm_config;
freedv = freedv_open_advanced(mode, &adv);
} else {
freedv = freedv_open(mode);
}
@ -264,8 +286,8 @@ int main(int argc, char *argv[]) {
fsk->Ndft);
}
/* for streaming bytes it's much easier use the modes that have a multiple of
* 8 payload bits/frame */
/* for streaming bytes it's much easier use the modes that have a multiple
* of 8 payload bits/frame */
assert((freedv_get_bits_per_modem_frame(freedv) % 8) == 0);
int bytes_per_modem_frame = freedv_get_bits_per_modem_frame(freedv) / 8;
// last two bytes used for CRC

View File

@ -238,6 +238,10 @@ int main(int argc, char *argv[]) {
mode = FREEDV_MODE_DATAC13;
if (!strcmp(argv[dx], "DATAC14") || !strcmp(argv[dx], "datac14"))
mode = FREEDV_MODE_DATAC14;
if (!strcmp(argv[dx], "QAM16C2") || !strcmp(argv[dx], "qam16c2"))
mode = FREEDV_MODE_QAM16C2;
if (!strcmp(argv[dx], "CUSTOM") || !strcmp(argv[dx], "custom"))
mode = FREEDV_MODE_DATA_CUSTOM;
if (mode == -1) {
fprintf(stderr, "Error: in mode: %s", argv[dx]);
exit(1);
@ -259,10 +263,28 @@ int main(int argc, char *argv[]) {
exit(1);
}
if (mode != FREEDV_MODE_FSK_LDPC)
freedv = freedv_open(mode);
else
if (mode == FREEDV_MODE_FSK_LDPC)
freedv = freedv_open_advanced(mode, &adv);
else if (mode == FREEDV_MODE_DATA_CUSTOM) {
// demonstrate custom OFDM raw data modes
struct OFDM_CONFIG ofdm_config;
ofdm_init_mode("datac14", &ofdm_config);
// modify datac14 to have 3 carriers instead of 4, which means
// we have to tweak Np, and the number of unique word bits
ofdm_config.nc = 3;
ofdm_config.np = 6;
ofdm_config.nuwbits = 48;
ofdm_config.bad_uw_errors = 18;
uint8_t uw[] = {1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1,
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0};
memcpy(ofdm_config.tx_uw, uw, sizeof(uw));
memcpy(&ofdm_config.tx_uw[ofdm_config.nuwbits - sizeof(uw)], uw,
sizeof(uw));
adv.config = (void *)&ofdm_config;
freedv = freedv_open_advanced(mode, &adv);
} else {
freedv = freedv_open(mode);
}
assert(freedv != NULL);

View File

@ -31,45 +31,32 @@
#include "gp_interleaver.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
/*
Choose b for Golden Prime Interleaver. b is chosen to be the
closest integer, which is relatively prime to N, to the Golden
section of N.
Implemented with a LUT in C for convenience, Octave version
has a more complete implementation. If you find you need some more
numbers head back to the Octave choose_interleaver_b() function.
*/
static const int b_table[] = {
48, 31, /* datac14: HRA_56_56, 40 data bits used */
56, 37, /* 700E: HRA_56_56 */
106, 67, /* 2020B: (112,56) partial protection */
112, 71, /* 700D: HRA_112_112 */
128, 83, /* datac0: H_128_256_5 */
192, 127, /* datac13: H_256_512_4, 128 data bits used */
210, 131, /* 2020: HRAb_396_504 with 312 data bits used */
736, 457, /* datac4: H_1024_2048_4f, 448 data bits used */
1024, 641, /* datac3: H_1024_2048_4f */
1290, 797, /* datac2: H2064_516_sparse */
4096, 2531 /* datac1: H_4096_8192_3d */
};
int is_prime(int x) {
for (int i = 2; i < x; i++) {
if ((x % i) == 0) return 0;
}
return 1;
}
int next_prime(int x) {
x++;
while (is_prime(x) == 0) x++;
return x;
}
int choose_interleaver_b(int Nbits) {
int i;
for (i = 0; i < sizeof(b_table) / sizeof(int); i += 2) {
if (b_table[i] == Nbits) {
return b_table[i + 1];
}
}
/* if we get to here it means a Nbits we don't have in our table so choke */
fprintf(stderr, "gp_interleaver: Nbits: %d, b not found!\n", Nbits);
assert(0);
return -1;
int b = floor(Nbits / 1.62);
b = next_prime(b);
return b;
}
void gp_interleave_comp(COMP interleaved_frame[], COMP frame[], int Nbits) {

View File

@ -134,17 +134,18 @@ void ldpc_encode_frame(struct LDPC *ldpc, int codeword[],
for (j = 0; j < ldpc->NumberParityBits; i++, j++) codeword[i] = pbits[j];
}
void qpsk_modulate_frame(COMP tx_symbols[], int codeword[], int n) {
void psk_modulate_frame(int bps, COMP tx_symbols[], int codeword[], int n) {
int s, i;
int dibit[2];
complex float qpsk_symb;
int bits[bps];
complex float symb;
for (s = 0, i = 0; i < n; s += 2, i++) {
dibit[0] = codeword[s + 1] & 0x1;
dibit[1] = codeword[s] & 0x1;
qpsk_symb = qpsk_mod(dibit);
tx_symbols[i].real = crealf(qpsk_symb);
tx_symbols[i].imag = cimagf(qpsk_symb);
assert((bps == 2) || (bps == 4));
for (s = 0, i = 0; i < n; s += bps, i++) {
for (int b = 0; b < bps; b++) bits[b] = codeword[s + bps - 1 - b] & 0x1;
if (bps == 2) symb = qpsk_mod(bits);
if (bps == 4) symb = qam16_mod(bits);
tx_symbols[i].real = crealf(symb);
tx_symbols[i].imag = cimagf(symb);
}
}
@ -220,7 +221,8 @@ void ldpc_decode_frame(struct LDPC *ldpc, int *parityCheckCount, int *iter,
of txt bits as this is done after we dissassemmble the frame */
int count_uncoded_errors(struct LDPC *ldpc, struct OFDM_CONFIG *config,
COMP codeword_symbols_de[], int crc16) {
COMP codeword_symbols_de[], float codeword_amps_de[],
int crc16) {
int i, Nerrs;
int coded_syms_per_frame = ldpc->coded_bits_per_frame / config->bps;
@ -248,12 +250,13 @@ int count_uncoded_errors(struct LDPC *ldpc, struct OFDM_CONFIG *config,
ldpc_encode_frame(ldpc, test_codeword, tx_bits);
for (i = 0; i < coded_syms_per_frame; i++) {
int bits[2];
int bits[config->bps];
complex float s =
codeword_symbols_de[i].real + I * codeword_symbols_de[i].imag;
qpsk_demod(s, bits);
rx_bits_raw[config->bps * i] = bits[1];
rx_bits_raw[config->bps * i + 1] = bits[0];
if (config->bps == 2) qpsk_demod(s, bits);
if (config->bps == 4) qam16_demod(s, bits, codeword_amps_de[i]);
for (int b = 0; b < config->bps; b++)
rx_bits_raw[config->bps * i + b] = bits[config->bps - 1 - b];
}
Nerrs = 0;
@ -329,10 +332,11 @@ void ofdm_ldpc_interleave_tx(struct OFDM *ofdm, struct LDPC *ldpc,
complex float tx_symbols[Nbitsperpacket / ofdm->bps];
ldpc_encode_frame(ldpc, codeword, tx_bits);
qpsk_modulate_frame(payload_symbols, codeword, Npayloadsymsperpacket);
psk_modulate_frame(ofdm->bps, payload_symbols, codeword,
Npayloadsymsperpacket);
gp_interleave_comp(payload_symbols_inter, payload_symbols,
Npayloadsymsperpacket);
ofdm_assemble_qpsk_modem_packet_symbols(ofdm, tx_symbols,
payload_symbols_inter, txt_bits);
ofdm_assemble_psk_modem_packet_symbols(ofdm, tx_symbols,
payload_symbols_inter, txt_bits);
ofdm_txframe(ofdm, tx_sams, tx_symbols);
}

View File

@ -49,7 +49,8 @@ void qpsk_modulate_frame(COMP tx_symbols[], int codeword[], int n);
void ldpc_decode_frame(struct LDPC *ldpc, int *parityCheckCount, int *iter,
uint8_t out_char[], float llr[]);
int count_uncoded_errors(struct LDPC *ldpc, struct OFDM_CONFIG *config,
COMP codeword_symbols_de[], int crc16);
COMP codeword_symbols_de[], float codeword_amps_de[],
int crc16);
int count_errors(uint8_t tx_bits[], uint8_t rx_bits[], int n);
void count_errors_protection_mode(int protection_mode, int *pNerrs,
int *pNcoded, uint8_t tx_bits[],

View File

@ -27,11 +27,21 @@
#define QPSK_CONSTELLATION_SIZE 4
#define QPSK_BITS_PER_SYMBOL 2
/* QPSK constellation for symbol likelihood calculations */
/* Constellations for symbol likelihood calculations */
static COMP S_matrix[] = {
static COMP S_matrix_qpsk[] = {
{1.0f, 0.0f}, {0.0f, 1.0f}, {0.0f, -1.0f}, {-1.0f, 0.0f}};
static COMP S_matrix_qam16[] = {
{4.4721e-01, 2.7756e-17}, {8.9443e-01, 4.4721e-01},
{8.9443e-01, -4.4721e-01}, {1.3416e+00, 1.1102e-16},
{2.7756e-17, -4.4721e-01}, {-4.4721e-01, -8.9443e-01},
{4.4721e-01, -8.9443e-01}, {1.1102e-16, -1.3416e+00},
{-2.7756e-17, 4.4721e-01}, {4.4721e-01, 8.9443e-01},
{-4.4721e-01, 8.9443e-01}, {-1.1102e-16, 1.3416e+00},
{-4.4721e-01, -2.7756e-17}, {-8.9443e-01, -4.4721e-01},
{-8.9443e-01, 4.4721e-01}, {-1.3416e+00, -1.1102e-16}};
// c_nodes will be an array of NumberParityBits of struct c_node
// Each c_node contains an array of <degree> c_sub_node elements
// This structure reduces the indexing calclations in SumProduct()
@ -565,17 +575,14 @@ void sd_to_llr(float llr[], float sd[], int n) {
*/
void Demod2D(float symbol_likelihood[], /* output, M*number_symbols */
COMP r[], /* received QPSK symbols, number_symbols */
COMP S_matrix[], /* constellation of size M */
float EsNo,
float fading[], /* real fading values, number_symbols */
COMP r[], /* received PSK symbols, number_symbols */
COMP S_matrix[], /* constellation of size M */
int M, float EsNo,
float fading[], /* real fading values, number_symbols */
float mean_amp, int number_symbols) {
int M = QPSK_CONSTELLATION_SIZE;
int i, j;
float tempsr, tempsi, Er, Ei;
/* determine output */
for (i = 0; i < number_symbols; i++) { /* go through each received symbol */
for (j = 0; j < M; j++) { /* each postulated symbol */
tempsr = fading[i] * S_matrix[j].real / mean_amp;
@ -583,10 +590,7 @@ void Demod2D(float symbol_likelihood[], /* output, M*number_symbols */
Er = r[i].real / mean_amp - tempsr;
Ei = r[i].imag / mean_amp - tempsi;
symbol_likelihood[i * M + j] = -EsNo * (Er * Er + Ei * Ei);
// printf("symbol_likelihood[%d][%d] = %f\n",
// i,j,symbol_likelihood[i*M+j]);
}
// exit(0);
}
}
@ -633,18 +637,22 @@ void Somap(float bit_likelihood[], /* number_bits, bps*number_symbols */
}
}
void symbols_to_llrs(float llr[], COMP rx_qpsk_symbols[], float rx_amps[],
float EsNo, float mean_amp, int nsyms) {
void symbols_to_llrs(float llr[], COMP rx_psk_symbols[], float rx_amps[],
float EsNo, float mean_amp, int bps, int nsyms) {
int i;
int constellation_points = 1 << bps;
float symbol_likelihood[nsyms * constellation_points];
float bit_likelihood[nsyms * bps];
float symbol_likelihood[nsyms * QPSK_CONSTELLATION_SIZE];
float bit_likelihood[nsyms * QPSK_BITS_PER_SYMBOL];
COMP *S_matrix;
assert((bps == 2) || (bps == 4));
if (bps == 2) S_matrix = S_matrix_qpsk;
if (bps == 4) S_matrix = S_matrix_qam16;
Demod2D(symbol_likelihood, rx_qpsk_symbols, S_matrix, EsNo, rx_amps, mean_amp,
nsyms);
Somap(bit_likelihood, symbol_likelihood, QPSK_CONSTELLATION_SIZE,
QPSK_BITS_PER_SYMBOL, nsyms);
for (i = 0; i < nsyms * QPSK_BITS_PER_SYMBOL; i++) {
Demod2D(symbol_likelihood, rx_psk_symbols, S_matrix, constellation_points,
EsNo, rx_amps, mean_amp, nsyms);
Somap(bit_likelihood, symbol_likelihood, constellation_points, bps, nsyms);
for (i = 0; i < nsyms * bps; i++) {
llr[i] = -bit_likelihood[i];
}
}

View File

@ -47,12 +47,12 @@ int run_ldpc_decoder(struct LDPC *ldpc, uint8_t out_char[], float input[],
int *parityCheckCount);
void sd_to_llr(float llr[], float sd[], int n);
void Demod2D(float symbol_likelihood[], COMP r[], COMP S_matrix[], float EsNo,
float fading[], float mean_amp, int number_symbols);
void Demod2D(float symbol_likelihood[], COMP r[], COMP S_matrix[], int M,
float EsNo, float fading[], float mean_amp, int number_symbols);
void Somap(float bit_likelihood[], float symbol_likelihood[], int M, int bps,
int number_symbols);
void symbols_to_llrs(float llr[], COMP rx_qpsk_symbols[], float rx_amps[],
float EsNo, float mean_amp, int nsyms);
float EsNo, float mean_amp, int bps, int nsyms);
void fsk_rx_filt_to_llrs(float llr[], float rx_filt[], float v_est,
float SNRest, int M, int nsyms);

View File

@ -77,10 +77,14 @@ static const complex float qpsk[] = {1.0f + 0.0f * I, 0.0f + 1.0f * I,
0.0f - 1.0f * I, -1.0f + 0.0f * I};
static const complex float qam16[] = {
1.0f + 1.0f * I, 1.0f + 3.0f * I, 3.0f + 1.0f * I, 3.0f + 3.0f * I,
1.0f - 1.0f * I, 1.0f - 3.0f * I, 3.0f - 1.0f * I, 3.0f - 3.0f * I,
-1.0f + 1.0f * I, -1.0f + 3.0f * I, -3.0f + 1.0f * I, -3.0f + 3.0f * I,
-1.0f - 1.0f * I, -1.0f - 3.0f * I, -3.0f - 1.0f * I, -3.0f - 3.0f * I};
4.4721e-01 + 2.7756e-17 * I, 8.9443e-01 + 4.4721e-01 * I,
8.9443e-01 - 4.4721e-01 * I, 1.3416e+00 + 1.1102e-16 * I,
2.7756e-17 - 4.4721e-01 * I, -4.4721e-01 - 8.9443e-01 * I,
4.4721e-01 - 8.9443e-01 * I, 1.1102e-16 - 1.3416e+00 * I,
-2.7756e-17 + 4.4721e-01 * I, 4.4721e-01 + 8.9443e-01 * I,
-4.4721e-01 + 8.9443e-01 * I, -1.1102e-16 + 1.3416e+00 * I,
-4.4721e-01 - 2.7756e-17 * I, -8.9443e-01 - 4.4721e-01 * I,
-8.9443e-01 + 4.4721e-01 * I, -1.3416e+00 - 1.1102e-16 * I};
/*
* These pilots are compatible with Octave version
@ -123,10 +127,13 @@ complex float qam16_mod(int *bits) {
return qam16[(bits[3] << 3) | (bits[2] << 2) | (bits[1] << 1) | bits[0]];
}
void qam16_demod(complex float symbol, int *bits) {
void qam16_demod(complex float symbol, int *bits, float amp_est) {
float dist[16];
int i;
amp_est += 1E-12; // prevent /0 errors
symbol /= amp_est;
for (i = 0; i < 16; i++) {
dist[i] = cnormf(symbol - qam16[i]);
}
@ -190,6 +197,7 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) {
ofdm->state_machine = "voice1";
ofdm->edge_pilots = 1;
ofdm->codename = "HRA_112_112";
ofdm->EsNodB = 3.0;
ofdm->amp_est_mode = 0;
ofdm->tx_bpf_en = true;
ofdm->rx_bpf_en = false;
@ -224,6 +232,7 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) {
ofdm->state_machine = config->state_machine;
ofdm->edge_pilots = config->edge_pilots;
ofdm->codename = config->codename;
ofdm->EsNodB = config->EsNodB;
ofdm->amp_est_mode = config->amp_est_mode;
ofdm->tx_bpf_en = config->tx_bpf_en;
ofdm->rx_bpf_en = config->rx_bpf_en;
@ -273,6 +282,7 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) {
ofdm->config.state_machine = ofdm->state_machine;
ofdm->config.edge_pilots = ofdm->edge_pilots;
ofdm->config.codename = ofdm->codename;
ofdm->config.EsNodB = ofdm->EsNodB;
ofdm->config.amp_est_mode = ofdm->amp_est_mode;
ofdm->config.tx_bpf_en = ofdm->tx_bpf_en;
ofdm->config.rx_bpf_en = ofdm->rx_bpf_en;
@ -464,13 +474,12 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) {
ofdm->tx_uw_syms =
MALLOC(sizeof(complex float) * (ofdm->nuwbits / ofdm->bps));
assert(ofdm->tx_uw_syms != NULL);
assert(ofdm->bps == 2); // TODO generalise
for (int s = 0; s < (ofdm->nuwbits / ofdm->bps); s++) {
int dibit[2];
dibit[1] = ofdm->tx_uw[2 * s];
dibit[0] = ofdm->tx_uw[2 * s + 1];
ofdm->tx_uw_syms[s] = qpsk_mod(dibit);
for (int b = 0, s = 0; b < ofdm->nuwbits; b += ofdm->bps, s++) {
int bits[ofdm->bps];
for (int i = 0; i < ofdm->bps; i++)
bits[ofdm->bps - 1 - i] = ofdm->tx_uw[b + i];
if (ofdm->bps == 2) ofdm->tx_uw_syms[s] = qpsk_mod(bits);
if (ofdm->bps == 4) ofdm->tx_uw_syms[s] = qam16_mod(bits);
}
/* sync state machine */
@ -1187,25 +1196,15 @@ void ofdm_mod(struct OFDM *ofdm, COMP *result, const int *tx_bits) {
complex float *tx =
(complex float *)result; // complex has same memory layout
complex float tx_sym_lin[length];
int dibit[2];
int s, i;
if (ofdm->bps == 1) {
/* Here we will have Nbitsperpacket / 1 */
for (s = 0; s < length; s++) {
tx_sym_lin[s] = (float)(2 * tx_bits[s] - 1);
}
} else if (ofdm->bps == 2) {
/* Here we will have Nbitsperpacket / 2 */
for (s = 0, i = 0; i < length; s += 2, i++) {
dibit[0] = tx_bits[s + 1] & 0x1;
dibit[1] = tx_bits[s] & 0x1;
tx_sym_lin[i] = qpsk_mod(dibit);
}
} /* else if (ofdm->bps == 3) { } TODO */
assert((ofdm->bps == 2) || (ofdm->bps == 4));
for (int b = 0, s = 0; b < ofdm->bitsperpacket; b += ofdm->bps, s++) {
int bits[ofdm->bps];
for (int i = 0; i < ofdm->bps; i++)
bits[ofdm->bps - 1 - i] = tx_bits[b + i] & 0x1;
if (ofdm->bps == 2) tx_sym_lin[s] = qpsk_mod(bits);
if (ofdm->bps == 4) tx_sym_lin[s] = qam16_mod(bits);
}
ofdm_txframe(ofdm, tx, tx_sym_lin);
}
@ -1875,7 +1874,7 @@ static void ofdm_demod_core(struct OFDM *ofdm, int *rx_bits) {
* frame bit ordering correct
*/
complex float rx_corr;
int abit[2];
int abit[ofdm->bps];
int bit_index = 0;
float sum_amp = 0.0f;
@ -1922,17 +1921,10 @@ static void ofdm_demod_core(struct OFDM *ofdm, int *rx_bits) {
ofdm->aphase_est_pilot_log[(rr * ofdm->nc) + (i - 1)] =
aphase_est_pilot[i];
if (ofdm->bps == 1) {
rx_bits[bit_index++] = crealf(rx_corr) > 0.0f;
} else if (ofdm->bps == 2) {
/*
* Only one final task, decode what quadrant the phase
* is in, and return the dibits
*/
qpsk_demod(rx_corr, abit);
rx_bits[bit_index++] = abit[1];
rx_bits[bit_index++] = abit[0];
}
if (ofdm->bps == 2) qpsk_demod(rx_corr, abit);
if (ofdm->bps == 4) qam16_demod(rx_corr, abit, aamp_est_pilot[i]);
for (int i = 0; i < ofdm->bps; i++)
rx_bits[bit_index++] = abit[ofdm->bps - 1 - i];
}
}
@ -2389,9 +2381,9 @@ void ofdm_get_demod_stats(struct OFDM *ofdm, struct MODEM_STATS *stats,
/*
* Assemble packet of bits from UW, payload bits, and txt bits
*/
void ofdm_assemble_qpsk_modem_packet(struct OFDM *ofdm, uint8_t modem_frame[],
uint8_t payload_bits[],
uint8_t txt_bits[]) {
void ofdm_assemble_psk_modem_packet(struct OFDM *ofdm, uint8_t modem_frame[],
uint8_t payload_bits[],
uint8_t txt_bits[]) {
int s, t;
int p = 0;
@ -2418,10 +2410,10 @@ void ofdm_assemble_qpsk_modem_packet(struct OFDM *ofdm, uint8_t modem_frame[],
/*
* Assemble packet of symbols from UW, payload symbols, and txt bits
*/
void ofdm_assemble_qpsk_modem_packet_symbols(struct OFDM *ofdm,
complex float modem_packet[],
COMP payload_syms[],
uint8_t txt_bits[]) {
void ofdm_assemble_psk_modem_packet_symbols(struct OFDM *ofdm,
complex float modem_packet[],
COMP payload_syms[],
uint8_t txt_bits[]) {
complex float *payload =
(complex float *)&payload_syms[0]; // complex has same memory layout
int Nsymsperpacket = ofdm->bitsperpacket / ofdm->bps;
@ -2433,10 +2425,6 @@ void ofdm_assemble_qpsk_modem_packet_symbols(struct OFDM *ofdm,
int p = 0;
int u = 0;
assert(
ofdm->bps ==
2); /* this only works for QPSK at this stage (e.g. modem packet mod) */
for (s = 0; s < (Nsymsperpacket - Ntxtsyms); s++) {
if ((u < Nuwsyms) && (s == ofdm->uw_ind_sym[u])) {
modem_packet[s] = ofdm->tx_uw_syms[u++];
@ -2448,6 +2436,9 @@ void ofdm_assemble_qpsk_modem_packet_symbols(struct OFDM *ofdm,
assert(u == Nuwsyms);
assert(p == (Nsymsperpacket - Nuwsyms - Ntxtsyms));
/* txt bit insertion only works for QPSK at this stage, however QAM modes
* generally has no txt bits */
assert((Ntxtsyms == 0) || (ofdm->bps == 2));
for (t = 0; s < Nsymsperpacket; s++, t += 2) {
dibit[1] = txt_bits[t] & 0x1;
dibit[0] = txt_bits[t + 1] & 0x1;
@ -2461,24 +2452,22 @@ void ofdm_assemble_qpsk_modem_packet_symbols(struct OFDM *ofdm,
* Disassemble a received packet of symbols into UW bits and payload data
* symbols
*/
void ofdm_disassemble_qpsk_modem_packet(struct OFDM *ofdm,
complex float rx_syms[],
float rx_amps[], COMP codeword_syms[],
float codeword_amps[],
short txt_bits[]) {
void ofdm_disassemble_psk_modem_packet(struct OFDM *ofdm,
complex float rx_syms[], float rx_amps[],
COMP codeword_syms[],
float codeword_amps[],
short txt_bits[]) {
complex float *codeword =
(complex float *)&codeword_syms[0]; // complex has same memory layout
int Nsymsperpacket = ofdm->bitsperpacket / ofdm->bps;
int Nuwsyms = ofdm->nuwbits / ofdm->bps;
int Ntxtsyms = ofdm->ntxtbits / ofdm->bps;
int dibit[2];
int bits[ofdm->bps];
int s, t;
int p = 0;
int u = 0;
assert(ofdm->bps == 2); /* this only works for QPSK at this stage */
for (s = 0; s < (Nsymsperpacket - Ntxtsyms); s++) {
if ((u < Nuwsyms) && (s == ofdm->uw_ind_sym[u])) {
u++;
@ -2492,11 +2481,12 @@ void ofdm_disassemble_qpsk_modem_packet(struct OFDM *ofdm,
assert(u == Nuwsyms);
assert(p == (Nsymsperpacket - Nuwsyms - Ntxtsyms));
for (t = 0; s < Nsymsperpacket; s++, t += 2) {
qpsk_demod(rx_syms[s], dibit);
for (t = 0; s < Nsymsperpacket; s++, t += ofdm->bps) {
if (ofdm->bps == 2) qpsk_demod(rx_syms[s], bits);
if (ofdm->bps == 4) qam16_demod(rx_syms[s], bits, rx_amps[s]);
txt_bits[t] = dibit[1];
txt_bits[t + 1] = dibit[0];
for (int i = 0; i < ofdm->bps; i++)
txt_bits[t + i] = bits[ofdm->bps - 1 - i];
}
assert(t == ofdm->ntxtbits);
@ -2506,7 +2496,7 @@ void ofdm_disassemble_qpsk_modem_packet(struct OFDM *ofdm,
* Disassemble a received packet of symbols into UW bits and payload data
* symbols
*/
void ofdm_disassemble_qpsk_modem_packet_with_text_amps(
void ofdm_disassemble_psk_modem_packet_with_text_amps(
struct OFDM *ofdm, complex float rx_syms[], float rx_amps[],
COMP codeword_syms[], float codeword_amps[], short txt_bits[],
int *textIndex) {
@ -2515,13 +2505,12 @@ void ofdm_disassemble_qpsk_modem_packet_with_text_amps(
int Nsymsperpacket = ofdm->bitsperpacket / ofdm->bps;
int Nuwsyms = ofdm->nuwbits / ofdm->bps;
int Ntxtsyms = ofdm->ntxtbits / ofdm->bps;
int dibit[2];
int bits[ofdm->bps];
int s, t;
int p = 0;
int u = 0;
assert(ofdm->bps == 2); /* this only works for QPSK at this stage */
assert(textIndex != NULL);
for (s = 0; s < (Nsymsperpacket - Ntxtsyms); s++) {
@ -2538,11 +2527,12 @@ void ofdm_disassemble_qpsk_modem_packet_with_text_amps(
assert(p == (Nsymsperpacket - Nuwsyms - Ntxtsyms));
*textIndex = s;
for (t = 0; s < Nsymsperpacket; s++, t += 2) {
qpsk_demod(rx_syms[s], dibit);
for (t = 0; s < Nsymsperpacket; s++, t += ofdm->bps) {
if (ofdm->bps == 2) qpsk_demod(rx_syms[s], bits);
if (ofdm->bps == 4) qam16_demod(rx_syms[s], bits, rx_amps[s]);
txt_bits[t] = dibit[1];
txt_bits[t + 1] = dibit[0];
for (int i = 0; i < ofdm->bps; i++)
txt_bits[t + i] = bits[ofdm->bps - 1 - i];
}
assert(t == ofdm->ntxtbits);
@ -2555,17 +2545,15 @@ void ofdm_extract_uw(struct OFDM *ofdm, complex float rx_syms[],
float rx_amps[], uint8_t rx_uw[]) {
int Nsymsperframe = ofdm->bitsperframe / ofdm->bps;
int Nuwsyms = ofdm->nuwbits / ofdm->bps;
int dibit[2];
int s, u;
assert(ofdm->bps ==
2); /* this only works for QPSK at this stage (e.g. UW demod) */
for (s = 0, u = 0; s < Nsymsperframe * ofdm->nuwframes; s++) {
if ((u < Nuwsyms) && (s == ofdm->uw_ind_sym[u])) {
qpsk_demod(rx_syms[s], dibit);
rx_uw[2 * u] = dibit[1];
rx_uw[2 * u + 1] = dibit[0];
int bits[ofdm->bps];
if (ofdm->bps == 2) qpsk_demod(rx_syms[s], bits);
if (ofdm->bps == 4) qam16_demod(rx_syms[s], bits, rx_amps[s]);
for (int i = 0; i < ofdm->bps; i++)
rx_uw[ofdm->bps * u + i] = bits[ofdm->bps - 1 - i];
u++;
}
}

View File

@ -408,9 +408,7 @@ int main(int argc, char *argv[]) {
else
Ndiscard = 1; /* much longer packets, so discard thresh smaller */
float EsNo = 3.0f;
if (verbose == 2) fprintf(stderr, "Warning EsNo: %f hard coded\n", EsNo);
float EsNo = pow(10.0, ofdm->EsNodB / 10.0);
/* More logging */
COMP payload_syms_log[NFRAMES][Npayloadsymsperpacket];
@ -473,8 +471,8 @@ int main(int argc, char *argv[]) {
/* we have received enough frames to make a complete packet .... */
/* extract payload symbols from packet */
ofdm_disassemble_qpsk_modem_packet(ofdm, rx_syms, rx_amps, payload_syms,
payload_amps, txt_bits);
ofdm_disassemble_psk_modem_packet(ofdm, rx_syms, rx_amps, payload_syms,
payload_amps, txt_bits);
if (ldpc_en) {
assert((ofdm_nuwbits + ofdm_ntxtbits + Npayloadbitsperpacket) <=
@ -492,15 +490,15 @@ int main(int argc, char *argv[]) {
uint8_t out_char[Npayloadbitsperpacket];
if (testframes == true) {
Nerrs_raw =
count_uncoded_errors(&ldpc, ofdm_config, payload_syms_de, 0);
Nerrs_raw = count_uncoded_errors(
&ldpc, ofdm_config, payload_syms_de, payload_amps_de, 0);
Terrs += Nerrs_raw;
Tbits +=
Npayloadbitsperpacket; /* not counting errors in txt bits */
}
symbols_to_llrs(llr, payload_syms_de, payload_amps_de, EsNo,
ofdm->mean_amp, Npayloadsymsperpacket);
ofdm->mean_amp, ofdm->bps, Npayloadsymsperpacket);
assert(Ndatabitsperpacket == ldpc.data_bits_per_frame);
ldpc_decode_frame(&ldpc, &parityCheckCount, &iter, out_char, llr);
@ -524,7 +522,7 @@ int main(int argc, char *argv[]) {
assert(Npayloadsymsperpacket * ofdm_config->bps ==
Npayloadbitsperpacket);
for (i = 0; i < Npayloadsymsperpacket; i++) {
int bits[2];
int bits[ofdm->bps];
complex float s = payload_syms[i].real + I * payload_syms[i].imag;
qpsk_demod(s, bits);
rx_bits_char[ofdm_config->bps * i] = bits[1];
@ -547,17 +545,16 @@ int main(int argc, char *argv[]) {
memset(txt_bits, 0, ofdm_ntxtbits);
uint8_t tx_bits[Nbitsperpacket];
ofdm_generate_payload_data_bits(payload_bits, Npayloadbitsperpacket);
ofdm_assemble_qpsk_modem_packet(ofdm, tx_bits, payload_bits,
txt_bits);
ofdm_assemble_psk_modem_packet(ofdm, tx_bits, payload_bits, txt_bits);
/* count errors across UW, payload, txt bits */
int rx_bits[Nbitsperpacket];
int dibit[2];
assert(ofdm->bps == 2); /* this only works for QPSK at this stage */
int bits[ofdm->bps];
for (int s = 0; s < Nsymsperpacket; s++) {
qpsk_demod(rx_syms[s], dibit);
rx_bits[2 * s] = dibit[1];
rx_bits[2 * s + 1] = dibit[0];
if (ofdm->bps == 2) qpsk_demod(rx_syms[s], bits);
if (ofdm->bps == 4) qam16_demod(rx_syms[s], bits, rx_amps[s]);
for (int i = 0; i < ofdm->bps; i++)
rx_bits[ofdm->bps * s + i] = bits[ofdm->bps - 1 - i];
}
for (Nerrs_raw = 0, i = 0; i < Nbitsperpacket; i++)
if (tx_bits[i] != rx_bits[i]) Nerrs_raw++;

View File

@ -46,7 +46,7 @@ extern "C" {
#define TAU (2.0f * M_PI)
#define ROT45 (M_PI / 4.0f)
#define MAX_UW_BITS 64
#define MAX_UW_BITS 192
#define cmplx(value) (cosf(value) + sinf(value) * I)
#define cmplxconj(value) (cosf(value) + sinf(value) * -I)
@ -108,6 +108,7 @@ struct OFDM_CONFIG {
char *data_mode;
float fmin;
float fmax;
float EsNodB; /* EsNo est used for LDPC decoder */
};
struct OFDM {
@ -248,6 +249,7 @@ struct OFDM {
detector */
char *codename;
float EsNodB; /* EsNo est used for LDPC decoder */
char *state_machine;
};
@ -256,19 +258,19 @@ struct OFDM {
complex float qpsk_mod(int *);
complex float qam16_mod(int *);
void qpsk_demod(complex float, int *);
void qam16_demod(complex float, int *);
void qam16_demod(complex float, int *, float);
void ofdm_txframe(struct OFDM *, complex float *, complex float[]);
void ofdm_assemble_qpsk_modem_packet(struct OFDM *, uint8_t[], uint8_t[],
uint8_t[]);
void ofdm_assemble_qpsk_modem_packet_symbols(struct OFDM *, complex float[],
COMP[], uint8_t[]);
void ofdm_disassemble_qpsk_modem_packet(struct OFDM *, complex float rx_syms[],
float rx_amps[], COMP[], float[],
short[]);
void ofdm_disassemble_qpsk_modem_packet_with_text_amps(struct OFDM *,
complex float rx_syms[],
float rx_amps[], COMP[],
float[], short[], int *);
void ofdm_assemble_psk_modem_packet(struct OFDM *, uint8_t[], uint8_t[],
uint8_t[]);
void ofdm_assemble_psk_modem_packet_symbols(struct OFDM *, complex float[],
COMP[], uint8_t[]);
void ofdm_disassemble_psk_modem_packet(struct OFDM *, complex float rx_syms[],
float rx_amps[], COMP[], float[],
short[]);
void ofdm_disassemble_psk_modem_packet_with_text_amps(struct OFDM *,
complex float rx_syms[],
float rx_amps[], COMP[],
float[], short[], int *);
void ofdm_extract_uw(struct OFDM *ofdm, complex float rx_syms[],
float rx_amps[], uint8_t rx_uw[]);
void ofdm_rand(uint16_t[], int);

View File

@ -398,8 +398,7 @@ int main(int argc, char *argv[]) {
/* assemble packet of bits then modulate */
uint8_t tx_bits_char[Nbitsperpacket];
ofdm_assemble_qpsk_modem_packet(ofdm, tx_bits_char, data_bits,
txt_bits);
ofdm_assemble_psk_modem_packet(ofdm, tx_bits_char, data_bits, txt_bits);
int tx_bits[Nbitsperpacket];
for (i = 0; i < Nbitsperpacket; i++) tx_bits[i] = tx_bits_char[i];
COMP tx_sams[Nsamperpacket];

View File

@ -42,6 +42,7 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->state_machine = "voice1";
config->data_mode = "";
config->codename = "HRA_112_112";
config->EsNodB = 3.0;
config->clip_gain1 = 2.5;
config->clip_gain2 = 0.8;
config->clip_en = true;
@ -92,23 +93,36 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->state_machine = "voice2";
config->ftwindowwidth = 64;
config->foff_limiter = true;
} else if (strcmp(mode, "qam16") == 0) {
/* not in use yet */
} else if (strcmp(mode, "qam16c2") == 0) {
config->ns = 5;
config->np = 5;
config->np = 31;
config->tcp = 0.004;
config->ts = 0.016;
config->nc = 33;
config->bps = 4;
config->txtbits = 0;
config->nuwbits = 15 * 4;
config->bad_uw_errors = 5;
config->ftwindowwidth = 32;
config->nuwbits = 42 * 4;
assert(config->nuwbits <= MAX_UW_BITS);
config->bad_uw_errors = 50;
config->ftwindowwidth = 80;
config->state_machine = "data";
config->amp_est_mode = 1;
config->tx_bpf_en = false;
config->clip_en = false;
config->data_mode = "streaming";
config->amp_scale = 135E3;
config->clip_en = false;
config->tx_bpf_en = false;
config->rx_bpf_en = false;
uint8_t uw[] = {1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1,
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0};
memset(config->tx_uw, 0, config->nuwbits);
memcpy(config->tx_uw, uw, sizeof(uw));
memcpy(&config->tx_uw[config->nuwbits - sizeof(uw)], uw, sizeof(uw));
config->EsNodB = 10;
config->codename = "H_16200_9720";
} else if (strcmp(mode, "datac0") == 0) {
config->ns = 5;
config->np = 4;

View File

@ -182,7 +182,8 @@ static int reliable_text_ldpc_decode(reliable_text_impl_t* obj, char* dest) {
float EsNo = 3.0; // note: constant from freedv_700.c
symbols_to_llrs(llr, (COMP*)deinterleavedSyms, deinterleavedAmps, EsNo,
obj->fdv->ofdm->mean_amp, Npayloadsymsperpacket);
obj->fdv->ofdm->mean_amp, obj->fdv->ofdm->bps,
Npayloadsymsperpacket);
} else {
// Deinterlace the received bits.
gp_deinterleave_bits(deinterleavedBits, src, LDPC_TOTAL_SIZE_BITS / 2);

View File

@ -25,7 +25,6 @@
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* This is a unit test implementation of the OFDM Demod function.
* It is used for several tests:
*
@ -45,40 +44,39 @@
* ofdm_get_test_bits - 10 | * ofdm_mod - - | \
* cohpsk_ch - stm_in.raw -20 -Fs 8000 -f -5
*
* Reference data can be created by running the same input through the x86
* Reference data can be created by running the same input through the x86
* ofdm_demod tool.
*
* ofdm_demod stm_in.raw ref_demod_out.raw -o ofdm_demod_ref_log.txt --testframes
* ofdm_demod stm_in.raw ref_demod_out.raw -o ofdm_demod_ref_log.txt
* --testframes
*
* Comparison of the results to the reference will depend on the test conditions.
* Some small differences are expected due to differences in implementation.
* Comparison of the results to the reference will depend on the test
* conditions. Some small differences are expected due to differences in
* implementation.
*
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "semihosting.h"
#include "codec2_ofdm.h"
#include "ofdm_internal.h"
#include "mpdecode_core.h"
#include "ldpc_codes.h"
#include "interldpc.h"
#include "gp_interleaver.h"
#include "test_bits_ofdm.h"
#include "debug_alloc.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "gp_interleaver.h"
#include "interldpc.h"
#include "ldpc_codes.h"
#include "machdep.h"
#include "mpdecode_core.h"
#include "ofdm_internal.h"
#include "semihosting.h"
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
#include "test_bits_ofdm.h"
#define NDISCARD 20
@ -92,347 +90,361 @@ static int ofdm_rowsperframe;
static int ofdm_nuwbits;
static int ofdm_ntxtbits;
static int ofdm_nin;
static char fout_buffer[4*4096];
static __attribute__ ((section (".ccm"))) char fdiag_buffer[4*8192];
static __attribute__ ((section (".ccm"))) char fin_buffer[4096*8];
static char fout_buffer[4 * 4096];
static __attribute__((section(".ccm"))) char fdiag_buffer[4 * 8192];
static __attribute__((section(".ccm"))) char fin_buffer[4096 * 8];
static char *statemode[] = {
"search",
"trial",
"synced"
};
static char *statemode[] = {"search", "trial", "synced"};
static FILE *fout, *fdiag;
void flush_all(void) {
fflush(fout);
fflush(fdiag);
fflush(stdout);
fflush(stderr);
}
fflush(fout);
fflush(fdiag);
fflush(stdout);
fflush(stderr);
}
int main(int argc, char *argv[]) {
struct OFDM *ofdm;
FILE *fcfg;
int nin_frame;
struct LDPC ldpc;
struct OFDM *ofdm;
FILE *fcfg;
int nin_frame;
struct LDPC ldpc;
// Test configuration, read from stm_cfg.txt
int config_verbose;
int config_testframes;
int config_ldpc_en;
int config_log_payload_syms;
int config_profile;
// Test configuration, read from stm_cfg.txt
int config_verbose;
int config_testframes;
int config_ldpc_en;
int config_log_payload_syms;
int config_profile;
int i;
int Nerrs, Terrs, Tbits, Terrs2, Tbits2, frame_count;
int Tbits_coded, Terrs_coded;
int i;
int Nerrs, Terrs, Tbits, Terrs2, Tbits2, frame_count;
int Tbits_coded, Terrs_coded;
semihosting_init();
semihosting_init();
fprintf(stdout, "OFDM Demod test\n");
fprintf(stdout, "OFDM Demod test\n");
// Read configuration - a file of '0' or '1' characters
char config[8];
fcfg = fopen("stm_cfg.txt", "r");
if (fcfg == NULL) {
fprintf(stderr, "Error opening config file\n");
exit(1);
// Read configuration - a file of '0' or '1' characters
char config[8];
fcfg = fopen("stm_cfg.txt", "r");
if (fcfg == NULL) {
fprintf(stderr, "Error opening config file\n");
exit(1);
}
if (fread(&config[0], 1, 8, fcfg) != 8) {
fprintf(stderr, "Error reading config file\n");
exit(1);
}
config_verbose = config[0] - '0';
config_testframes = config[1] - '0';
config_ldpc_en = config[2] - '0';
config_log_payload_syms = config[3] - '0';
config_profile = config[4] - '0';
fclose(fcfg);
int Nerrs_raw = 0;
int Nerrs_coded = 0;
int iter = 0;
int parityCheckCount = 0;
PROFILE_VAR(ofdm_demod_start, ofdm_demod_sync_search, ofdm_demod_demod,
ofdm_demod_diss, ofdm_demod_snr);
ofdm_demod_start = 0;
ofdm_demod_sync_search = 0;
ofdm_demod_demod = 0;
ofdm_demod_diss = 0;
ofdm_demod_snr = 0;
if (config_profile) machdep_profile_init();
ofdm = ofdm_create(NULL);
assert(ofdm != NULL);
/* Get a copy of the actual modem config */
ofdm_config = ofdm_get_config_param(ofdm);
ldpc_codes_setup(&ldpc, "HRA_112_112");
ofdm_bitsperframe = ofdm_get_bits_per_frame(ofdm);
ofdm_rowsperframe = ofdm_bitsperframe / (ofdm_config->nc * ofdm_config->bps);
ofdm_nuwbits =
(ofdm_config->ns - 1) * ofdm_config->bps - ofdm_config->txtbits;
ofdm_ntxtbits = ofdm_config->txtbits;
ofdm_nin = ofdm_get_nin(ofdm);
ofdm_set_verbose(ofdm, config_verbose);
int Nmaxsamperframe = ofdm_get_max_samples_per_frame(ofdm);
int data_bits_per_frame = ldpc.data_bits_per_frame;
int coded_bits_per_frame = ldpc.coded_bits_per_frame;
int coded_syms_per_frame = ldpc.coded_bits_per_frame / ofdm->bps;
short rx_scaled[Nmaxsamperframe];
int rx_bits[ofdm_bitsperframe];
char rx_bits_char[ofdm_bitsperframe];
uint8_t rx_uw[ofdm_nuwbits];
short txt_bits[ofdm_ntxtbits];
int f = 0;
Nerrs = Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded =
frame_count = 0;
float snr_est_smoothed_dB = 0.0;
float EsNo = 3.0f; // Constant from ofdm_demod.c
COMP payload_syms[coded_syms_per_frame];
float payload_amps[coded_syms_per_frame];
COMP codeword_symbols[coded_syms_per_frame];
float codeword_amps[coded_syms_per_frame];
FILE *fin = fopen("stm_in.raw", "rb");
if (fin == NULL) {
fprintf(stderr, "Error opening input file\n");
exit(1);
}
setvbuf(fin, fin_buffer, _IOFBF, sizeof(fin_buffer));
fout = fopen("stm_out.raw", "wb");
if (fout == NULL) {
fprintf(stderr, "Error opening output file\n");
exit(1);
}
setvbuf(fout, fout_buffer, _IOFBF, sizeof(fout_buffer));
fdiag = fopen("stm_diag.raw", "wb");
if (fdiag == NULL) {
fprintf(stderr, "Error opening diag file\n");
exit(1);
}
setvbuf(fdiag, fdiag_buffer, _IOFBF, sizeof(fdiag_buffer));
nin_frame = ofdm_get_nin(ofdm);
int num_read;
while ((num_read = fread(rx_scaled, sizeof(short), nin_frame, fin)) ==
nin_frame) {
int log_payload_syms_flag = 0;
if (config_profile) PROFILE_SAMPLE(ofdm_demod_start);
/* demod */
if (config_profile)
PROFILE_SAMPLE_AND_LOG2(ofdm_demod_start, " ofdm_demod_start");
if (ofdm->sync_state == search) {
if (config_profile) PROFILE_SAMPLE(ofdm_demod_sync_search);
ofdm_sync_search_shorts(ofdm, rx_scaled, (OFDM_PEAK / 2));
if (config_profile)
PROFILE_SAMPLE_AND_LOG2(ofdm_demod_sync_search,
" ofdm_demod_sync_search");
}
if (fread(&config[0], 1, 8, fcfg) != 8) {
fprintf(stderr, "Error reading config file\n");
exit(1);
}
config_verbose = config[0] - '0';
config_testframes = config[1] - '0';
config_ldpc_en = config[2] - '0';
config_log_payload_syms = config[3] - '0';
config_profile = config[4] - '0';
fclose(fcfg);
int Nerrs_raw = 0;
int Nerrs_coded = 0;
int iter = 0;
int parityCheckCount = 0;
if ((ofdm->sync_state == synced) || (ofdm->sync_state == trial)) {
if (config_profile) PROFILE_SAMPLE(ofdm_demod_demod);
ofdm_demod_shorts(ofdm, rx_bits, rx_scaled, (OFDM_PEAK / 2));
if (config_profile)
PROFILE_SAMPLE_AND_LOG2(ofdm_demod_demod, " ofdm_demod_demod");
if (config_profile) PROFILE_SAMPLE(ofdm_demod_diss);
ofdm_extract_uw(ofdm, ofdm->rx_np, ofdm->rx_amp, rx_uw);
ofdm_disassemble_psk_modem_packet(ofdm, ofdm->rx_np, ofdm->rx_amp,
payload_syms, payload_amps, txt_bits);
if (config_profile)
PROFILE_SAMPLE_AND_LOG2(ofdm_demod_diss, " ofdm_demod_diss");
log_payload_syms_flag = 1;
PROFILE_VAR(ofdm_demod_start, ofdm_demod_sync_search,
ofdm_demod_demod, ofdm_demod_diss, ofdm_demod_snr);
ofdm_demod_start = 0;
ofdm_demod_sync_search = 0;
ofdm_demod_demod = 0;
ofdm_demod_diss = 0;
ofdm_demod_snr = 0;
if (config_profile) machdep_profile_init();
/* SNR estimation and smoothing */
if (config_profile) PROFILE_SAMPLE(ofdm_demod_snr);
float EsNodB = ofdm_esno_est_calc((complex float *)payload_syms,
coded_syms_per_frame);
float snr_est_dB = ofdm_snr_from_esno(ofdm, EsNodB);
snr_est_smoothed_dB = 0.9f * snr_est_smoothed_dB + 0.1f * snr_est_dB;
if (config_profile) {
PROFILE_SAMPLE_AND_LOG2(ofdm_demod_snr, " ofdm_demod_snr");
}
ofdm = ofdm_create(NULL);
assert(ofdm != NULL);
// LDPC
if (config_ldpc_en) { // was llr_en in orig
/* Get a copy of the actual modem config */
ofdm_config = ofdm_get_config_param(ofdm);
/* first few symbols are used for UW and txt bits, find
start of (224,112) LDPC codeword and extract QPSK
symbols and amplitude estimates */
assert((ofdm_nuwbits + ofdm_ntxtbits + coded_bits_per_frame) ==
ofdm_bitsperframe);
ldpc_codes_setup(&ldpc, "HRA_112_112");
/* newest symbols at end of buffer (uses final i from last loop) */
for (i = 0; i < coded_syms_per_frame; i++) {
codeword_symbols[i] = payload_syms[i];
codeword_amps[i] = payload_amps[i];
}
ofdm_bitsperframe = ofdm_get_bits_per_frame(ofdm);
ofdm_rowsperframe = ofdm_bitsperframe / (ofdm_config->nc * ofdm_config->bps);
ofdm_nuwbits = (ofdm_config->ns - 1) * ofdm_config->bps - ofdm_config->txtbits;
ofdm_ntxtbits = ofdm_config->txtbits;
ofdm_nin = ofdm_get_nin(ofdm);
/* run de-interleaver */
COMP codeword_symbols_de[coded_syms_per_frame];
float codeword_amps_de[coded_syms_per_frame];
ofdm_set_verbose(ofdm, config_verbose);
gp_deinterleave_comp(codeword_symbols_de, codeword_symbols,
coded_syms_per_frame);
gp_deinterleave_float(codeword_amps_de, codeword_amps,
coded_syms_per_frame);
int Nmaxsamperframe = ofdm_get_max_samples_per_frame(ofdm);
float llr[coded_bits_per_frame];
int data_bits_per_frame = ldpc.data_bits_per_frame;
int coded_bits_per_frame = ldpc.coded_bits_per_frame;
int coded_syms_per_frame = ldpc.coded_bits_per_frame/ofdm->bps;
if (config_ldpc_en) {
uint8_t out_char[coded_bits_per_frame];
short rx_scaled[Nmaxsamperframe];
int rx_bits[ofdm_bitsperframe];
char rx_bits_char[ofdm_bitsperframe];
uint8_t rx_uw[ofdm_nuwbits];
short txt_bits[ofdm_ntxtbits];
int f = 0;
Nerrs = Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded = frame_count = 0;
if (config_testframes) {
Terrs += count_uncoded_errors(
&ldpc, ofdm_config, codeword_symbols_de, codeword_amps_de, 0);
Tbits += coded_bits_per_frame;
}
float snr_est_smoothed_dB = 0.0;
symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo,
ofdm->mean_amp, ofdm->bps, coded_syms_per_frame);
iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount);
float EsNo = 3.0f; // Constant from ofdm_demod.c
// fprintf(stderr,"iter: %d pcc: %d\n", iter, parityCheckCount);
COMP payload_syms[coded_syms_per_frame];
float payload_amps[coded_syms_per_frame];
COMP codeword_symbols[coded_syms_per_frame];
float codeword_amps[coded_syms_per_frame];
if (config_testframes) {
/* construct payload data bits */
uint8_t payload_data_bits[data_bits_per_frame];
ofdm_generate_payload_data_bits(payload_data_bits,
data_bits_per_frame);
FILE* fin = fopen("stm_in.raw", "rb");
if (fin == NULL) {
fprintf(stderr, "Error opening input file\n");
exit(1);
}
setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer));
Nerrs_coded =
count_errors(payload_data_bits, out_char, data_bits_per_frame);
Terrs_coded += Nerrs_coded;
Tbits_coded += data_bits_per_frame;
}
fwrite(out_char, sizeof(char), data_bits_per_frame, fout);
} else {
/* lpdc_en == 0, external LDPC decoder, so output LLRs */
symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo,
ofdm->mean_amp, ofdm->bps, coded_syms_per_frame);
fwrite(llr, sizeof(double), coded_bits_per_frame, fout);
}
} else { // !llrs_en (or ldpc_en)
fout = fopen("stm_out.raw", "wb");
if (fout == NULL) {
fprintf(stderr, "Error opening output file\n");
exit(1);
}
setvbuf(fout, fout_buffer,_IOFBF,sizeof(fout_buffer));
/* simple hard decision output for uncoded testing, excluding UW and txt
*/
assert(coded_syms_per_frame * ofdm_config->bps == coded_bits_per_frame);
for (i = 0; i < coded_syms_per_frame; i++) {
int bits[2];
complex float s = payload_syms[i].real + I * payload_syms[i].imag;
qpsk_demod(s, bits);
rx_bits_char[ofdm_config->bps * i] = bits[1];
rx_bits_char[ofdm_config->bps * i + 1] = bits[0];
}
fdiag = fopen("stm_diag.raw", "wb");
if (fdiag == NULL) {
fprintf(stderr, "Error opening diag file\n");
exit(1);
}
setvbuf(fdiag, fdiag_buffer,_IOFBF,sizeof(fdiag_buffer));
fwrite(rx_bits_char, sizeof(uint8_t), coded_bits_per_frame, fout);
}
/* optional error counting on uncoded data in non-LDPC testframe mode */
if (config_testframes && (config_ldpc_en == 0)) {
/* build up a test frame consisting of unique word, txt bits, and
psuedo-random uncoded payload bits. The psuedo-random generator is
the same as Octave so it can interoperate with ofdm_tx.m/ofdm_rx.m */
int Npayloadbits = ofdm_bitsperframe - (ofdm_nuwbits + ofdm_ntxtbits);
uint16_t r[Npayloadbits];
uint8_t payload_bits[Npayloadbits];
uint8_t tx_bits[Npayloadbits];
ofdm_rand(r, Npayloadbits);
for (i = 0; i < Npayloadbits; i++) {
payload_bits[i] = r[i] > 16384;
// fprintf(stderr,"%d %d ", r[i], tx_bits_char[i]);
}
uint8_t txt_bits[ofdm_ntxtbits];
for (i = 0; i < ofdm_ntxtbits; i++) {
txt_bits[i] = 0;
}
ofdm_assemble_psk_modem_packet(ofdm, tx_bits, payload_bits, txt_bits);
Nerrs = 0;
for (i = 0; i < ofdm_bitsperframe; i++) {
if (tx_bits[i] != rx_bits[i]) {
Nerrs++;
}
}
Terrs += Nerrs;
Tbits += ofdm_bitsperframe;
if (frame_count >= NDISCARD) {
Terrs2 += Nerrs;
Tbits2 += ofdm_bitsperframe;
}
} // config_testframes ...
frame_count++;
} // state "synced" or "trial"
nin_frame = ofdm_get_nin(ofdm);
int num_read;
while((num_read = fread(rx_scaled, sizeof(short) , nin_frame, fin)) == nin_frame) {
ofdm_sync_state_machine(ofdm, rx_uw);
int log_payload_syms_flag = 0;
/* act on any events returned by state machine */
if (config_profile) PROFILE_SAMPLE(ofdm_demod_start);
/* demod */
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_start, " ofdm_demod_start");
if (ofdm->sync_state == search) {
if (config_profile) PROFILE_SAMPLE(ofdm_demod_sync_search);
ofdm_sync_search_shorts(ofdm, rx_scaled, (OFDM_PEAK/2));
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_sync_search, " ofdm_demod_sync_search");
}
if ((ofdm->sync_state == synced) || (ofdm->sync_state == trial) ) {
if (config_profile) PROFILE_SAMPLE(ofdm_demod_demod);
ofdm_demod_shorts(ofdm, rx_bits, rx_scaled, (OFDM_PEAK/2));
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_demod, " ofdm_demod_demod");
if (config_profile) PROFILE_SAMPLE(ofdm_demod_diss);
ofdm_extract_uw(ofdm, ofdm->rx_np, ofdm->rx_amp, rx_uw);
ofdm_disassemble_qpsk_modem_packet(ofdm, ofdm->rx_np, ofdm->rx_amp, payload_syms, payload_amps, txt_bits);
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_diss, " ofdm_demod_diss");
log_payload_syms_flag = 1;
/* SNR estimation and smoothing */
if (config_profile) PROFILE_SAMPLE(ofdm_demod_snr);
float EsNodB = ofdm_esno_est_calc((complex float*)payload_syms, coded_syms_per_frame);
float snr_est_dB = ofdm_snr_from_esno(ofdm, EsNodB);
snr_est_smoothed_dB = 0.9f * snr_est_smoothed_dB + 0.1f *snr_est_dB;
if (config_profile) {
PROFILE_SAMPLE_AND_LOG2(ofdm_demod_snr, " ofdm_demod_snr");
}
// LDPC
if (config_ldpc_en) { // was llr_en in orig
/* first few symbols are used for UW and txt bits, find
start of (224,112) LDPC codeword and extract QPSK
symbols and amplitude estimates */
assert((ofdm_nuwbits + ofdm_ntxtbits + coded_bits_per_frame)
== ofdm_bitsperframe);
/* newest symbols at end of buffer (uses final i from last loop) */
for(i=0; i < coded_syms_per_frame; i++) {
codeword_symbols[i] = payload_syms[i];
codeword_amps[i] = payload_amps[i];
}
/* run de-interleaver */
COMP codeword_symbols_de[coded_syms_per_frame];
float codeword_amps_de[coded_syms_per_frame];
gp_deinterleave_comp (codeword_symbols_de, codeword_symbols, coded_syms_per_frame);
gp_deinterleave_float(codeword_amps_de, codeword_amps, coded_syms_per_frame);
float llr[coded_bits_per_frame];
if (config_ldpc_en) {
uint8_t out_char[coded_bits_per_frame];
if (config_testframes) {
Terrs += count_uncoded_errors(&ldpc, ofdm_config, codeword_symbols_de, 0);
Tbits += coded_bits_per_frame;
}
symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de,
EsNo, ofdm->mean_amp, coded_syms_per_frame);
iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount);
//fprintf(stderr,"iter: %d pcc: %d\n", iter, parityCheckCount);
if (config_testframes) {
/* construct payload data bits */
uint8_t payload_data_bits[data_bits_per_frame];
ofdm_generate_payload_data_bits(payload_data_bits, data_bits_per_frame);
Nerrs_coded = count_errors(payload_data_bits, out_char, data_bits_per_frame);
Terrs_coded += Nerrs_coded;
Tbits_coded += data_bits_per_frame;
}
fwrite(out_char, sizeof(char), data_bits_per_frame, fout);
} else {
/* lpdc_en == 0, external LDPC decoder, so output LLRs */
symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo, ofdm->mean_amp, coded_syms_per_frame);
fwrite(llr, sizeof(double), coded_bits_per_frame, fout);
}
} else { // !llrs_en (or ldpc_en)
/* simple hard decision output for uncoded testing, excluding UW and txt */
assert(coded_syms_per_frame*ofdm_config->bps == coded_bits_per_frame);
for (i = 0; i < coded_syms_per_frame; i++) {
int bits[2];
complex float s = payload_syms[i].real + I * payload_syms[i].imag;
qpsk_demod(s, bits);
rx_bits_char[ofdm_config->bps * i] = bits[1];
rx_bits_char[ofdm_config->bps * i + 1] = bits[0];
}
fwrite(rx_bits_char, sizeof (uint8_t), coded_bits_per_frame, fout);
}
/* optional error counting on uncoded data in non-LDPC testframe mode */
if (config_testframes && (config_ldpc_en == 0)) {
/* build up a test frame consisting of unique word, txt bits, and psuedo-random
uncoded payload bits. The psuedo-random generator is the same as Octave so
it can interoperate with ofdm_tx.m/ofdm_rx.m */
int Npayloadbits = ofdm_bitsperframe-(ofdm_nuwbits+ofdm_ntxtbits);
uint16_t r[Npayloadbits];
uint8_t payload_bits[Npayloadbits];
uint8_t tx_bits[Npayloadbits];
ofdm_rand(r, Npayloadbits);
for(i=0; i<Npayloadbits; i++) {
payload_bits[i] = r[i] > 16384;
//fprintf(stderr,"%d %d ", r[i], tx_bits_char[i]);
}
uint8_t txt_bits[ofdm_ntxtbits];
for(i=0; i<ofdm_ntxtbits; i++) {
txt_bits[i] = 0;
}
ofdm_assemble_qpsk_modem_packet(ofdm, tx_bits, payload_bits, txt_bits);
Nerrs = 0;
for(i=0; i<ofdm_bitsperframe; i++) {
if (tx_bits[i] != rx_bits[i]) {
Nerrs++;
}
}
Terrs += Nerrs;
Tbits += ofdm_bitsperframe;
if (frame_count >= NDISCARD) {
Terrs2 += Nerrs;
Tbits2 += ofdm_bitsperframe;
}
} // config_testframes ...
frame_count++;
} // state "synced" or "trial"
nin_frame = ofdm_get_nin(ofdm);
ofdm_sync_state_machine(ofdm, rx_uw);
/* act on any events returned by state machine */
if (ofdm->sync_start) {
Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded = frame_count = Nerrs_raw = Nerrs_coded = 0;
}
if (config_testframes && config_verbose) {
fprintf(stderr, "%3d st: %-6s", f, statemode[ofdm->last_sync_state]);
fprintf(stderr, " euw: %2d %1d f: %5.1f eraw: %3d ecdd: %3d iter: %3d pcc: %3d\n",
ofdm->uw_errors, ofdm->sync_counter,
(double)ofdm->foff_est_hz,
Nerrs, Nerrs_coded, iter, parityCheckCount);
}
if (config_log_payload_syms) {
if (! log_payload_syms_flag) {
memset(payload_syms, 0, (sizeof(COMP)*coded_syms_per_frame));
memset(payload_amps, 0, (sizeof(float)*coded_syms_per_frame));
}
fwrite(payload_syms, sizeof(COMP), coded_syms_per_frame, fdiag);
fwrite(payload_amps, sizeof(float), coded_syms_per_frame, fdiag);
}
f++;
} // while(fread(.., fin))
flush_all(); // To make sure this function is included in binary.
fclose(fin);
fclose(fout);
fclose(fdiag);
if (config_testframes) {
printf("BER......: %5.4f Tbits: %5d Terrs: %5d\n", (double)Terrs/Tbits, Tbits, Terrs);
if (!config_ldpc_en) {
printf("BER2.....: %5.4f Tbits: %5d Terrs: %5d\n", (double)Terrs2/Tbits2, Tbits2, Terrs2);
}
if (config_ldpc_en) {
printf("Coded BER: %5.4f Tbits: %5d Terrs: %5d\n",
(double)Terrs_coded/Tbits_coded, Tbits_coded, Terrs_coded);
}
if (ofdm->sync_start) {
Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded =
frame_count = Nerrs_raw = Nerrs_coded = 0;
}
if (config_profile) {
printf("\nStart Profile Data\n");
machdep_profile_print_logged_samples();
printf("End Profile Data\n");
}
if (config_testframes && config_verbose) {
fprintf(stderr, "%3d st: %-6s", f, statemode[ofdm->last_sync_state]);
fprintf(stderr,
" euw: %2d %1d f: %5.1f eraw: %3d ecdd: %3d iter: %3d pcc: %3d\n",
ofdm->uw_errors, ofdm->sync_counter, (double)ofdm->foff_est_hz,
Nerrs, Nerrs_coded, iter, parityCheckCount);
}
printf("\nEnd of Test\n");
fclose(stdout);
fclose(stderr);
if (config_log_payload_syms) {
if (!log_payload_syms_flag) {
memset(payload_syms, 0, (sizeof(COMP) * coded_syms_per_frame));
memset(payload_amps, 0, (sizeof(float) * coded_syms_per_frame));
}
fwrite(payload_syms, sizeof(COMP), coded_syms_per_frame, fdiag);
fwrite(payload_amps, sizeof(float), coded_syms_per_frame, fdiag);
}
return 0;
f++;
} // while(fread(.., fin))
flush_all(); // To make sure this function is included in binary.
fclose(fin);
fclose(fout);
fclose(fdiag);
if (config_testframes) {
printf("BER......: %5.4f Tbits: %5d Terrs: %5d\n", (double)Terrs / Tbits,
Tbits, Terrs);
if (!config_ldpc_en) {
printf("BER2.....: %5.4f Tbits: %5d Terrs: %5d\n",
(double)Terrs2 / Tbits2, Tbits2, Terrs2);
}
if (config_ldpc_en) {
printf("Coded BER: %5.4f Tbits: %5d Terrs: %5d\n",
(double)Terrs_coded / Tbits_coded, Tbits_coded, Terrs_coded);
}
}
if (config_profile) {
printf("\nStart Profile Data\n");
machdep_profile_print_logged_samples();
printf("End Profile Data\n");
}
printf("\nEnd of Test\n");
fclose(stdout);
fclose(stderr);
return 0;
}
/* vi:set ts=4 et sts=4: */

View File

@ -29,7 +29,7 @@
*
* Typical run:
ofdm_gen_test_bits stm_in.raw 6 --rand
ofdm_gen_test_bits stm_in.raw 6 --rand
ofdm_mod stm_in.raw ref_mod_out.raw
@ -58,191 +58,195 @@
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "semihosting.h"
#include "codec2_ofdm.h"
#include "ofdm_internal.h"
#include "ldpc_codes.h"
#include "interldpc.h"
#include "gp_interleaver.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
#include "debug_alloc.h"
#include "gp_interleaver.h"
#include "interldpc.h"
#include "ldpc_codes.h"
#include "machdep.h"
#include "ofdm_internal.h"
#include "semihosting.h"
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
int main(int argc, char *argv[]) {
struct OFDM *ofdm;
FILE *fcfg;
struct LDPC ldpc;
struct OFDM *ofdm;
FILE *fcfg;
struct LDPC ldpc;
// Test configuration, read from stm_cfg.txt
int config_verbose;
// int config_testframes;
int config_ldpc_en;
// int config_log_payload_syms;
int config_profile;
// Test configuration, read from stm_cfg.txt
int config_verbose;
// int config_testframes;
int config_ldpc_en;
// int config_log_payload_syms;
int config_profile;
int Nbitsperframe, Nsamperframe;
int frame = 0;
int i;
int Nbitsperframe, Nsamperframe;
int frame = 0;
int i;
semihosting_init();
semihosting_init();
printf("OFDM_mod test and profile\n");
printf("OFDM_mod test and profile\n");
// Read configuration - a file of '0' or '1' characters
char config[8];
fcfg = fopen("stm_cfg.txt", "r");
if (fcfg == NULL) {
fprintf(stderr, "Error opening config file\n");
exit(1);
}
if (fread(&config[0], 1, 8, fcfg) != 8) {
fprintf(stderr, "Error reading config file\n");
exit(1);
}
config_verbose = config[0] - '0';
// config_testframes = config[1] - '0';
config_ldpc_en = config[2] - '0';
// config_log_payload_syms = config[3] - '0';
config_profile = config[4] - '0';
fclose(fcfg);
// Read configuration - a file of '0' or '1' characters
char config[8];
fcfg = fopen("stm_cfg.txt", "r");
if (fcfg == NULL) {
fprintf(stderr, "Error opening config file\n");
exit(1);
}
if (fread(&config[0], 1, 8, fcfg) != 8) {
fprintf(stderr, "Error reading config file\n");
exit(1);
}
config_verbose = config[0] - '0';
// config_testframes = config[1] - '0';
config_ldpc_en = config[2] - '0';
// config_log_payload_syms = config[3] - '0';
config_profile = config[4] - '0';
fclose(fcfg);
PROFILE_VAR(ofdm_mod_start);
if (config_profile) machdep_profile_init();
PROFILE_VAR(ofdm_mod_start);
if (config_profile) machdep_profile_init();
struct OFDM_CONFIG *ofdm_config;
struct OFDM_CONFIG *ofdm_config;
ofdm = ofdm_create(NULL);
assert(ofdm != NULL);
ofdm = ofdm_create(NULL);
assert(ofdm != NULL);
/* Get a copy of the actual modem config */
ofdm_config = ofdm_get_config_param(ofdm);
/* Get a copy of the actual modem config */
ofdm_config = ofdm_get_config_param(ofdm);
ldpc_codes_setup(&ldpc, "HRA_112_112");
ldpc_codes_setup(&ldpc, "HRA_112_112");
Nbitsperframe = ofdm_get_bits_per_frame(ofdm);
int Ndatabitsperframe;
if (config_ldpc_en) {
Ndatabitsperframe = ldpc.data_bits_per_frame;
} else {
Ndatabitsperframe = ofdm_get_bits_per_frame(ofdm) - ofdm->nuwbits - ofdm->ntxtbits;
}
Nbitsperframe = ofdm_get_bits_per_frame(ofdm);
int Ndatabitsperframe;
if (config_ldpc_en) {
Ndatabitsperframe = ldpc.data_bits_per_frame;
} else {
Ndatabitsperframe =
ofdm_get_bits_per_frame(ofdm) - ofdm->nuwbits - ofdm->ntxtbits;
}
Nsamperframe = ofdm_get_samples_per_frame(ofdm);
// int ofdm_nuwbits = (ofdm_config->ns - 1) * ofdm_config->bps - ofdm_config->txtbits;
Nsamperframe = ofdm_get_samples_per_frame(ofdm);
// int ofdm_nuwbits = (ofdm_config->ns - 1) * ofdm_config->bps -
// ofdm_config->txtbits;
if (config_verbose) {
ofdm_set_verbose(ofdm, config_verbose);
fprintf(stderr, "Nsamperframe: %d, Nbitsperframe: %d \n", Nsamperframe, Nbitsperframe);
}
if (config_verbose) {
ofdm_set_verbose(ofdm, config_verbose);
fprintf(stderr, "Nsamperframe: %d, Nbitsperframe: %d \n", Nsamperframe,
Nbitsperframe);
}
int ofdm_ntxtbits = ofdm_config->txtbits;
int ofdm_ntxtbits = ofdm_config->txtbits;
uint8_t tx_bits_char[Ndatabitsperframe];
int16_t tx_scaled[Nsamperframe];
uint8_t txt_bits_char[ofdm_ntxtbits];
uint8_t tx_bits_char[Ndatabitsperframe];
int16_t tx_scaled[Nsamperframe];
uint8_t txt_bits_char[ofdm_ntxtbits];
for(i=0; i< ofdm_ntxtbits; i++) {
txt_bits_char[i] = 0;
}
if (config_verbose) {
ofdm_print_info(ofdm);
}
for (i = 0; i < ofdm_ntxtbits; i++) {
txt_bits_char[i] = 0;
}
int sin = open("stm_in.raw", O_RDONLY);
if (sin < 0) {
printf("Error opening input file\n");
exit(1);
}
if (config_verbose) {
ofdm_print_info(ofdm);
}
int sout = open("mod.raw", O_WRONLY|O_TRUNC|O_CREAT, 0666);
if (sout < 0) {
printf("Error opening output file\n");
exit(1);
}
int sin = open("stm_in.raw", O_RDONLY);
if (sin < 0) {
printf("Error opening input file\n");
exit(1);
}
while (read(sin, tx_bits_char, sizeof(char) * Ndatabitsperframe) == Ndatabitsperframe) {
fprintf(stderr, "Frame %d\n", frame);
int sout = open("mod.raw", O_WRONLY | O_TRUNC | O_CREAT, 0666);
if (sout < 0) {
printf("Error opening output file\n");
exit(1);
}
if (config_profile) { PROFILE_SAMPLE(ofdm_mod_start); }
if (config_ldpc_en) {
complex float tx_sams[Nsamperframe];
ofdm_ldpc_interleave_tx(ofdm, &ldpc, tx_sams, tx_bits_char, txt_bits_char);
for(i=0; i<Nsamperframe; i++) {
tx_scaled[i] = crealf(tx_sams[i]);
}
} else { // !config_ldpc_en
uint8_t tx_frame[Nbitsperframe];
ofdm_assemble_qpsk_modem_packet(ofdm, tx_frame, tx_bits_char, txt_bits_char);
int tx_bits[Nbitsperframe];
for(i=0; i<Nbitsperframe; i++) {
tx_bits[i] = tx_frame[i];
}
if (config_verbose >=3) {
fprintf(stderr, "\ntx_bits:\n");
for (i = 0; i < Nbitsperframe; i++) {
fprintf(stderr, " %3d %8d\n", i, tx_bits[i]);
}
}
COMP tx_sams[Nsamperframe];
ofdm_mod(ofdm, tx_sams, tx_bits);
if (config_verbose >=3) {
fprintf(stderr, "\ntx_sams:\n");
for (i = 0; i < Nsamperframe; i++) {
fprintf(stderr, " %3d % f\n", i, (double)tx_sams[i].real);
}
}
for(i=0; i<Nsamperframe; i++) {
tx_scaled[i] = tx_sams[i].real;
}
}
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_mod_start, " ofdm_mod");
write(sout, tx_scaled, sizeof(int16_t) * Nsamperframe);
frame ++;
} // while (fread(...
close(sin);
close(sout);
if (config_verbose)
printf("%d frames processed\n", frame);
while (read(sin, tx_bits_char, sizeof(char) * Ndatabitsperframe) ==
Ndatabitsperframe) {
fprintf(stderr, "Frame %d\n", frame);
if (config_profile) {
printf("\nStart Profile Data\n");
machdep_profile_print_logged_samples();
printf("End Profile Data\n");
PROFILE_SAMPLE(ofdm_mod_start);
}
if (config_ldpc_en) {
complex float tx_sams[Nsamperframe];
ofdm_ldpc_interleave_tx(ofdm, &ldpc, tx_sams, tx_bits_char,
txt_bits_char);
for (i = 0; i < Nsamperframe; i++) {
tx_scaled[i] = crealf(tx_sams[i]);
}
} else { // !config_ldpc_en
uint8_t tx_frame[Nbitsperframe];
ofdm_assemble_psk_modem_packet(ofdm, tx_frame, tx_bits_char,
txt_bits_char);
int tx_bits[Nbitsperframe];
for (i = 0; i < Nbitsperframe; i++) {
tx_bits[i] = tx_frame[i];
}
if (config_verbose >= 3) {
fprintf(stderr, "\ntx_bits:\n");
for (i = 0; i < Nbitsperframe; i++) {
fprintf(stderr, " %3d %8d\n", i, tx_bits[i]);
}
}
printf("\nEnd of Test\n");
fclose(stdout);
fclose(stderr);
COMP tx_sams[Nsamperframe];
ofdm_mod(ofdm, tx_sams, tx_bits);
return 0;
if (config_verbose >= 3) {
fprintf(stderr, "\ntx_sams:\n");
for (i = 0; i < Nsamperframe; i++) {
fprintf(stderr, " %3d % f\n", i, (double)tx_sams[i].real);
}
}
for (i = 0; i < Nsamperframe; i++) {
tx_scaled[i] = tx_sams[i].real;
}
}
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_mod_start, " ofdm_mod");
write(sout, tx_scaled, sizeof(int16_t) * Nsamperframe);
frame++;
} // while (fread(...
close(sin);
close(sout);
if (config_verbose) printf("%d frames processed\n", frame);
if (config_profile) {
printf("\nStart Profile Data\n");
machdep_profile_print_logged_samples();
printf("End Profile Data\n");
}
printf("\nEnd of Test\n");
fclose(stdout);
fclose(stderr);
return 0;
}
/* vi:set ts=4 et sts=4: */

View File

@ -324,8 +324,8 @@ int main(int argc, char *argv[]) {
for (i = 0; i < ofdm_ntxtbits; i++) txt_bits[i] = 0;
uint8_t tx_bits_char[ofdm_bitsperframe];
ofdm_assemble_qpsk_modem_packet(ofdm, tx_bits_char, payload_bits,
txt_bits);
ofdm_assemble_psk_modem_packet(ofdm, tx_bits_char, payload_bits,
txt_bits);
for (i = 0; i < ofdm_bitsperframe; i++) tx_bits[i] = tx_bits_char[i];
}
@ -475,8 +475,8 @@ int main(int argc, char *argv[]) {
float *ldpc_codeword_symbol_amps =
&ofdm->rx_amp[(ofdm_nuwbits + ofdm_ntxtbits) / ofdm_bps];
Demod2D(symbol_likelihood, ldpc_codeword_symbols, S_matrix, EsNo,
ldpc_codeword_symbol_amps, ofdm->mean_amp,
Demod2D(symbol_likelihood, ldpc_codeword_symbols, S_matrix, 1 << ofdm_bps,
EsNo, ldpc_codeword_symbol_amps, ofdm->mean_amp,
CODED_BITSPERFRAME / ofdm_bps);
Somap(bit_likelihood, symbol_likelihood, 1 << ofdm_bps, ofdm_bps,
CODED_BITSPERFRAME / ofdm_bps);

View File

@ -19,7 +19,7 @@ int main(void) {
int tx_bits[4], rx_bits[4];
for (int i = 0; i < 4; i++) tx_bits[i] = (c >> (3 - i)) & 0x1;
complex float symbol = qam16_mod(tx_bits);
qam16_demod(symbol, rx_bits);
qam16_demod(symbol, rx_bits, 1.0);
if (memcmp(tx_bits, rx_bits, 4)) {
fprintf(stderr, "FAIL on %d!\ntx_bits: ", c);
for (int i = 0; i < 4; i++) fprintf(stderr, "%d ", tx_bits[i]);