Built as part of codec2-dev, see README for build instructions.
-1. Using 10 test frames as a source of bits, generate 2FSK using a
- 8000 Hz sample rate, at 100 symbols/s (== 100 bit/s for 2FSK), with
- two frequencies of 1200 and 2400 Hz, and stream via stdout to
- "play" out speaker:
+1. Using 1000 test bits, generate 2FSK using a 8000 Hz sample rate, at
+ 100 symbols/s (== 100 bit/s for 2FSK), with two frequencies of 1200
+ and 2400 Hz, and stream via stdout to "play" out speaker:
$ cd build_linux/src
- $ ./fsk_get_test_bits - 10 | ./fsk_mod 2 8000 100 1200 1200 - - | play -t raw -r 8000 -s -2 -
-
- Each test frame has 400 bits, and the "fsk_get_test_bits"
- generates 1+10=11 test frames in the example above - an extra
- first frame is always generated to give the demod time to sync.
+ $ ./fsk_get_test_bits - 1000 | ./fsk_mod 2 8000 100 1200 1200 - - | play -t raw -r 8000 -s -2 -
The low tone frequency is 1200Hz, and the upper tone 1200 + 1200 = 2400Hz.
-2. Measure the bit error rate of 100 frames of 100 bit/s 2FSK:
+2. Measure the bit error rate over 10,000 bits of 100 bit/s 2FSK:
- $ ./fsk_get_test_bits - 100 | ./fsk_mod 2 8000 100 1200 100 - - | ./fsk_demod -l 2 8000 100 - - | ./fsk_put_test_bits -
- FSK BER 0.000000, bits tested 39899, bit errors 0
+ $ ./fsk_get_test_bits - 10000 | ./fsk_mod 2 8000 100 1200 100 - - | ./fsk_demod -l 2 8000 100 - - | ./fsk_put_test_bits -
+ FSK BER 0.000000, bits tested 9800, bit errors 0
In this example the two tones are at 1200 and 1200+100 = 1300Hz.
A shift of 100Hz is the minimum possible for an incoherent FSK
is well suited to applications that can tolerate long latency, such
as balloon telemetry.
-3. Measure the bit error rate of 100 frames at 1200 bits/s, using a
+ The demod and test frame logic takes a few frames to sync up, so
+ although we sent 10,000 bits, only 9800 are received. However
+ there were no errors in those received bits.
+
+3. Measure the bit error rate of 5000 bits at 1200 bits/s, using a
sample rate of 9600 Hz:
- $ ./fsk_get_test_bits - 100 | ./fsk_mod 2 9600 1200 1200 1200 - - | ./fsk_demod -p 8 2 9600 1200 - - | ./fsk_put_test_bits -
- FSK BER 0.000000, bits tested 39967, bit errors 0
+ $ ./fsk_get_test_bits - 5000 | ./fsk_mod 2 9600 1200 1200 1200 - - | ./fsk_demod -p 8 2 9600 1200 - - | ./fsk_put_test_bits -
+ FSK BER 0.000000, bits tested 4900, bit errors 0
In this example, the -l and --lbr options are left out setting the modem
up in "high speed" mode. In this mode, the demodulator operates on blocks of
P should be left alone unless CPU and memory usage needs to be lowered
for the application.
+ (TODO, make this easier to understand, perhaps with figure)
+
4. (TODO High bit rate example like 115k project Horus)
5. Automatically check C implementation against Octave using a variety of test conditions and
FILE........: fsk_get_test_bits.c
AUTHOR......: Brady O'Brien
- DATE CREATED: Januar 2016
+ DATE CREATED: January 2016
Generates a pseudorandom sequence of bits for testing of fsk_mod and fsk_demod
#include <stdio.h>
#include <string.h>
#include "fsk.h"
-#include "codec2_fdmdv.h"
-#define FSK_FRAME_SIZE 400
-#define INIT_SEQ {0,1,1,0,1,0,0,1,1,1,1,0,1,1,0,0,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,1}
-
-uint8_t init[] = INIT_SEQ;
+#define TEST_FRAME_SIZE 100 /* arbitrary chice, repeats after this
+ many bits, sets frame size for rx
+ processing */
int main(int argc,char *argv[]){
- int bitcnt;
- int i,j;
+ int bitcnt, framecnt;
+ int i;
FILE *fout;
uint8_t *bitbuf;
-
if(argc != 3){
- fprintf(stderr,"usage: %s OutputBitsOnePerByte FrameCount\n",argv[0]);
+ fprintf(stderr,"usage: %s OutputBitsOnePerByte numBits\n",argv[0]);
exit(1);
}
/* Extract parameters */
bitcnt = atoi(argv[2]);
-
- if(strcmp(argv[1],"-")==0){
- fout = stdout;
- }else{
- fout = fopen(argv[1],"w");
- }
+ framecnt = bitcnt/TEST_FRAME_SIZE;
+ if (framecnt == 0) {
+ fprintf(stderr,"Need a minimum of %d bits\n", TEST_FRAME_SIZE);
+ exit(1);
+ }
+
+ if(strcmp(argv[1],"-")==0){
+ fout = stdout;
+ }else{
+ fout = fopen(argv[1],"w");
+ }
if(fout==NULL){
- fprintf(stderr,"Couldn't open test vector files\n");
+ fprintf(stderr,"Couldn't open output file: %s\n", argv[1]);
goto cleanup;
}
/* allocate buffers for processing */
- bitbuf = (uint8_t*)alloca(sizeof(uint8_t)*FSK_FRAME_SIZE);
+ bitbuf = (uint8_t*)alloca(sizeof(uint8_t)*TEST_FRAME_SIZE);
- /* Write out sync frame and sequence */
- for(i=0; i<FSK_FRAME_SIZE; i++){
+ /* Generate buffer of test frame bits from known seed */
+ srand(158324);
+ for(i=0; i<TEST_FRAME_SIZE; i++){
bitbuf[i] = rand()&0x1;
}
- for(i=0;i<sizeof(init);i++){
- bitbuf[FSK_FRAME_SIZE-sizeof(init)+i]=init[i];
- }
- fwrite(bitbuf,sizeof(uint8_t),FSK_FRAME_SIZE,fout);
-
-
- /* Seed the RNG with some constant */
+
+ /* Output test frames */
srand(158324);
- for(i=0; i<bitcnt; i++){
- for(j=0; j<FSK_FRAME_SIZE; j++){
- bitbuf[j] = rand()&0x1;
- }
- fwrite(bitbuf,sizeof(uint8_t),FSK_FRAME_SIZE,fout);
+ for(i=0; i<framecnt; i++){
+ fwrite(bitbuf,sizeof(uint8_t),TEST_FRAME_SIZE,fout);
if(fout == stdout){
fflush(fout);
}
}
- cleanup:
+ cleanup:
fclose(fout);
return 0;
FILE........: fsk_get_test_bits.c
AUTHOR......: Brady O'Brien
- DATE CREATED: Januar 2016
+ DATE CREATED: January 2016
- Generates a pseudorandom sequence of bits for testing of fsk_mod and fsk_demod
+ Generates a pseudorandom sequence of bits for testing of fsk_mod and
+ fsk_demod.
\*---------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include "fsk.h"
-#include "codec2_fdmdv.h"
-
-#define FSK_FRAME_SIZE 100
-#define INIT_SEQ {0,1,1,0,1,0,0,1,1,1,1,0,1,1,0,0,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,1}
-
-uint8_t init[] = INIT_SEQ;
-uint8_t finit[sizeof(init)];
-
-int find_init(uint8_t next){
- memmove(&finit[0],&finit[1],sizeof(init)-1);
- finit[sizeof(init)-1] = next;
- int i, err = 0;
- for(i = 0;i<sizeof(init); i++){
- if(init[i]!=finit[i]) err++;
- }
- return err<=3;
-}
+
+#define TEST_FRAME_SIZE 100 /* must match fsk_get_test_bits.c */
int main(int argc,char *argv[]){
- int bitcnt,bitcorr;
+ int bitcnt,biterr,i,errs;
FILE *fin;
- uint8_t bitbuf,cntbit;;
-
- /* Seed the RNG with some constant */
- srand(158324);
+ uint8_t *bitbuf_tx, *bitbuf_rx, abit;
if(argc != 2){
fprintf(stderr,"usage: %s InputBitsOnePerByte \n",argv[0]);
exit(1);
}
-
- if(strcmp(argv[1],"-")==0 || argc<2){
- fin = stdin;
- }else{
- fin = fopen(argv[1],"r");
- }
+ if(strcmp(argv[1],"-")==0 || argc<2){
+ fin = stdin;
+ }else{
+ fin = fopen(argv[1],"r");
+ }
if(fin==NULL){
- fprintf(stderr,"Couldn't open test vector files\n");
+ fprintf(stderr,"Couldn't open input file: %s\n", argv[1]);
goto cleanup;
}
+
+ /* allocate buffers for processing */
+ bitbuf_tx = (uint8_t*)alloca(sizeof(uint8_t)*TEST_FRAME_SIZE);
+ bitbuf_rx = (uint8_t*)alloca(sizeof(uint8_t)*TEST_FRAME_SIZE);
+
+ /* Generate known tx frame from known seed */
+ srand(158324);
+ for(i=0; i<TEST_FRAME_SIZE; i++){
+ bitbuf_tx[i] = rand()&0x1;
+ bitbuf_rx[i] = 0;
+ }
+
bitcnt = 0;
- bitcorr = 0;
+ biterr = 0;
- /* Find frame start word */
- do{
- fread(&bitbuf,sizeof(uint8_t),1,fin);
- }while(!find_init(bitbuf));
-
-
- while(fread(&bitbuf,sizeof(uint8_t),1,fin)>0){
- cntbit = rand()&0x1;
- if( (cntbit>0)==(bitbuf>0))
- bitcorr++;
- bitcnt++;
- if(fin == stdin)
- fflush(fin);
- }
- fprintf(stderr,"FSK BER %f, bits tested %d, bit errors %d\n",1-((float)bitcorr/(float)bitcnt),bitcnt,bitcnt-bitcorr);
+ while(fread(&abit,sizeof(uint8_t),1,fin)>0){
+
+ /* update silding window of input bits */
+
+ for(i=0; i<TEST_FRAME_SIZE-1; i++) {
+ bitbuf_rx[i] = bitbuf_rx[i+1];
+ }
+ bitbuf_rx[TEST_FRAME_SIZE-1] = abit;
+
+ /* compare to know tx frame. If they are time aligned, there
+ will be a fairly low bit error rate */
+
+ errs = 0;
+ for(i=0; i<TEST_FRAME_SIZE; i++) {
+ if (bitbuf_rx[i] != bitbuf_tx[i]) {
+ errs++;
+ }
+ }
+ if (errs < 0.1*TEST_FRAME_SIZE) {
+ /* OK, we have a valid test frame sync, so lets count errors */
+ bitcnt += TEST_FRAME_SIZE;
+ biterr += errs;
+ }
+ }
+
+ fprintf(stderr,"FSK BER %f, bits tested %d, bit errors %d\n",
+ ((float)biterr/(float)bitcnt),bitcnt,biterr);
- cleanup:
+ cleanup:
fclose(fin);
}