Merge pull request #46 from drowe67/dr-freedata-001

FreeDATA Feature Request 001 - FreeDV API support for custom OFDM raw data modes
This commit is contained in:
drowe67 2024-05-11 08:13:44 +09:30 committed by GitHub
commit 3d69c8d063
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 221 additions and 111 deletions

View file

@ -1291,6 +1291,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;

View file

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

View file

@ -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,14 @@ 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_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 +225,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 +305,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 +338,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;
@ -471,8 +478,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);
@ -510,8 +517,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;

View file

@ -60,7 +60,7 @@
/* The API version number. The first version is 10. Increment if the API
changes in a way that would require changes by the API user. */
#define VERSION 15
#define VERSION 16
/*
Version 10 Initial version August 2, 2015.
@ -79,6 +79,9 @@
Version 15 December 2022 Removing rarely used DPSK support which is not
needed given fast fading modes
Version 16 April 2024, added field to struct freedv_advanced to support
FREEDV_MODE_DATA_CUSTOM
*/
char *ofdm_statemode[] = {"search", "trial", "synced"};
@ -101,7 +104,8 @@ char *rx_sync_flags_to_text[] = {"----", "---T", "--S-", "--ST", "-B--", "-B-T",
struct freedv *freedv_open(int mode) {
// defaults for those modes that support the use of adv
struct freedv_advanced adv = {0, 2, 100, 8000, 1000, 200, "H_256_512_4"};
struct freedv_advanced adv = {0, 2, 100, 8000,
1000, 200, "H_256_512_4", NULL};
return freedv_open_advanced(mode, &adv);
}
@ -126,7 +130,8 @@ 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)) == false)
return NULL;
/* set everything to zero just in case */
@ -150,12 +155,16 @@ 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);
varicode_decode_init(&f->varicode_dec_states, 1);
@ -238,7 +247,8 @@ 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_DATA_CUSTOM, freedv->mode)) {
FREE(freedv->rx_syms);
FREE(freedv->rx_amps);
FREE(freedv->ldpc);
@ -270,7 +280,8 @@ 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_DATA_CUSTOM, f->mode);
}
static int is_ofdm_data_mode(struct freedv *f) {
@ -279,7 +290,8 @@ 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_DATA_CUSTOM, f->mode);
}
/*---------------------------------------------------------------------------*\
@ -470,7 +482,8 @@ 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_DATA_CUSTOM, f->mode))
freedv_comptx_ofdm(f, mod_out);
if (FDV_MODE_ACTIVE(FREEDV_MODE_FSK_LDPC, f->mode)) {
@ -1070,7 +1083,8 @@ 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_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);
@ -1612,3 +1626,7 @@ unsigned short freedv_gen_crc16(unsigned char *data_p, int length) {
return crc;
}
void freedv_ofdm_print_info(struct freedv *freedv) {
ofdm_print_info(freedv->ofdm);
}

View file

@ -62,6 +62,7 @@ extern "C" {
#define FREEDV_MODE_DATAC4 18
#define FREEDV_MODE_DATAC13 19
#define FREEDV_MODE_DATAC14 20
#define FREEDV_MODE_DATA_CUSTOM 21
// Sample rates used
#define FREEDV_FS_8000 8000
@ -144,6 +145,9 @@ 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
#define FDV_MODE_ACTIVE(mode_name, var) \
((mode_name##_EN) == 0 ? 0 : (var) == mode_name)
@ -163,6 +167,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
@ -334,6 +341,9 @@ int freedv_get_bits_per_modem_frame(struct freedv *freedv);
int freedv_get_sz_error_pattern(struct freedv *freedv);
int freedv_get_protocol_bits(struct freedv *freedv);
// dump OFDM modem config
void freedv_ofdm_print_info(struct freedv *freedv);
#ifdef __cplusplus
}
#endif

View file

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

View file

@ -39,6 +39,7 @@
#include "ldpc_codes.h"
#include "modem_stats.h"
#include "octave.h"
#include "ofdm_internal.h"
/* other processes can end this program using signals */
@ -216,6 +217,8 @@ 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], "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 +251,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 +284,8 @@ int main(int argc, char *argv[]) {
fsk->Ndft);
}
/* for streaming bytes it's much easier use the modes that have a multiple of
* 8 payload bits/frame */
/* for streaming bytes it's much easier use the modes that have a multiple
* of 8 payload bits/frame */
assert((freedv_get_bits_per_modem_frame(freedv) % 8) == 0);
int bytes_per_modem_frame = freedv_get_bits_per_modem_frame(freedv) / 8;
// last two bytes used for CRC

View file

