From: baobrien Date: Wed, 13 Apr 2016 05:07:16 +0000 (+0000) Subject: Initial commit of experimental 800 FSK mode X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=7e0cf8b65fbfec7481edcd8250fe5bb3eaf65202;p=freetel-svn-tracking.git Initial commit of experimental 800 FSK mode git-svn-id: https://svn.code.sf.net/p/freetel/code@2785 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/src/freedv_api.c b/codec2-dev/src/freedv_api.c index 7eff7c1f..8489a2c5 100644 --- a/codec2-dev/src/freedv_api.c +++ b/codec2-dev/src/freedv_api.c @@ -77,7 +77,7 @@ struct freedv *freedv_open(int mode) { if ((mode != FREEDV_MODE_1600) && (mode != FREEDV_MODE_700) && (mode != FREEDV_MODE_700B) && (mode != FREEDV_MODE_2400A) && - (mode != FREEDV_MODE_2400B)) + (mode != FREEDV_MODE_2400B) && (mode != FREEDV_MODE_800XA)) return NULL; f = (struct freedv*)malloc(sizeof(struct freedv)); @@ -203,6 +203,38 @@ struct freedv *freedv_open(int mode) { fmfsk_setup_modem_stats(f->fmfsk,&(f->stats)); } + if (mode == FREEDV_MODE_800XA) { + /* Create the framer|deframer */ + f->deframer = fvhff_create_deframer(FREEDV_HF_FRAME_B,0); + if(f->deframer == NULL) + return NULL; + + f->fsk = fsk_create_hbr(8000,400,10,4,400,400); + fsk_set_nsym(f->fsk,32); + + /* Note: fsk expects tx/rx bits as an array of uint8_ts, not ints */ + f->tx_bits = (int*)malloc(f->fsk->Nbits*sizeof(uint8_t)); + + if(f->fsk == NULL){ + fvhff_destroy_deframer(f->deframer); + return NULL; + } + + f->n_nom_modem_samples = f->fsk->N; + f->n_max_modem_samples = f->fsk->N + (f->fsk->Ts); + f->n_nat_modem_samples = f->fsk->N; + f->nin = fsk_nin(f->fsk); + f->modem_sample_rate = 8000; + /* Malloc something to appease freedv_init and freedv_destroy */ + f->codec_bits = malloc(1); + + f->n_protocol_bits = 0; + codec2_mode = CODEC2_MODE_700B; + + /* Set up the stats */ + fsk_setup_modem_stats(f->fsk,&(f->stats)); + } + #endif f->test_frame_sync_state = 0; @@ -214,12 +246,20 @@ struct freedv *freedv_open(int mode) { return NULL; if ((mode == FREEDV_MODE_1600) || (mode == FREEDV_MODE_2400A) || (mode == FREEDV_MODE_2400B)) { f->n_speech_samples = codec2_samples_per_frame(f->codec2); - f->n_codec_bits = codec2_bits_per_frame(f->codec2); + f->n_codec_bits = codec2_bits_per_frame(f->codec2); nbit = f->n_codec_bits; nbyte = (nbit + 7) / 8; + } else if ((mode == FREEDV_MODE_800XA)) { + f->n_speech_samples = 2*codec2_samples_per_frame(f->codec2); + f->n_codec_bits = codec2_bits_per_frame(f->codec2); + nbit = f->n_codec_bits; + nbyte = (nbit + 7) / 8; + nbyte = nbyte*2; + nbit = 8*nbyte; + f->n_codec_bits = nbit; } else { /* ((mode == FREEDV_MODE_700) || (mode == FREEDV_MODE_700B)) */ f->n_speech_samples = 2*codec2_samples_per_frame(f->codec2); - f->n_codec_bits = 2*codec2_bits_per_frame(f->codec2); + f->n_codec_bits = 2*codec2_bits_per_frame(f->codec2); nbit = f->n_codec_bits; nbyte = 2*((codec2_bits_per_frame(f->codec2) + 7) / 8); } @@ -351,40 +391,46 @@ static void freedv_tx_fsk_voice(struct freedv *f, short mod_out[]) { uint8_t vc_bits[2]; /* Varicode bits for 2400 framing */ uint8_t proto_bits[3]; /* Prococol bits for 2400 framing */ - /* Get varicode bits for TX and possibly ask for a new char */ - /* 2 bits per 2400A/B frame, so this has to be done twice */ - for(i=0;i<2;i++){ - if (f->nvaricode_bits) { - vc_bits[i] = f->tx_varicode_bits[f->varicode_bit_index++]; - f->nvaricode_bits--; - } + /* Frame for 2400A/B */ + if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_2400B){ + /* Get varicode bits for TX and possibly ask for a new char */ + /* 2 bits per 2400A/B frame, so this has to be done twice */ + for(i=0;i<2;i++){ + if (f->nvaricode_bits) { + vc_bits[i] = 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; + 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; + } } } - } - - /* If the API user hasn't set up message callbacks, don't bother with varicode bits */ - if(f->freedv_get_next_proto != NULL){ - (*f->freedv_get_next_proto)(f->proto_callback_state,(char*)proto_bits); - fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),proto_bits,vc_bits); - }else if(f->freedv_get_next_tx_char != NULL){ - fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,vc_bits); - }else { - fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL); + + /* If the API user hasn't set up message callbacks, don't bother with varicode bits */ + if(f->freedv_get_next_proto != NULL){ + (*f->freedv_get_next_proto)(f->proto_callback_state,(char*)proto_bits); + fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),proto_bits,vc_bits); + }else if(f->freedv_get_next_tx_char != NULL){ + fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,vc_bits); + }else { + fvhff_frame_bits(FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL); + } + /* Frame for 800XA */ + }else if(f->mode == FREEDV_MODE_800XA){ + fvhff_frame_bits(FREEDV_HF_FRAME_B,(uint8_t*)(f->tx_bits),(uint8_t*)(f->packed_codec_bits),NULL,NULL); } /* Allocate floating point buffer for FSK mod */ tx_float = alloca(sizeof(float)*f->n_nom_modem_samples); /* do 4fsk mod */ - if(f->mode == FREEDV_MODE_2400A){ + if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_800XA){ fsk_mod(f->fsk,tx_float,(uint8_t*)(f->tx_bits)); /* Convert float samps to short */ for(i=0; in_nom_modem_samples; i++){ @@ -406,7 +452,7 @@ static void freedv_tx_fsk_voice(struct freedv *f, short mod_out[]) { static void freedv_tx_fsk_data(struct freedv *f, short mod_out[]) { int i; float *tx_float; /* To hold on to modulated samps from fsk/fmfsk */ - + fvhff_frame_data_bits(f->deframer, FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits)); /* Allocate floating point buffer for FSK mod */ @@ -434,18 +480,27 @@ void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]) { assert(f != NULL); 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_2400A) || - (f->mode == FREEDV_MODE_2400B)); + uint8_t c2_buf[8]; + assert((f->mode == FREEDV_MODE_1600) || (f->mode == FREEDV_MODE_700) || + (f->mode == FREEDV_MODE_700B) || (f->mode == FREEDV_MODE_2400A) || + (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)); /* FSK and MEFSK/FMFSK modems work only on real samples. It's simpler to just * 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)){ + if((f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)){ #ifndef CORTEX_M4 - codec2_encode(f->codec2, f->packed_codec_bits, speech_in); + /* 800XA has two codec frames per modem frame */ + if((f->mode == FREEDV_MODE_800XA)){ + memset(f->packed_codec_bits,0,8); + codec2_encode(f->codec2, &f->packed_codec_bits[0], &speech_in[ 0]); + codec2_encode(f->codec2, &f->packed_codec_bits[4], &speech_in[320]); + uint8_t * cb = &f->packed_codec_bits[0]; + fprintf(stderr,"%02x%02x%02x%02x %02x%02x%02x%02x\n",cb[0],cb[1],cb[2],cb[3],cb[4],cb[5],cb[6],cb[7]); + }else{ + codec2_encode(f->codec2, f->packed_codec_bits, speech_in); + } freedv_tx_fsk_voice(f, mod_out); #endif }else{ @@ -784,7 +839,7 @@ int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) { float rx_float[f->n_max_modem_samples]; /* FSK RX happens in real floats, so convert to those and call their demod here */ - if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ){ + if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA) ){ for(i=0; imode == FREEDV_MODE_2400A){ + if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_800XA){ fsk_demod(f->fsk,(uint8_t*)f->tx_bits,demod_in); f->nin = fsk_nin(f->fsk); }else{ @@ -859,9 +914,9 @@ int freedv_floatrx(struct freedv *f, short speech_out[], float demod_in[]) { /* FSK RX happens in real floats, so demod for those goes here */ #ifndef CORTEX_M4 - if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ){ + if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)){ int valid; - int nout = freedv_floatrx_fsk_2400(f, demod_in, &valid); + int nout = freedv_floatrx_fsk(f, demod_in, &valid); if (valid == 0) for (i = 0; i < nout; i++) speech_out[i] = 0; @@ -1253,8 +1308,8 @@ int freedv_codecrx(struct freedv *f, unsigned char *packed_codec_bits, short dem freedv_comprx_fdmdv_700(f, rx_fdm, &valid); } - if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) ){ - freedv_floatrx_fsk_2400(f, rx_float, &valid); + if( (f->mode == FREEDV_MODE_2400A) || (f->mode == FREEDV_MODE_2400B) || (f->mode == FREEDV_MODE_800XA)){ + freedv_floatrx_fsk(f, rx_float, &valid); } #endif diff --git a/codec2-dev/src/freedv_api.h b/codec2-dev/src/freedv_api.h index 44bc66a7..5158517e 100644 --- a/codec2-dev/src/freedv_api.h +++ b/codec2-dev/src/freedv_api.h @@ -42,6 +42,7 @@ #define FREEDV_MODE_700B 2 #define FREEDV_MODE_2400A 3 #define FREEDV_MODE_2400B 4 +#define FREEDV_MODE_800XA 5 struct freedv; diff --git a/codec2-dev/src/freedv_rx.c b/codec2-dev/src/freedv_rx.c index 210ff4fa..df7207c0 100644 --- a/codec2-dev/src/freedv_rx.c +++ b/codec2-dev/src/freedv_rx.c @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) { float clock_offset; if (argc < 4) { - printf("usage: %s 1600|700|700B|2400A|2400B InputModemSpeechFile OutputSpeechRawFile [--test_frames]\n", argv[0]); + printf("usage: %s 1600|700|700B|2400A|2400B|800XA InputModemSpeechFile OutputSpeechRawFile [--test_frames]\n", argv[0]); printf("e.g %s 1600 hts1a_fdmdv.raw hts1a_out.raw txtLogFile\n", argv[0]); exit(1); } @@ -94,6 +94,8 @@ int main(int argc, char *argv[]) { mode = FREEDV_MODE_2400A; if (!strcmp(argv[1],"2400B")) mode = FREEDV_MODE_2400B; + if (!strcmp(argv[1],"800XA")) + mode = FREEDV_MODE_800XA; assert(mode != -1); if (strcmp(argv[2], "-") == 0) fin = stdin; diff --git a/codec2-dev/src/freedv_tx.c b/codec2-dev/src/freedv_tx.c index 5a6aeaaf..b96103da 100644 --- a/codec2-dev/src/freedv_tx.c +++ b/codec2-dev/src/freedv_tx.c @@ -67,7 +67,7 @@ int main(int argc, char *argv[]) { int n_nom_modem_samples; if (argc < 4) { - printf("usage: %s 1600|700|700B|2400A|2400B InputRawSpeechFile OutputModemRawFile [--testframes]\n", argv[0]); + printf("usage: %s 1600|700|700B|2400A|2400B|800XA InputRawSpeechFile OutputModemRawFile [--testframes]\n", argv[0]); printf("e.g %s 1600 hts1a.raw hts1a_fdmdv.raw\n", argv[0]); exit(1); } @@ -83,6 +83,8 @@ int main(int argc, char *argv[]) { mode = FREEDV_MODE_2400A; if (!strcmp(argv[1],"2400B")) mode = FREEDV_MODE_2400B; + if (!strcmp(argv[1],"800XA")) + mode = FREEDV_MODE_800XA; assert(mode != -1); if (strcmp(argv[2], "-") == 0) fin = stdin; diff --git a/codec2-dev/src/freedv_vhf_framing.c b/codec2-dev/src/freedv_vhf_framing.c index 14f54c1b..63757f6f 100644 --- a/codec2-dev/src/freedv_vhf_framing.c +++ b/codec2-dev/src/freedv_vhf_framing.c @@ -251,7 +251,12 @@ struct freedv_vhf_deframer * fvhff_create_deframer(uint8_t frame_type, int enabl deframer->frame_size = frame_size; deframer->uw_size = uw_size; deframer->on_inv_bits = 0; + deframer->sym_size = 1; + deframer->ber_est = 0; + deframer->total_uw_bits = 0; + deframer->total_uw_err = 0; + deframer->fdc = NULL; return deframer; @@ -555,14 +560,16 @@ int fvhff_deframe_bits(struct freedv_vhf_deframer * def,uint8_t codec2_out[],uin }else{ return 0; } + /* Skip N bits for multi-bit symbol modems */ for(i=0; i= frame_size) bitptr = 0; + if(bitptr >= frame_size) bitptr -= frame_size; def->bitptr = bitptr; /* Enter state machine */ if(state==ST_SYNC){ @@ -594,7 +601,9 @@ int fvhff_deframe_bits(struct freedv_vhf_deframer * def,uint8_t codec2_out[],uin fvhff_extract_frame(def,bits,codec2_out,proto_out,vc_out,pt); /* Update BER estimate */ - def->ber_est = (.99*def->ber_est) + (.01*((float)uw_diff)/((float)uw_size)); + def->ber_est = (.995*def->ber_est) + (.005*((float)uw_diff)/((float)uw_size)); + def->total_uw_bits += uw_size; + def->total_uw_err += uw_diff; } /* Not yet sunk */ }else{ @@ -608,7 +617,9 @@ int fvhff_deframe_bits(struct freedv_vhf_deframer * def,uint8_t codec2_out[],uin on_inv_bits = 1; fvhff_extract_frame(def,invbits,codec2_out,proto_out,vc_out,pt); /* Update BER estimate */ - def->ber_est = (.99*def->ber_est) + (.01*((float)uw_diff)/((float)uw_size)); + def->ber_est = (.995*def->ber_est) + (.005*((float)uw_diff)/((float)uw_size)); + def->total_uw_bits += uw_size; + def->total_uw_err += uw_diff; } } if(fvhff_match_uw(def,strbits,uw_first_tol, &uw_diff, &pt)){ @@ -619,7 +630,9 @@ int fvhff_deframe_bits(struct freedv_vhf_deframer * def,uint8_t codec2_out[],uin on_inv_bits = 0; fvhff_extract_frame(def,strbits,codec2_out,proto_out,vc_out,pt); /* Update BER estimate */ - def->ber_est = (.98*def->ber_est) + (.02*((float)uw_diff)/((float)uw_size)); + def->ber_est = (.995*def->ber_est) + (.005*((float)uw_diff)/((float)uw_size)); + def->total_uw_bits += uw_size; + def->total_uw_err += uw_diff; } } } diff --git a/codec2-dev/src/freedv_vhf_framing.h b/codec2-dev/src/freedv_vhf_framing.h index c41e801b..877d6bfe 100644 --- a/codec2-dev/src/freedv_vhf_framing.h +++ b/codec2-dev/src/freedv_vhf_framing.h @@ -53,9 +53,12 @@ struct freedv_vhf_deframer { int last_uw; /* How many bits since the last UW? */ int frame_size; /* How big is a frame? */ int uw_size; /* How big is the UW */ - int on_inv_bits; /* Are we using the inverted bits? */ + int on_inv_bits; /* Are we using the inverted bits? */ + int sym_size; /* How many bits in a modem symbol */ float ber_est; /* Bit error rate estimate */ + int total_uw_bits; /* Total RX-ed bits of UW */ + int total_uw_err; /* Total errors in UW bits */ struct freedv_data_channel *fdc; }; diff --git a/codec2-dev/src/fsk.c b/codec2-dev/src/fsk.c index a7053e98..dc2ea956 100644 --- a/codec2-dev/src/fsk.c +++ b/codec2-dev/src/fsk.c @@ -346,6 +346,37 @@ struct FSK * fsk_create(int Fs, int Rs,int M, int tx_f1, int tx_fs) return fsk; } + +void fsk_set_nsym(struct FSK *fsk,int nsyms){ + assert(nsyms>0); + int Ndft,i; + Ndft = 0; + + /* Set constant config parameters */ + fsk->N = fsk->Ts*nsyms; + fsk->Nsym = nsyms; + fsk->Nmem = fsk->N+(2*fsk->Ts); + fsk->nin = fsk->N; + fsk->Nbits = fsk->mode==2 ? fsk->Nsym : fsk->Nsym*2; + + /* Find smallest 2^N value that fits Fs for efficient FFT */ + /* It would probably be better to use KISS-FFt's routine here */ + for(i=1; i; i<<=1) + if((fsk->N)&i) + Ndft = i; + + fsk->Ndft = Ndft; + + free(fsk->fft_cfg); + free(fsk->fft_est); + + fsk->fft_cfg = kiss_fftr_alloc(Ndft,0,NULL,NULL); + fsk->fft_est = (float*)malloc(sizeof(float)*fsk->Ndft/2); + + for(i=0;ifft_est[i] = 0; + +} + uint32_t fsk_nin(struct FSK *fsk){ return (uint32_t)fsk->nin; } diff --git a/codec2-dev/src/fsk.h b/codec2-dev/src/fsk.h index 29563dca..a0a75ba9 100644 --- a/codec2-dev/src/fsk.h +++ b/codec2-dev/src/fsk.h @@ -109,6 +109,11 @@ struct FSK * fsk_create(int Fs, int Rs, int M, int tx_f1, int tx_fs); */ struct FSK * fsk_create_hbr(int Fs, int Rs, int P, int M, int tx_f1, int tx_fs); +/* + * Set a new number of symbols per processing frame + */ +void fsk_set_nsym(struct FSK *fsk,int nsym); + /* * Set a MODEM_STATS struct in which to deposit demod statistics */ diff --git a/codec2-dev/unittest/tdeframer.c b/codec2-dev/unittest/tdeframer.c index b1fe7597..03e8bb14 100644 --- a/codec2-dev/unittest/tdeframer.c +++ b/codec2-dev/unittest/tdeframer.c @@ -29,10 +29,10 @@ #define TESTBER 0.01 /* Frame count */ -#define FRCNT 15000 +#define FRCNT 1500 /* Random bits leading frame */ -#define LRCNT 55 +#define LRCNT 44 #include #include @@ -135,6 +135,7 @@ int main(int argc,char *argv[]){ printf("Extracted %d frames of %d, %f hit rate\n",total_extract,FRCNT,((float)total_extract/(float)FRCNT)); printf("Bit error rate %f measured from golay code\n",measured_ber); printf("Bit error rate %f measured by deframer\n",fvd->ber_est); + printf("Bit error rate %f measured by deframer\n",(float)fvd->total_uw_err/(float)fvd->total_uw_bits); /* Check test condition */ if(first_extract