#define NORM_PWR_COHPSK 1.74 /* experimentally derived fudge factor to normalise power for cohpsk modes */
#define NORM_PWR_FSK 0.193 /* experimentally derived fudge factor to normalise power for fsk modes */
+#define NORM_PWR_OFDM 10.00 /* todo: experimentally derived fudge factor to normalise power for OFDM modes */
+
+/* OFDM payload data test frame for 700D */
+
+extern int payload_data_bits[];
/*---------------------------------------------------------------------------*\
return NULL;
f->sz_error_pattern = cohpsk_error_pattern_size();
}
-
+
if (mode == FREEDV_MODE_700D) {
/*
TODO:
codec2_mode = CODEC2_MODE_700C;
f->ofdm = ofdm_create(OFDM_CONFIG_700D);
+ f->interleave_frames = 1;
+
f->nin = ofdm_get_samples_per_frame();
f->n_nat_modem_samples = ofdm_get_samples_per_frame();
f->n_nom_modem_samples = ofdm_get_samples_per_frame();
f->codec2 = codec2_create(codec2_mode);
if (f->codec2 == NULL)
return NULL;
-
+
/* work out how many codec 2 frames per mode frame, and number of
bytes of storage for packed and unpacket bits. TODO: do we really
need to work in packed bits at all? It's messy, chars would probably
assert((f->ldpc->data_bits_per_frame % codec2_bits_per_frame(f->codec2)) == 0);
- int Ncodec2frames = f->ldpc->data_bits_per_frame/codec2_bits_per_frame(f->codec2);
-
+ int Ncodec2frames = f->ldpc->data_bits_per_frame*f->interleave_frames/codec2_bits_per_frame(f->codec2);
f->n_speech_samples = Ncodec2frames*codec2_samples_per_frame(f->codec2);
f->n_codec_bits = Ncodec2frames*codec2_bits_per_frame(f->codec2);
nbit = f->n_codec_bits;
nbyte = (nbit + 7) / 8;
+ fprintf(stderr, "Ncodec2frames: %d nbit: %d nbyte: %d \n", Ncodec2frames, nbit, nbyte);
}
f->packed_codec_bits = (unsigned char*)malloc(nbyte*sizeof(char));
if (mode == FREEDV_MODE_1600)
f->codec_bits = (int*)malloc(nbit*sizeof(int));
- if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B) || (mode == FREEDV_MODE_700C))
+ if ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B) || (mode == FREEDV_MODE_700C) || (mode == FREEDV_MODE_700D))
f->codec_bits = (int*)malloc(COHPSK_BITS_PER_FRAME*sizeof(int));
/* Note: VHF Framer/deframer goes directly from packed codec/vc/proto bits to filled frame */
COMP tx_fdm[f->n_nom_modem_samples];
int i;
assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) ||
- (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C) ||
+ (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C) ||
+ (f->mode == FREEDV_MODE_700D) ||
(f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ||
(f->mode == FREEDV_MODE_800XA));
* stick them in the real sample tx/rx functions than to add a comp->real converter
* to comptx */
- if((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)){
+ if ((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)){
/* 800XA has two codec frames per modem frame */
if((f->mode == FREEDV_MODE_800XA)){
codec2_encode(f->codec2, &f->packed_codec_bits[0], &speech_in[ 0]);
codec2_encode(f->codec2, f->packed_codec_bits, speech_in);
}
freedv_tx_fsk_voice(f, mod_out);
- }else{
+ } else{
freedv_comptx(f, tx_fdm, speech_in);
for(i=0; i<f->n_nom_modem_samples; i++)
mod_out[i] = tx_fdm[i].real;
}
#ifndef CORTEX_M4
-static void freedv_comptx_fdmdv_700(struct freedv *f, COMP mod_out[]) {
+static void freedv_comptx_700(struct freedv *f, COMP mod_out[]) {
int bit, byte, i, j, k;
int bits_per_codec_frame, bits_per_modem_frame;
int data_flag_index, nspare;
// Caution: assert fails if f->n_nat_modem_samples * 16.0 / 15.0 is not an integer
}
+
+/*
+ TODO: Configure to input/output one modem frame for each call, even
+ when interleaved. This means we'll need to buffer coded bits,
+ then buffer tx modem signal. Start with single frame, get that
+ working first.
+*/
+
+static void freedv_comptx_700d(struct freedv *f, COMP mod_out[]) {
+ int bit, byte, i, j, k;
+ int bits_per_codec_frame, bits_per_modem_frame;
+ int nspare;
+
+ int data_bits_per_frame = f->ldpc->data_bits_per_frame;
+
+ bits_per_modem_frame = f->interleave_frames*data_bits_per_frame;
+ uint8_t tx_bits[bits_per_modem_frame];
+
+ bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
+
+ byte = 0;
+ for (j=0; j<bits_per_modem_frame; j+=bits_per_codec_frame) {
+
+ /* unpack bits, MSB first */
+
+ bit = 7;
+ for(i=0; i<bits_per_codec_frame; i++) {
+ tx_bits[j+i] = (f->packed_codec_bits[byte] >> bit) & 0x1;
+ bit--;
+ if (bit < 0) {
+ bit = 7;
+ byte++;
+ }
+ }
+ if (bit != 7)
+ byte++;
+ }
+
+ // Generate Varicode txt bits. Txt bits in OFDM frame come just
+ // after Unique Word (UW). Txt bits aren't protected by FEC, and need to be
+ // added to each frame after interleaver as done it's thing
+
+ nspare = OFDM_NTXTBITS*f->interleave_frames;
+ uint8_t txt_bits[nspare];
+
+ for(k=0; k<nspare; k++) {
+ if (f->nvaricode_bits) {
+ txt_bits[k] = f->tx_varicode_bits[f->varicode_bit_index++];
+ f->nvaricode_bits--;
+ }
+ if (f->nvaricode_bits == 0) {
+ /* get new char and encode */
+ char s[2];
+ if (f->freedv_get_next_tx_char != NULL) {
+ s[0] = (*f->freedv_get_next_tx_char)(f->callback_state);
+ f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 1);
+ f->varicode_bit_index = 0;
+ }
+ }
+ }
+
+ /* optionally replace codec payload bits with test frames known to rx */
+
+ if (f->test_frames) {
+ for (j=0; j<f->interleave_frames; j++) {
+ for(i=0; i<data_bits_per_frame; i++) {
+ tx_bits[j*data_bits_per_frame + i] = payload_data_bits[i];
+ }
+ }
+ }
+
+ /* OK now ready to LDPC encode, interleave, and OFDM modulate */
+
+ complex float tx_sams[f->interleave_frames*ofdm_get_samples_per_frame()];
+ COMP asam;
+
+ ofdm_ldpc_interleave_tx(f->ofdm, f->ldpc, tx_sams, tx_bits, txt_bits, f->interleave_frames);
+
+ assert(f->n_nat_modem_samples == f->interleave_frames*ofdm_get_samples_per_frame());
+
+ for(i=0; i<f->n_nat_modem_samples; i++) {
+ asam.real = crealf(tx_sams[i]);
+ asam.imag = cimagf(tx_sams[i]);
+ mod_out[i] = fcmult(FDMDV_SCALE*NORM_PWR_OFDM, asam);
+ }
+
+ assert(f->clip == 0); /* todo: support clipping, requires some simulations and testing */
+}
+
#endif
+
void freedv_comptx(struct freedv *f, COMP mod_out[], short speech_in[]) {
assert(f != NULL);
#ifndef CORTEX_M4
assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) ||
(f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C) ||
- (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B));
+ (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ||
+ (f->mode == FREEDV_MODE_700D));
if (f->mode == FREEDV_MODE_1600) {
codec2_encode(f->codec2, f->packed_codec_bits, speech_in);
}
#ifndef CORTEX_M4
- if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B)|| (f->mode == FREEDV_MODE_700C)) {
+
+ /* all these modes need to pack a bunch of codec frames into one modem frame */
+
+ if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)
+ || (f->mode == FREEDV_MODE_700D)) {
bits_per_codec_frame = codec2_bits_per_frame(f->codec2);
int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
int codec_frames = f->n_codec_bits / bits_per_codec_frame;
- for (j=0; j < codec_frames; j++) {
+ for (j=0; j<codec_frames; j++) {
codec2_encode(f->codec2, f->packed_codec_bits + j * bytes_per_codec_frame, speech_in);
speech_in += codec2_samples_per_frame(f->codec2);
}
- freedv_comptx_fdmdv_700(f, mod_out);
+ if (f->mode == FREEDV_MODE_700D) {
+ freedv_comptx_700d(f, mod_out);
+ } else {
+ freedv_comptx_700(f, mod_out);
+ }
}
#endif
/* 2400 A and B are handled by the real-mode TX */
case FREEDV_MODE_700:
case FREEDV_MODE_700B:
case FREEDV_MODE_700C:
- freedv_comptx_fdmdv_700(f, tx_fdm);
+ freedv_comptx_700(f, tx_fdm);
break;
case FREEDV_MODE_2400A:
case FREEDV_MODE_2400B:
}
#ifndef CORTEX_M4
-static int freedv_comprx_fdmdv_700(struct freedv *f, COMP demod_in_8kHz[], int *valid) {
+static int freedv_comprx_700(struct freedv *f, COMP demod_in_8kHz[], int *valid) {
int bits_per_codec_frame, bytes_per_codec_frame;
int i, j, bit, byte, nout, k;
int data_flag_index, n_ascii, nspare;
}
#ifndef CORTEX_M4
if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) {
- nout = freedv_comprx_fdmdv_700(f, demod_in, &valid);
+ nout = freedv_comprx_700(f, demod_in, &valid);
//valid = -1;
}
#ifndef CORTEX_M4
if ((f->mode == FREEDV_MODE_700) || (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_700C)) {
- freedv_comprx_fdmdv_700(f, rx_fdm, &valid);
+ freedv_comprx_700(f, rx_fdm, &valid);
}
#endif
void freedv_set_callback_txt (struct freedv *freedv, freedv_callback_rx rx, freedv_callback_tx tx, void *callback_state);
void freedv_set_callback_protocol (struct freedv *freedv, freedv_callback_protorx rx, freedv_callback_prototx tx, void *callback_state);
-void freedv_set_callback_data (struct freedv *freedv, freedv_callback_datarx datarx, freedv_callback_datatx datatx, void *callback_state);
-void freedv_set_test_frames (struct freedv *freedv, int test_frames);
+void freedv_set_callback_data (struct freedv *freedv, freedv_callback_datarx datarx, freedv_callback_datatx datatx, void *callback_state);
+void freedv_set_test_frames (struct freedv *freedv, int test_frames);
void freedv_set_test_frames_diversity (struct freedv *freedv, int test_frames_diversity);
-void freedv_set_smooth_symbols (struct freedv *freedv, int smooth_symbols);
-void freedv_set_squelch_en (struct freedv *freedv, int squelch_en);
-void freedv_set_snr_squelch_thresh (struct freedv *freedv, float snr_squelch_thresh);
+void freedv_set_smooth_symbols (struct freedv *freedv, int smooth_symbols);
+void freedv_set_squelch_en (struct freedv *freedv, int squelch_en);
+void freedv_set_snr_squelch_thresh (struct freedv *freedv, float snr_squelch_thresh);
void freedv_set_clip (struct freedv *freedv, int val);
void freedv_set_total_bit_errors (struct freedv *freedv, int val);
void freedv_set_total_bits (struct freedv *freedv, int val);
int freedv_get_mode (struct freedv *freedv);
void freedv_get_modem_stats (struct freedv *freedv, int *sync, float *snr_est);
void freedv_get_modem_extended_stats(struct freedv *freedv, struct MODEM_STATS *stats);
-int freedv_get_test_frames (struct freedv *freedv);
-int freedv_get_n_speech_samples (struct freedv *freedv);
-int freedv_get_modem_sample_rate (struct freedv *freedv);
-int freedv_get_n_max_modem_samples (struct freedv *freedv);
-int freedv_get_n_nom_modem_samples (struct freedv *freedv);
-int freedv_get_total_bits (struct freedv *freedv);
-int freedv_get_total_bit_errors (struct freedv *freedv);
-int freedv_get_sync (struct freedv *freedv);
-struct FSK * freedv_get_fsk(struct freedv *f);
-struct CODEC2 *freedv_get_codec2 (struct freedv *freedv);
-int freedv_get_n_codec_bits (struct freedv *freedv);
+int freedv_get_test_frames (struct freedv *freedv);
+int freedv_get_n_speech_samples (struct freedv *freedv);
+int freedv_get_modem_sample_rate (struct freedv *freedv);
+int freedv_get_n_max_modem_samples (struct freedv *freedv);
+int freedv_get_n_nom_modem_samples (struct freedv *freedv);
+int freedv_get_total_bits (struct freedv *freedv);
+int freedv_get_total_bit_errors (struct freedv *freedv);
+int freedv_get_sync (struct freedv *freedv);
+struct FSK * freedv_get_fsk (struct freedv *f);
+struct CODEC2 *freedv_get_codec2 (struct freedv *freedv);
+int freedv_get_n_codec_bits (struct freedv *freedv);
int freedv_get_sz_error_pattern (struct freedv *freedv);
int freedv_get_protocol_bits (struct freedv *freedv);
struct quisk_cfFilter * ptFilter7500to8000; // Filters to change to/from 7500 and 8000 sps
struct quisk_cfFilter * ptFilter8000to7500;
- int n_speech_samples;
+ int n_speech_samples; // number of speech samples we need for each freedv_tx() call
int n_nom_modem_samples; // size of tx and most rx modem sample buffers
int n_max_modem_samples; // make your rx modem sample buffers this big
int n_nat_modem_samples; // tx modem sample block length as used by the modem before interpolation to output
-
- int modem_sample_rate; // ATM caller is responsible for meeting this (TBC)
+ // usually the same as n_nom_modem_samples, except for 700..700C
+ int modem_sample_rate; // ATM caller is responsible for meeting this
int clip; // non-zero for cohpsk modem output clipping for low PAPR
unsigned char *packed_codec_bits;
int *rx_bits;
int tx_sync_bit;
int smooth_symbols;
- int n_codec_bits; // amount of codec bits in a frame
+ int n_codec_bits; // number of codec bits in a frame
int *ptest_bits_coh;
int *ptest_bits_coh_end;
int nvaricode_bits;
int varicode_bit_index;
+ /* interleaved LDPC OFDM states */
+
+ int interleave_frames; // number of OFDM modem frames in interleaver, e.g. 1,2,4,8,16
+
/* user defined function ptrs to produce and consume ASCII
characters using aux txt channel */
int i;
if (argc < 4) {
- printf("usage: %s 1600|700|700B|700C|2400A|2400B|800XA InputRawSpeechFile OutputModemRawFile [--testframes] [--codectx] [--datatx]\n", argv[0]);
+ printf("usage: %s 1600|700|700B|700C|700D|2400A|2400B|800XA InputRawSpeechFile OutputModemRawFile [--testframes] [--codectx] [--datatx]\n", argv[0]);
printf("e.g %s 1600 hts1a.raw hts1a_fdmdv.raw\n", argv[0]);
exit(1);
}
mode = FREEDV_MODE_700B;
if (!strcmp(argv[1],"700C"))
mode = FREEDV_MODE_700C;
+ if (!strcmp(argv[1],"700D"))
+ mode = FREEDV_MODE_700D;
if (!strcmp(argv[1],"2400A")){
mode = FREEDV_MODE_2400A;
}
}
-void ofdm_ldpc_interleave_tx(struct OFDM *ofdm, struct LDPC *ldpc, complex float tx_sams[], uint8_t tx_bits_char[], complex float tx_symbols[], int interleave_frames)
+/*
+ Given an array of tx_bits, LDPC encodes, interleaves, and OFDM
+ modulates.
+
+ Note this could be refactored to save memory, e.g. for embedded
+ applications we could call ofdm_txframe on a frame by frame
+ basis
+*/
+
+void ofdm_ldpc_interleave_tx(struct OFDM *ofdm, struct LDPC *ldpc, complex float tx_sams[], uint8_t tx_bits[], uint8_t txt_bits[], int interleave_frames)
{
int coded_syms_per_frame = ldpc->coded_syms_per_frame;
int coded_bits_per_frame = ldpc->coded_bits_per_frame;
COMP coded_symbols[interleave_frames*coded_syms_per_frame];
COMP coded_symbols_inter[interleave_frames*coded_syms_per_frame];
int Nsamperframe = ofdm_get_samples_per_frame();
-
+ complex float tx_symbols[(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS + coded_syms_per_frame];
+
int i,j;
for (j=0; j<interleave_frames; j++) {
- ldpc_encode_frame(ldpc, codeword, &tx_bits_char[j*data_bits_per_frame]);
+ ldpc_encode_frame(ldpc, codeword, &tx_bits[j*data_bits_per_frame]);
qpsk_modulate_frame(&coded_symbols[j*coded_syms_per_frame], codeword, coded_syms_per_frame);
}
gp_interleave_comp(coded_symbols_inter, coded_symbols, interleave_frames*coded_syms_per_frame);
for (j=0; j<interleave_frames; j++) {
for(i=0; i<coded_syms_per_frame; i++) {
+ /* todo: we don't need to build modulated UW every tinme, just txt bits */
+ build_modulated_uw(ofdm, tx_symbols, &txt_bits[OFDM_NTXTBITS*j]);
tx_symbols[(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS+i] = coded_symbols_inter[j*coded_syms_per_frame+i].real
+ I * coded_symbols_inter[j*coded_syms_per_frame+i].imag;
}
/* UW never changes so we can pre-load tx_symbols with modulated UW */
-void build_modulated_uw(struct OFDM *ofdm, complex float tx_symbols[])
+void build_modulated_uw(struct OFDM *ofdm, complex float tx_symbols[], uint8_t txt_bits[])
{
int uw_txt_bits[OFDM_NUWBITS+OFDM_NTXTBITS];
COMP uw_txt_syms[(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS];
}
/* clear txt bits for now, they can be added in later */
for(j=0; j<OFDM_NTXTBITS; j++,i++) {
- uw_txt_bits[i] = 0;
+ uw_txt_bits[i] = txt_bits[j];
}
qpsk_modulate_frame(uw_txt_syms, uw_txt_bits, (OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS);
for(i=0; i<(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS; i++) {
int *inter, int *parityCheckCount, int *Nerrs_coded);
int count_uncoded_errors(struct LDPC *ldpc, int Nerrs_raw[], int interleave_frames, COMP codeword_symbols_de[]);
int count_errors(int tx_bits[], char rx_bits[], int n);
-void ofdm_ldpc_interleave_tx(struct OFDM *ofdm, struct LDPC *ldpc, complex float tx_sams[], uint8_t tx_bits_char[], complex float tx_symbols[], int interleave_frames);
-void build_modulated_uw(struct OFDM *ofdm, complex float tx_symbols[]);
+void ofdm_ldpc_interleave_tx(struct OFDM *ofdm, struct LDPC *ldpc, complex float tx_sams[], uint8_t tx_bits[], uint8_t txt_bits[], int interleave_frames);
+void build_modulated_uw(struct OFDM *ofdm, complex float tx_symbols[], uint8_t txt_bits[]);
#endif
set_up_hra_112_112(&ldpc);
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_syms_per_frame;
if (argc < 3) {
fprintf(stderr, "\n");
int Nsamperframe = ofdm_get_samples_per_frame();
fprintf(stderr, "Nbitsperframe: %d interleave_frames: %d\n", Nbitsperframe, interleave_frames);
- unsigned char tx_bits_char[Nbitsperframe];
- int tx_bits[Nbitsperframe];
- short tx_scaled[Nsamperframe];
-
- /* build modulated UW and txt bits */
+ uint8_t tx_bits_char[Nbitsperframe];
+ short tx_scaled[Nsamperframe];
+ uint8_t txt_bits_char[OFDM_NTXTBITS*interleave_frames];
- complex float tx_symbols[(OFDM_NUWBITS+OFDM_NTXTBITS)/OFDM_BPS + coded_syms_per_frame];
- build_modulated_uw(ofdm, tx_symbols);
-
+ for(i=0; i<OFDM_NTXTBITS*interleave_frames; i++) { txt_bits_char[i] = 0; }
+
testframes = 0;
int Nframes = 0;
if ((arg = (opt_exists(argv, argc, "-t")))) {
}
complex float tx_sams[interleave_frames*Nsamperframe];
- ofdm_ldpc_interleave_tx(ofdm, &ldpc, tx_sams, tx_bits_char, tx_symbols, interleave_frames);
+ ofdm_ldpc_interleave_tx(ofdm, &ldpc, tx_sams, tx_bits_char, txt_bits_char, interleave_frames);
for (j=0; j<interleave_frames; j++) {
for(i=0; i<Nsamperframe; i++) {
}
}
- for(i=0; i<Nbitsperframe; i++)
+ int tx_bits[Nbitsperframe];
+ for(i=0; i<Nbitsperframe; i++)
tx_bits[i] = tx_bits_char[i];
COMP tx_sams[Nsamperframe];
ofdm_mod(ofdm, tx_sams, tx_bits);