@ -238,6 +238,8 @@ 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], "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 +261,33 @@ 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));
/* set up a trivial Tx band pass filter as a demo */
static float tx_bpf[] = {1.0, 1.0, 1.0};
ofdm_config.tx_bpf_proto = tx_bpf;
ofdm_config.tx_bpf_proto_n = 3;
adv.config = (void *)&ofdm_config;
freedv = freedv_open_advanced(mode, &adv);
freedv_ofdm_print_info(freedv);
} else {
freedv = freedv_open(mode);
}
assert(freedv != NULL);

View file

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

View file

@ -76,9 +76,11 @@ void ldpc_mode_specific_setup(struct OFDM *ofdm, struct LDPC *ldpc) {
set_data_bits_per_frame(ldpc, 156);
ldpc->protection_mode = LDPC_PROT_2020B;
}
if (!strcmp(ofdm->mode, "datac4")) set_data_bits_per_frame(ldpc, 448);
if (!strcmp(ofdm->mode, "datac13")) set_data_bits_per_frame(ldpc, 128);
if (!strcmp(ofdm->mode, "datac14")) set_data_bits_per_frame(ldpc, 40);
/* compute the number of data bits used in the codeword */
int data_bits_per_frame = ofdm->bitsperpacket - ofdm->nuwbits -
ofdm->ntxtbits - ldpc->NumberParityBits;
set_data_bits_per_frame(ldpc, data_bits_per_frame);
}
/* LDPC encode frame - generate parity bits and a codeword, applying the

View file

@ -192,6 +192,8 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) {
ofdm->codename = "HRA_112_112";
ofdm->amp_est_mode = 0;
ofdm->tx_bpf_en = true;
ofdm->tx_bpf_proto = filtP650S900;
ofdm->tx_bpf_proto_n = sizeof(filtP650S900) / sizeof(float);
ofdm->rx_bpf_en = false;
ofdm->amp_scale = 245E3;
ofdm->clip_gain1 = 2.0;
@ -226,6 +228,8 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) {
ofdm->codename = config->codename;
ofdm->amp_est_mode = config->amp_est_mode;
ofdm->tx_bpf_en = config->tx_bpf_en;
ofdm->tx_bpf_proto = config->tx_bpf_proto;
ofdm->tx_bpf_proto_n = config->tx_bpf_proto_n;
ofdm->rx_bpf_en = config->rx_bpf_en;
ofdm->foff_limiter = config->foff_limiter;
ofdm->amp_scale = config->amp_scale;
@ -275,6 +279,8 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) {
ofdm->config.codename = ofdm->codename;
ofdm->config.amp_est_mode = ofdm->amp_est_mode;
ofdm->config.tx_bpf_en = ofdm->tx_bpf_en;
ofdm->config.tx_bpf_proto = ofdm->tx_bpf_proto;
ofdm->config.tx_bpf_proto_n = ofdm->tx_bpf_proto_n;
ofdm->config.rx_bpf_en = ofdm->rx_bpf_en;
ofdm->config.foff_limiter = ofdm->foff_limiter;
ofdm->config.amp_scale = ofdm->amp_scale;
@ -539,36 +545,19 @@ struct OFDM *ofdm_create(const struct OFDM_CONFIG *config) {
static void allocate_tx_bpf(struct OFDM *ofdm) {
ofdm->tx_bpf = MALLOC(sizeof(struct quisk_cfFilter));
assert(ofdm->tx_bpf != NULL);
assert(ofdm->tx_bpf_proto != NULL);
assert(ofdm->tx_bpf_proto_n != 0);
/* Transmit bandpass filter; complex coefficients, center frequency */
if (!strcmp(ofdm->mode, "700D")) {
quisk_filt_cfInit(ofdm->tx_bpf, filtP650S900,
sizeof(filtP650S900) / sizeof(float));
quisk_cfTune(ofdm->tx_bpf, ofdm->tx_centre / ofdm->fs);
} else if (!strcmp(ofdm->mode, "700E") || !strcmp(ofdm->mode, "2020") ||
!strcmp(ofdm->mode, "datac1")) {
quisk_filt_cfInit(ofdm->tx_bpf, filtP900S1100,
sizeof(filtP900S1100) / sizeof(float));
quisk_cfTune(ofdm->tx_bpf, ofdm->tx_centre / ofdm->fs);
} else if (!strcmp(ofdm->mode, "2020B")) {
quisk_filt_cfInit(ofdm->tx_bpf, filtP1100S1300,
sizeof(filtP1100S1300) / sizeof(float));
quisk_cfTune(ofdm->tx_bpf, ofdm->tx_centre / ofdm->fs);
} else if (!strcmp(ofdm->mode, "datac0") || !strcmp(ofdm->mode, "datac3")) {
quisk_filt_cfInit(ofdm->tx_bpf, filtP400S600,
sizeof(filtP400S600) / sizeof(float));
quisk_cfTune(ofdm->tx_bpf, ofdm->tx_centre / ofdm->fs);
} else if (!strcmp(ofdm->mode, "datac4") || !strcmp(ofdm->mode, "datac13") ||
!strcmp(ofdm->mode, "datac14")) {
quisk_filt_cfInit(ofdm->tx_bpf, filtP200S400,
sizeof(filtP200S400) / sizeof(float));
// centre the filter on the mean carrier freq, allows a narrower filter to
// be used
float tx_centre = find_carrier_centre(ofdm);
quisk_cfTune(ofdm->tx_bpf, tx_centre / ofdm->fs);
} else
assert(0);
quisk_filt_cfInit(ofdm->tx_bpf, ofdm->tx_bpf_proto, ofdm->tx_bpf_proto_n);
float tx_centre = ofdm->tx_centre;
if (!strcmp(ofdm->mode, "datac4") || !strcmp(ofdm->mode, "datac13") ||
!strcmp(ofdm->mode, "datac14")) {
// Centre the filter on the mean carrier freq, allows a narrower
// filter to be used. Only really useful for very narrow, Nc odd
// waveforms. TODO: make this feature config controlled
tx_centre = find_carrier_centre(ofdm);
}
quisk_cfTune(ofdm->tx_bpf, tx_centre / ofdm->fs);
}
static void deallocate_tx_bpf(struct OFDM *ofdm) {
@ -589,7 +578,9 @@ static void allocate_rx_bpf(struct OFDM *ofdm) {
ofdm->rx_bpf = MALLOC(sizeof(struct quisk_cfFilter));
assert(ofdm->rx_bpf != NULL);
/* Receive bandpass filter; complex coefficients, center frequency */
/* Receive bandpass filter; complex coefficients, center frequency, only
really needed for very low SNR waveforms. TODO: make this config
controlled. */
if (!strcmp(ofdm->mode, "datac4") || !strcmp(ofdm->mode, "datac13") ||
!strcmp(ofdm->mode, "datac14")) {
@ -2678,6 +2669,11 @@ void ofdm_print_info(struct OFDM *ofdm) {
ofdm->phase_est_en ? "true" : "false");
fprintf(stderr, "ofdm->tx_bpf_en = %s\n", ofdm->tx_bpf_en ? "true" : "false");
fprintf(stderr, "ofdm->rx_bpf_en = %s\n", ofdm->rx_bpf_en ? "true" : "false");
fprintf(stderr, "ofdm->tx_bpf_proto_n = %d\n", ofdm->tx_bpf_proto_n);
fprintf(stderr, "ofdm->tx_bpf_proto:\n");
for (int i = 0; i < ofdm->tx_bpf_proto_n; i++)
fprintf(stderr, "%f\t", ofdm->tx_bpf_proto[i]);
fprintf(stderr, "\n");
fprintf(stderr, "ofdm->dpsk_en = %s\n", ofdm->dpsk_en ? "true" : "false");
fprintf(stderr, "ofdm->phase_est_bandwidth_mode = %s\n",
phase_est_bandwidth_mode[ofdm->phase_est_bandwidth_mode]);

View file

@ -94,15 +94,17 @@ struct OFDM_CONFIG {
char *codename; /* name of LDPC code used with this mode */
uint8_t tx_uw[MAX_UW_BITS]; /* user defined unique word */
int amp_est_mode;
bool tx_bpf_en; /* default tx (mod) hilbert clipper BPF enable */
bool rx_bpf_en; /* default rx (demod) input BPF enable */
bool foff_limiter; /* tames freq offset updates in low SNR */
float amp_scale; /* used to scale Tx waveform to approx FREEDV_PEAK with
clipper off */
float clip_gain1; /* gain we apply to Tx signal before clipping to control
PAPR*/
float clip_gain2; /* gain we apply to Tx signal after clipping and BBF to
control peak level */
bool tx_bpf_en; /* default tx (mod) hilbert clipper BPF enable */
bool rx_bpf_en; /* default rx (demod) input BPF enable */
float *tx_bpf_proto; /* low pass prototype for complex BPF */
int tx_bpf_proto_n; /* number of taps in low pass prototype */
bool foff_limiter; /* tames freq offset updates in low SNR */
float amp_scale; /* used to scale Tx waveform to approx FREEDV_PEAK with
clipper off */
float clip_gain1; /* gain we apply to Tx signal before clipping to control
PAPR*/
float clip_gain2; /* gain we apply to Tx signal after clipping and BBF to
control peak level */
bool clip_en;
char mode[16]; /* OFDM mode in string form */
char *data_mode;
@ -156,6 +158,7 @@ struct OFDM {
int packetsperburst; /* for OFDM data modes, how many packets before we reset
state machine */
int amp_est_mode; /* amplitude estimtor algorithm */
int tx_bpf_proto_n; /* number of taps in low pass prototype */
float amp_scale;
float clip_gain1;
float clip_gain2;
@ -220,6 +223,7 @@ struct OFDM {
float coarse_foff_est_hz;
float timing_norm;
float mean_amp;
float *tx_bpf_proto;
// Integer
int clock_offset_counter;

View file

@ -46,6 +46,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->clip_gain2 = 0.8;
config->clip_en = true;
config->tx_bpf_en = true;
config->tx_bpf_proto = filtP650S900;
config->tx_bpf_proto_n = sizeof(filtP650S900) / sizeof(float);
config->rx_bpf_en = false;
config->amp_scale = 245E3;
config->foff_limiter = false;
@ -69,6 +71,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->amp_scale = 155E3;
config->clip_gain1 = 3;
config->clip_gain2 = 0.8;
config->tx_bpf_proto = filtP900S1100;
config->tx_bpf_proto_n = sizeof(filtP900S1100) / sizeof(float);
} else if ((strcmp(mode, "2020") == 0)) {
config->ts = 0.0205;
config->nc = 31;
@ -76,6 +80,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->amp_scale = 167E3;
config->clip_gain1 = 2.5;
config->clip_gain2 = 0.8;
config->tx_bpf_proto = filtP900S1100;
config->tx_bpf_proto_n = sizeof(filtP900S1100) / sizeof(float);
} else if (strcmp(mode, "2020B") == 0) {
config->ts = 0.014;
config->tcp = 0.004;
@ -92,6 +98,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->state_machine = "voice2";
config->ftwindowwidth = 64;
config->foff_limiter = true;
config->tx_bpf_proto = filtP1100S1300;
config->tx_bpf_proto_n = sizeof(filtP1100S1300) / sizeof(float);
} else if (strcmp(mode, "qam16") == 0) {
/* not in use yet */
config->ns = 5;
@ -109,6 +117,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->tx_bpf_en = false;
config->clip_en = false;
config->data_mode = "streaming";
config->tx_bpf_proto = NULL;
config->tx_bpf_proto_n = 0;
} else if (strcmp(mode, "datac0") == 0) {
config->ns = 5;
config->np = 4;
@ -130,6 +140,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->amp_scale = 300E3;
config->clip_gain1 = 2.2;
config->clip_gain2 = 0.85;
config->tx_bpf_proto = filtP400S600;
config->tx_bpf_proto_n = sizeof(filtP400S600) / sizeof(float);
} else if (strcmp(mode, "datac1") == 0) {
config->ns = 5;
config->np = 38;
@ -152,6 +164,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->amp_scale = 145E3;
config->clip_gain1 = 2.7;
config->clip_gain2 = 0.8;
config->tx_bpf_proto = filtP900S1100;
config->tx_bpf_proto_n = sizeof(filtP900S1100) / sizeof(float);
} else if (strcmp(mode, "datac3") == 0) {
config->ns = 5;
config->np = 29;
@ -176,6 +190,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->amp_scale = 300E3;
config->clip_gain1 = 2.2;
config->clip_gain2 = 0.8;
config->tx_bpf_proto = filtP400S600;
config->tx_bpf_proto_n = sizeof(filtP400S600) / sizeof(float);
} else if (strcmp(mode, "datac4") == 0) {
config->ns = 5;
config->np = 47;
@ -201,6 +217,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->clip_gain1 = 1.2;
config->clip_gain2 = 1.0;
config->rx_bpf_en = true;
config->tx_bpf_proto = filtP200S400;
config->tx_bpf_proto_n = sizeof(filtP200S400) / sizeof(float);
} else if (strcmp(mode, "datac13") == 0) {
config->ns = 5;
config->np = 18;
@ -226,6 +244,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->clip_gain1 = 1.2;
config->clip_gain2 = 1.0;
config->rx_bpf_en = true;
config->tx_bpf_proto = filtP200S400;
config->tx_bpf_proto_n = sizeof(filtP200S400) / sizeof(float);
} else if (strcmp(mode, "datac14") == 0) {
config->ns = 5;
config->np = 4;
@ -251,6 +271,8 @@ void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config) {
config->clip_gain1 = 2.0;
config->clip_gain2 = 1.0;
config->rx_bpf_en = true;
config->tx_bpf_proto = filtP200S400;
config->tx_bpf_proto_n = sizeof(filtP200S400) / sizeof(float);
} else {
assert(0);
}