mirror of https://github.com/drowe67/codec2.git
Merge 6aeb1f52d6
into 6930e3c26a
commit
fe12189105
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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[],
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
146
src/ofdm.c
146
src/ofdm.c
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
|
|
Loading…
Reference in New Issue