Skip to content

Latest commit

 

History

History
175 lines (143 loc) · 8.61 KB

README_fsk.md

File metadata and controls

175 lines (143 loc) · 8.61 KB

README_fsk

A 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.

Here is a typical Bit Error Rate (BER) versus Eb/No curve:

BER versus Eb/No curve

Note how close the theory line is to measured performance.

This modem can demodulate FSK signals that sound like this sample; and is used to receive images from the edge of space:

HAB image from edge of space

Credits

The 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.

Quickstart

  1. Build codec2:

    $ cd codec2 && mkdir build_linux && cmake .. && make
    
  2. Generate 1000 test bits, modulate them using 2FSK using a 8000 Hz sample rate, 100 bits/s, play on your sound card:

    $ cd ~/codec2/build_linux/src
    $ ./fsk_get_test_bits - 1000 | ./fsk_mod 2 8000 100 1200 1200 - - | aplay -f S16_LE
    

    The low tone frequency is 1200Hz, and the upper tone 1200 + 1200 = 2400Hz.

  3. Add the demodulator and measure the bit error rate over 10,000 bits of 100 bit/s 2FSK:

    $ ./fsk_get_test_bits - 10000 | ./fsk_mod 2 8000 100 1200 100 - - | ./fsk_demod 2 8000 100 - - | ./fsk_put_test_bits -
    <snip>
    [0099] BER 0.000, bits tested   9900, bit errors    0
    PASS
    

    We get a Bit Error Rate (BER) of 0, as there is no channel noise to induce bit errors.

  4. Same thing but this time with 4FSK, and less verbose output:

    $ ./fsk_get_test_bits - 10000 | ./fsk_mod 4 8000 100 1200 100 - - | ./fsk_demod 4 8000 100 - - | ./fsk_put_test_bits -q -
    <snip>
    [0099] BER 0.000, bits tested   9900, bit errors    0
    PASS
    
  5. Lets add some channel noise:

    $ ./fsk_get_test_bits - 10000 | ./fsk_mod 2 8000 100 1200 100 - - | ./ch - - --No -26 | ./fsk_demod 2 8000 100 - - | ./fsk_put_test_bits -b 0.015 -
    <snip>
    SNR3k(dB): -5.76 C/No: 29.0 PAPR:  3.0 
    [0099] BER 0.010, bits tested   9900, bit errors  103
    PASS
    

    The ch utility takes the FSK modulator signal, and adds calibrated noise to it (the --No -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).

    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.

  6. You can visualise the C modem operation with a companion python script, for example:

    $ ./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
    $ python ../../octave/plot_fsk_demod_stats.py stats.txt
    
  7. Send some digital voice using FSK at 800 bits/s, and try the two 2400 bits/s FSK modes:

    $ ./freedv_tx 800XA ../../raw/ve9qrp.raw - | ./freedv_rx 800XA - - -vv | aplay -f S16_LE
    $ ./freedv_tx 2400A ../../raw/ve9qrp.raw - | ./freedv_rx 2400A - - -vv | aplay -f S16_LE
    $ ./freedv_tx 2400B ../../raw/ve9qrp.raw - | ./freedv_rx 2400B - - -vv | aplay -f S16_LE
    
  8. LDPC encoded 4FSK, with framing:

    $ cd ~/codec2/build_linux/src
    $ ./ldpc_enc /dev/zero - --code H_256_512_4 --testframes 200 |
      ./framer - - 512 5186 | ./fsk_mod 4 8000 100 1000 100 - - |
      ./ch - - --No -24 |
      ./fsk_demod -s 4 8000 100 - - |
      ./deframer - - 512 5186  |
      ./ldpc_dec - /dev/null --code H_256_512_4 --testframes
    <snip>
    SNR3k(dB): -7.74 C/No: 27.0 PAPR:  3.0 
    Raw   Tbits: 100352 Terr:   6701 BER: 0.067
    Coded Tbits:  50176 Terr:    139 BER: 0.003
          Tpkts:    196 Tper:      4 PER: 0.020
    

    In this example the unique word is the 16 bit sequence 5186. See also several ctests using these application. Other codes are also available:

    $ ./ldpc_enc --listcodes
    
    H2064_516_sparse     rate 0.80 (2580,2064) 
    HRA_112_112          rate 0.50 (224,112) 
    HRAb_396_504         rate 0.79 (504,396) 
    H_256_768            rate 0.33 (768,256) 
    H_256_512_4          rate 0.50 (512,256) 
    HRAa_1536_512        rate 0.75 (2048,1536) 
    H_128_256_5          rate 0.50 (256,128)
    

    If you change the code you also need to change the frameSizeBits argument in framer/deframer (512 in the example above).

  9. The FSK/LDPC/framer steps above have been combined in a FreeDV API mode. See "FSK LDPC Raw Data Mode" in README_data.md.

  10. FSK modem C files in codec2/src:

    File Description
    fsk.c/fsk.h core FSK modem library
    fsk_mod.c command line modulator
    fsk_demod.c command line demodulator
    fsk_get_test_bits.c source of test bits
    fsk_put_test_bits.c test bit sync, counts bit errors and packet errors
    fsk_mod_ext_vco.c modulator that uses an external FSK oscillator
    framer.c adds a unique word to a frame of bits to implement frame sync for LDPC codewords
    deframer.c locates and strips a unique word to implement frame sync for LDPC codewords
    tollr.c converts bits to LLRs for testing LDPC framing
  11. GNU Octave files in codec2/octave:

    File Description
    fsk_lib.m Core FSK modem library
    fsk_lib_demo.m A demonstration of fsk_lib, runs a single point BER test
    fsk_demod_file.m Demodulates FSK signals from a file, useful for debugging FSK waveforms
    tfsk.m automated test that compares the C and Octave versions of the modem
    fsk_lib_ldpc_demo.m CML library LLR routines and LDPC codes with fsk_lib.m

    You can run many of them from the Octave command line:

    $ octave --no-gui
    octave:1> fsk_lib_demo
    
  12. A suite of automated ctests that exercise the C and Octave code:

    $ cd ~/codec2/build_linux
    $ ctest -R test_fsk
    1/9 Test #39: test_fsk_lib ......................   Passed    3.37 sec
    3/9 Test #41: test_fsk_modem_octave_port ........   Passed    4.17 sec
    4/9 Test #42: test_fsk_modem_mod_demod ..........   Passed    0.06 sec
    5/9 Test #43: test_fsk_2fsk_ber .................   Passed    0.24 sec
    6/9 Test #44: test_fsk_4fsk_ber .................   Passed    0.12 sec
    7/9 Test #45: test_fsk_4fsk_ber_negative_freq ...   Passed    0.07 sec
    8/9 Test #46: test_fsk_4fsk_lockdown ............   Passed    2.84 sec
    9/9 Test #47: test_fsk_vhf_framer ...............   Passed    0.06 sec
    

    These are written in codec2/CmakeLists.txt, inspect them to find out how we test the modem.

  13. fsk_demod_file.m is useful for peering inside the modem, for example when debugging.

    $ cd ~/codec2/build_linux/src
    $ ./fsk_get_test_bits - 1000 | ./fsk_mod 2 8000 100 1000 1000 - ../../octave/fsk.s16
    $ octave --no-gui
    octave:1> fsk_demod_file("fsk.s16",format="s16",8000,100,2)
    

Further Reading

Here are some links to projects and blog posts that use this modem:

  1. Horus Binary High Altitude Balloon (HAB) telemetry protocol, 3 second updates, works at 7dB lower SNR that RTTY.
  2. Testing HAB Telemetry, Horus binary waveform
  3. A really useful reference on a variety of modulation techniques from Atlanta DSP. I keep this handy when experimenting with modems.
  4. The RTTY modem project that kicked off the FSK modem work.
  5. Wenet - high speed SSTV images from balloons at the edge of space
  6. Wenet High speed SSTV images
  7. FreeDV 2400A and 2400B, digital speech for VHF/UHF radios.
  8. HF FSK with Rpitx, a zero hardware FSK transmitter using a Pi
  9. Eb/No and SNR worked Example
  10. FSK LLR LDPC Code Experiments
  11. FreeDV API FSK LDPC Raw Data Mode