1# README_fsk 2 3A FSK modem with a non-coherent demodulator. Performance is within a fraction of a dB of ideal. The demodulator automagically estimates the tone frequencies and tracks frequency drift. 4 5Here is a typical Bit Error Rate (BER) versus Eb/No curve: 6 7![BER versus Eb/No curve](doc/fsk_modem_ber_8000_100.png) 8 9Note how close the theory line is to measured performance. 10 11This modem can demodulate FSK signals that sound like [this sample](doc/lockdown_3s.wav); and is used to receive images from the [edge of space](https://github.com/projecthorus/wenet): 12 13![HAB image from edge of space](doc/wenet_image.jpg) 14 15## Credits 16 17The Octave version of the modem was developed by David Rowe. Brady O'Brien ported the modem to C, and wrote the C/Octave tests. The modem is being maintained by David Rowe. Mark Jessop has helped improve the modem operation by testing against various balloon telemtry waveforms. Bill Cowley has developed the Log Likelihood Ratio (LLR) algorithms for 4FSK. 18 19## Quickstart 20 211. Build codec2: 22 ``` 23 $ cd codec2 && mkdir build_linux && cmake .. && make 24 ``` 25 261. Generate 1000 test bits, modulate them using 2FSK using a 8000 Hz sample rate, 100 bits/s, play on your sound card: 27 ``` 28 $ cd ~/codec2/build_linux/src 29 $ ./fsk_get_test_bits - 1000 | ./fsk_mod 2 8000 100 1200 1200 - - | aplay -f S16_LE 30 ``` 31 The low tone frequency is 1200Hz, and the upper tone 1200 + 1200 = 2400Hz. 32 331. Add the demodulator and measure the bit error rate over 10,000 bits of 100 bit/s 2FSK: 34 ``` 35 $ ./fsk_get_test_bits - 10000 | ./fsk_mod 2 8000 100 1200 100 - - | ./fsk_demod 2 8000 100 - - | ./fsk_put_test_bits - 36 <snip> 37 [0099] BER 0.000, bits tested 9900, bit errors 0 38 PASS 39 ``` 40 We get a Bit Error Rate (BER) of 0, as there is no channel noise to induce bit errors. 41 421. Same thing but this time with 4FSK, and less verbose output: 43 ``` 44 $ ./fsk_get_test_bits - 10000 | ./fsk_mod 4 8000 100 1200 100 - - | ./fsk_demod 4 8000 100 - - | ./fsk_put_test_bits -q - 45 <snip> 46 [0099] BER 0.000, bits tested 9900, bit errors 0 47 PASS 48 ``` 49 501. Lets add some channel noise: 51 ``` 52 $ ./fsk_get_test_bits - 10000 | ./fsk_mod 2 8000 100 1200 100 - - | ./cohpsk_ch - - -26 --Fs 8000 | ./fsk_demod 2 8000 100 - - | ./fsk_put_test_bits -b 0.015 - 53 <snip> 54 SNR3k(dB): -5.76 C/No: 29.0 PAPR: 3.0 55 [0099] BER 0.010, bits tested 9900, bit errors 103 56 PASS 57 ``` 58 The cohpsk_ch utility takes the FSK modulator signal, and adds calibrated noise to it (the -26 value specifies the noise). Try changing the noise level, and note how the Bit Error Rate (BER) changes. The BER is 0.01, which is right on theory for this sort of FSK demodulator at this SNR (2FSK non-coherent demodulator Eb/No=9dB). 59 60 The SNR is calculated using the signal power divided by the noise power in 3000 Hz. The C/No value is the same thing, but uses a noise bandwidth of 1 Hz. There is less noise power when you look at just 1Hz, so C/No is higher. Peak to Average Power ratio (PAPR) is 3dB as a FSK signal is just a single sine wave, and a sine wave peak is 3dB higher than it's average. 61 621. You can visualise the C modem operation with a companion python script, for example: 63 ``` 64 $ ./fsk_get_test_bits - 10000 | ./fsk_mod -p 10 4 8000 400 400 400 - - | ./fsk_demod -p 10 -t1 4 8000 400 - /dev/null 2>stats.txt 65 $ python ../../octave/plot_fsk_demod_stats.py stats.txt 66 ``` 67 681. Send some digital voice using FSK at 800 bits/s, and try the two 2400 bits/s FSK modes: 69 ``` 70 $ ./freedv_tx 800XA ../../raw/ve9qrp.raw - | ./freedv_rx 800XA - - -vv | aplay -f S16_LE 71 $ ./freedv_tx 2400A ../../raw/ve9qrp.raw - | ./freedv_rx 2400A - - -vv | aplay -f S16_LE 72 $ ./freedv_tx 2400B ../../raw/ve9qrp.raw - | ./freedv_rx 2400B - - -vv | aplay -f S16_LE 73 ``` 74 751. LDPC encoded 4FSK, with framing: 76 ``` 77 $ cd ~/codec2/build_linux/src 78 $ ./ldpc_enc /dev/zero - --code H_256_512_4 --testframes 200 | 79 ./framer - - 512 5186 | ./fsk_mod 4 8000 100 1000 100 - - | 80 ./cohpsk_ch - - -24 --Fs 8000 | 81 ./fsk_demod -s 4 8000 100 - - | 82 ./deframer - - 512 5186 | 83 ./ldpc_dec - /dev/null --code H_256_512_4 --testframes 84 <snip> 85 SNR3k(dB): -7.74 C/No: 27.0 PAPR: 3.0 86 Raw Tbits: 100352 Terr: 6701 BER: 0.067 87 Coded Tbits: 50176 Terr: 139 BER: 0.003 88 Tpkts: 196 Tper: 4 PER: 0.020 89 ``` 90 In this example the unique word is the 16 bit sequence `5186`. See also several ctests using these application. Other codes are also available: 91 ``` 92 $ ./ldpc_enc --listcodes 93 94 H2064_516_sparse rate 0.80 (2580,2064) 95 HRA_112_112 rate 0.50 (224,112) 96 HRAb_396_504 rate 0.79 (504,396) 97 H_256_768 rate 0.33 (768,256) 98 H_256_512_4 rate 0.50 (512,256) 99 HRAa_1536_512 rate 0.75 (2048,1536) 100 H_128_256_5 rate 0.50 (256,128) 101 ``` 102 If you change the code you also need to change the `frameSizeBits` argument in `framer/deframer` (`512` in the example above). 103 1041. The FSK/LDPC/framer steps above have been combined in a FreeDV API mode. See "FSK LDPC Raw Data Mode" in [README_data.md](README_data.md). 105 1061. FSK modem C files in ```codec2/src```: 107 108 | File | Description | 109 | --- | --- | 110 | fsk.c/fsk.h | core FSK modem library | 111 | fsk_mod.c | command line modulator | 112 | fsk_demod.c | command line demodulator | 113 | fsk_get_test_bits.c | source of test bits | 114 | fsk_put_test_bits.c | test bit sync, counts bit errors and packet errors | 115 | fsk_mod_ext_vco.c | modulator that uses an external FSK oscillator | 116 | framer.c | adds a unique word to a frame of bits to implement frame sync for LDPC codewords | 117 | deframer.c | locates and strips a unique word to implement frame sync for LDPC codewords | 118 | tollr.c | converts bits to LLRs for testing LDPC framing | 119 1201. GNU Octave files in ```codec2/octave```: 121 122 | File | Description | 123 | --- | --- | 124 | fsk_lib.m | Core FSK modem library | 125 | fsk_lib_demo.m | A demonstration of fsk_lib, runs a single point BER test | 126 | fsk_demod_file.m | Demodulates FSK signals from a file, useful for debugging FSK waveforms | 127 | fsk_lock_down.m | simulations to support the "lock down" low SNR waveform | 128 | tfsk.m | automated test that compares the C and Octave versions of the modem | 129 | fsk_cml.m | Symbol rate experiments with FSK modem LLR estimation and LDPC | 130 | fsk_cml_sam.m | Sample rate experiments with FSK modem LLR estimation and LDPC | 131 | fsk_llr_plot.m | Plots curves from fsk_cml.m & fsk_cml_sam.m | 132 | fsk_lib_ldpc_demo.m | CML library LLR routines and LDPC codes with fsk_lib.m | 133 134 You can run many of them from the Octave command line: 135 ``` 136 $ octave --no-gui 137 octave:1> fsk_lib_demo 138 ``` 139 1401. A suite of automated ctests that exercise the C and Octave code: 141 ``` 142 $ cd ~/codec2/build_linux 143 $ ctest -R test_fsk 144 1/9 Test #39: test_fsk_lib ...................... Passed 3.37 sec 145 3/9 Test #41: test_fsk_modem_octave_port ........ Passed 4.17 sec 146 4/9 Test #42: test_fsk_modem_mod_demod .......... Passed 0.06 sec 147 5/9 Test #43: test_fsk_2fsk_ber ................. Passed 0.24 sec 148 6/9 Test #44: test_fsk_4fsk_ber ................. Passed 0.12 sec 149 7/9 Test #45: test_fsk_4fsk_ber_negative_freq ... Passed 0.07 sec 150 8/9 Test #46: test_fsk_4fsk_lockdown ............ Passed 2.84 sec 151 9/9 Test #47: test_fsk_vhf_framer ............... Passed 0.06 sec 152 ``` 153 These are written in ```codec2/CmakeLists.txt```, inspect them to find out how we test the modem. 154 1551. ```fsk_demod_file.m``` is useful for peering inside the modem, for example when debugging. 156 ``` 157 $ cd ~/codec2/build_linux/src 158 $ ./fsk_get_test_bits - 1000 | ./fsk_mod 2 8000 100 1000 1000 - ../../octave/fsk.s16 159 $ octave --no-gui 160 octave:1> fsk_demod_file("fsk.s16",format="s16",8000,100,2) 161 ``` 162 163## Further Reading 164 165 Here are some links to projects and blog posts that use this modem: 166 167 1. [Horus Binary](https://github.com/projecthorus/horusbinary) High Altitude Balloon (HAB) telemetry protocol, 3 second updates, works at 7dB lower SNR that RTTY. 168 1. [Testing HAB Telemetry, Horus binary waveform](http://www.rowetel.com/?p=5906) 169 1. A really useful reference on a variety of modulation techniques from [Atlanta DSP](http://www.atlantarf.com/FSK_Modulation.php). I keep this handy when experimenting with modems. 170 1. The [RTTY modem project](http://www.rowetel.com/?p=4629) that kicked off the FSK modem work. 171 1. [Wenet](https://github.com/projecthorus/wenet) - high speed SSTV images from balloons at the edge of space 172 1. [Wenet High speed SSTV images](http://www.rowetel.com/?p=5344) 173 1. [FreeDV 2400A and 2400B](http://www.rowetel.com/?p=5219), digital speech for VHF/UHF radios. 174 1. [HF FSK with Rpitx](http://www.rowetel.com/?p=6317), a zero hardware FSK transmitter using a Pi 175 1. [Eb/No and SNR worked Example](http://www.rowetel.com/wordpress/?p=4621) 176 1. [FSK LLR LDPC Code Experiments](https://github.com/drowe67/codec2/pull/129) 177 1. [FreeDV API FSK LDPC Raw Data Mode](README_data.md) 178 179 180