A key use for Codec 2 is digital voice over HF and VHF radio. This requires a HF modem optimised for digital speech, in particular fast sync, no multi-second training sequences, the ability to recover quickly after a fade, and no automatic re-transmit of “bad” packets. FDMDV was a working system for HF Digital Voice from a few years ago, so seemed like a good starting point.
FDMDV stands for Frequency Division Multiplexed Digital Voice. A FDM modem is a basically a bunch of slow modems running in parallel. For example FDMDV has 14 carriers spaced 75 Hz apart, each running at 50 symbols/second. Due to multipath problems on HF this approach works better than one carrier running at 14×50 = 700 symbols/second. On each symbol is encoded two bits using differential QPSK, so the bit rate is 1400 bit/s.
The source code for the original FDMDV modem is not available, so I have written an open source implementation based on the FDMDV specification. I have also written this page, the README_fdmdv.txt, and various blog posts to explain how the modem works as a resource for others.
Actually there are two versions of the modem, one in GNU Octave, and one in C. Octave is useful for rapid algorithm development, C for real time implementation. The two versions can inter-operate, and automated tests have been developed to make sure the two implementations have identical performance.
Below is a spectrogram (waterfall plot) of the modem signal over a real 925 mile HF path, this blog post has more information:
Get the Source Code
The FDMDV modem is part of Codec 2 SVN:
$ svn co https://freetel.svn.sourceforge.net/svnroot/freetel/codec2-dev
README_fdmdv.txt describes the various modem files and how to use them.
$ cd codec2-dev
$ ./configure && make
$ cd src
1. Generate some test bits and modulate them (using files):
$ ./fdmdv_get_test_bits test.c2 1400
$ ./fdmdv_mod test.c2 test.raw
$ play -r 8000 -s -2 test.raw
2. Two seconds of test frame data modulated and sent out of sound device (using pipes):
$ ./fdmdv_get_test_bits - 2800 | ./fdmdv_mod - - | play -t raw -r 8000 -s -2 -
3. Send 14000 modulated bits (10 seconds) to the demod and count errors:
$ ./fdmdv_get_test_bits - 14000 | ./fdmdv_mod - - | ./fdmdv_demod - - demod_dump.txt | ./fdmdv_put_test_bits -
4. Encode a voice file with Codec 2 and send through mod & demod, play decoded audio:
$ ./c2enc 1400 ../raw/hts1a.raw - | ./fdmdv_mod - - | ./fdmdv_demod - - | ./c2dec 1400 - - | play -t raw -r 8000 -s -2 -
As of May 2012 the status is Alpha. The modem has been carefully tested against various channel simulations and samples played over real world HF channels. It hasn’t been used for real world DV work yet. It has been developed and tested on Ubuntu Linux. The source compiles on Windows but hasn’t been tested.
If you would like to contribute there is a TODO list at the end of README_fdmdv.txt.
Use the Codec 2 mailing list for support, questions, and contributions.
How it works
This section briefly describes how the modem works, in particular it has some figures that couldn’t be included in the ASCII README_fdmdv.txt file. The commented source code explains more detail about the modem algorithms. Using Octave it is easy to plot the states of various algorithms to get a picture of how they work.
Here is a block diagram of the modulator:
The modulator takes a sequence of bits at 1400 bit/s and maps them to 14 parallel streams of DQPSK symbols at 50 symbols/s. The parallel arrows on the figures indicate where there are parallel streams of symbols. In addition to the data symbols a single DBPSK pilot at 50 symbol/s sends a constant …0101010… sequence to provide frame syncronisation and fast frequency offset estimation at the demodulator. Here is the constellation or “scatter diagram” of the transmitted symbols:
The four points in the centre represent the 4 possible phases of the DQPSK symbols. All 14 carriers are plotted on top of each other. With 4 possible phases we can transmit 2 bits per symbol. The two widely spaced diagonal points are the DBPSK pilot symbols. The distance from the centre shows the power of each symbol. We have intentionally assigned higher power to the pilot to make sure the import sync information carried by the pilot gets through under adverse channel conditions. Higher power also prevent confusion with adjacent DQPSK carriers that may (for a short time at least) carry similar 01010 data to the pilot.
The symbols are then transmit filtered using a root raised cosine filter. This filter limits the bandwidth of the signal to a little more than the symbol rate, and increases the sample rate from Rs (the symbol rate, 50 Hz) to M=160 times the symbol rate or 8000 Hz. Each filtered symbol steam is then upconverted to separate carrier frequencies which are summed together into a single FDMDV signal. The centre frequency of 1200 Hz is roughly the centre of the audio passband of a typical SSB tranceiver. The carriers are separated by 75 Hz, and extend from about 600 to 1800 Hz. The DBPSK pilot carrier is inserted right in the centre at 1200 Hz, and it’s power is a few dB higher in comparison with the other modem carriers.
Here is a nice waterfall plot of the FDMDV signal from Peter M6DGI (click for larger image). The …01010… pilot data produces the two tone BPSK pilot in the centre, with the 14 data carriers either side.
Here is a block diagram of the demodulator:
The input to the demodulator is the FDMDV signal from the SSB receiver, sampled at 8 kHz. This signal will have several impairments such as noise, frequency and phase offsets, timing offset, and sample rate differences between the modulator and demodulator.
The first step is frequency offset estimation and correction. The coarse frequency offset estimator looks for the received pilot signal in a window +/- 200 Hz from the nominal centre frequency. The modem signal is down converted to 14 parallel baseband signals using the estimated frequency offset and known frequency of each carrier.
Each signal is then Rx filtered and the sample rate reduced to P = 4 times the symbol rate or 200 Hz. Using a P = 4 sampling rate reduces the computational complexity of the filtering and timing estimation. The Rx filtering uses a root raised cosine filter identical to the modulator that removes most of the channel noise and interference from adjacent symbols.
To recover the transmitted symbols we need to sample each parallel signal at exactly the right time. The timing estimator determines the optimum timing instant from the received signals. Given a timing estimate each parallel signal is then re-sampled to produce 14 parallel received DQPSK symbols at the symbol rate Rs = 50 Hz. The demapper then converts the DQPSK symbols back to a single stream of bits. The demapper also estimates the fine frequency offset from the received DBPSK pilot.
Here is a scatter diagram showing the received symbols when the modem signal passed through a noisey channel with a SNR of 4dB:
A state machine determines if the coarse or fine frequency estimate is used. The coarse estimator can quickly estimate the frequency offset allowing fast syncronisation but occasionally makes large errors. So after we have acquired the BPSK pilot sequence we switch to the fine frequency estimator which is sufficient to track small changes in frequency (up to a few Hz per second).
The plot below shows the timing and frequency estimators in action, the x axis is time in seconds:
After about 100 ms the coarse frequency estimator acquires the correct frequency offset (0 Hz in this case). The timing estimator acquires the timing estimate at about 250 ms. At 300ms the state machine switches from the coarse to fine frequency estimators.
The top plot below shows the received pilot bits. Just after 200 ms the correct 010101 sequence starts.
The middle plot shows bit errors measured from test frames of data (zero in this case), and the bottom plot indicates if we have found and synced up to the test data frames. This test data is convenient for testing the modem but would be replaced with Codec 2 data in a real world Digital Voice application.
The blog post Testing a FDMDV Modem shows how the modem performs over a real world HF channel.
Thanks for help and advice from Mel Whitten K0PFX, Peter Martinez G3PLX, Rick Muething KN6KB, and Bill Cowley VK5DSP.