In the previous post I argued that pushing bits through a HF channel involves much wailing and gnashing of teeth. Now we shall apply numbers and graphs to the problem, which is – in a nutshell – Engineering.
QPSK Modem Simulation
I have worked up a GNU Octave modem simulation called hf_modem_curves.m. This operates at 1 sample/symbol, i.e. the sample rate is the symbol rate. So we takes some random bits, map them to QPSK symbols, add noise, then turn the noisy symbols back into bits and count errors:
The simulation ignores a few real world details like timing and phase synchronisation, so is a best case model. That’s OK for now. QPSK uses symbols that each carry 2 bits of information, here is the symbol set or “constellation”:
Four different points, each representing a different 2 bit combination. For example the bits ’00’ would be the cross at 45 degrees, ’10’ at 135 degrees etc. The plot above shows all possible symbols, but we just send one at a time. However it’s useful to plot all of the received symbols like this, as an indication of received signal quality. If the channel is playing nice, we receive something like this:
Each cross is now a fuzzy dot, as noise has been added by the channel. No bit errors yet – a bit error happens when we get enough noise to move received symbols into another quadrant. This sort of channel is called Additive White Gaussian Noise (AWGN). Line of site UHF radio is a good example of a real world AWGN channel – all you have to worry about is additive noise.
With a fading or multipath channel like HF we end up with something like:
In a fading channel the received symbol amplitudes bounce up and down as the channel fades in and out. Sometimes the symbols dip down into the noise and we get lots of bit errors. Sometimes the signal is reinforced, and the symbol amplitude gets bigger.
The simulation used for the multipath or HF channel uses a two path model, with additive noise as per the AWGN simulation:
Graphs and Modem Performance
Turns out there are some surprisingly good models to help us work out the expected Bit Error Rate (BER) for a modem. By “model” I mean people have worked out the maths to describe the Bit Error Rate (BER) for a QPSK Modem. This graph shows us how to work out the BER for QPSK (and BPSK):
So the red line shows us the BER given Eb/No (E-B on N-naught), which is a normalised form of Signal to Noise Ratio (SNR). Think about Eb/No as a modem running at 1 bit per second, with the noise power measured in 1 Hz of bandwidth. It’s a useful scale for comparing modems and modulation schemes.
Looking at the black lines, we can see that for an Eb/No or 4dB, we can expect a BER of 1E-2 or 0.01 or 1% of our bits will be received in error over an AWGN channel. This curve is for QPSK or BPSK, different curves would be used for other modems like FSK.
Given Eb/No you can work out the SNR if you know the bit rate and noise bandwidth:
SNR = S/N = EbRb/NoB
or in dB:
SNR(dB) = Eb/No(dB) + 10log10(Rb/B)
For example at Rb = 1600 bit/s and a noise bandwidth B = 3000 Hz:
SNR(dB) = 4 + 10log10(1600/3000) = 1.27 dB
OK, so that was for ideal QPSK. Lets add a few more curves to our graph:
We have added the experimental results for our QPSK simulation (green), and for Differential QPSK (DQPSK – blue). Our QPSK modem simulation (green) is right on top of the theoretical QPSK curve (red) – this is good and shows our simulation is working really well.
DQPSK was discussed in Part 1. Phase differences are sent, which helps with phase errors in the channels but costs us extra bit errors. This is evident on the curves – at the 1E-2 BER line, DQPSK requires 7dB Eb/No, 3dB more (double the power) of QPSK.
Now lets look at modem performance for HF (multipath) channels, on this rather busy graph (click for larger version):
Wow, HF sucks. Looking at the theoretical HF QPSK performance (straight red line) to achieve a BER of 1E-2, we need 14dB of Eb/No. That’s 10dB worse than QPSK on the AWGN channel. With DQPSK, we need about 16dB.
For HF, a lot of extra power is required to make a small difference in BER.
Some of the kinks in the HF curves (e.g. green QPSK HF simulated just under red QPSK HF theory) are due to not enough simulation points – it’s not actually possible to do better than theory!
Estimated Performance of FreeDV Modes
Now we have the tools to estimate the performance of FreeDV modes. FreeDV 1600 uses Codec 2 at 1300 bit/s, plus a little FEC at 300 bit/s to give a total of 1600 bit/s. With the FEC, lets say we can get reasonable voice quality at 4% BER. FreeDV 1600 uses a DQPSK modem.
On an AWGN channel, that’s an Eb/No of 4.4dB for DQPSK, and a SNR of:
SNR(dB) = 4.4 + 10log10(1600/3000) = 1.7 dB
On a multipath channel, that’s an Eb/No of 11dB for DQPSK, and a SNR of:
SNR(dB) = 11 + 10log10(1600/3000) = 8.3 dB
As discussed in Part 1, FreeDV 700C uses diversity and coherent QPSK, and has a multipath (HF) performance curve plotted in cyan above, and close to ideal QPSK on AWGN channels. The payload data rate is 700 bit/s, however we have an overhead of two pilot symbols for every 4 data symbols. This means we effectively need a bit rate of Rb = 700*(4+2)/4 = 1050 bit/s to pump 700 bits/s through the channel. It doesn’t have any FEC (yet, anyway), so we need a BER of a little lower than FreeDV 1600, about 2%. Running the numbers:
On an AWGN channel, for 2% BER we need an Eb/No of 3dB for QPSK, and a SNR of:
SNR(dB) = 3 + 10log10(1050/3000) = -1.5 dB
On a multipath channel, diversity (cyan line) helps a lot, that’s an Eb/No of 8dB, and a SNR of:
SNR(dB) = 8 + 10log10(1050/3000) = 3.4 dB
The diversity model in the simulation uses two carriers. The amplitudes of each carrier after passing through the multipath model are plotted below:
Often when one carrier is faded, the other is not faded, so when we recombine them at the receiver we get an average that is closer to AWGN performance. However diversity is not perfect, occasionally both carriers are wiped out at the same time by a fade.
So we can see FreeDV 700C is about 4 dB in front of FreeDV 1600, which matches the best reports from early adopters. I’ve had reports of FreeDV 700C operating at as low as -2dB , which is presumably on channels that don’t have heavy fading and are more like AWGN. Also some reports of 700C falling over at high SNRs (around like 8dB)! However that is probably a bug, e.g. a sync issue or something else we can track down in time.
Real world channels can vary. The multipath model above doesn’t take into account fast or slow fading, it just calculates the average bit errors rate. In practice, slow fading is hard to handle in digital voice applications, as the whole channel might be wiped out for a few seconds.
Now that we have a reasonable 700 bit/s codec – we can also consider other schemes, such as a more powerful FEC code rather than diversity. Like diversity, FEC codes provide “coding gain”, moving our operating point to the left. Really good codes operate at 10% BER, right over on the Eb/No = 2dB region of the curve. No free lunch of course – such codes may require long latency (seconds) or be expensive to decode.
Next Steps
I’d like to “instrument” FreeDV 700C and work with the 700C early adopters to find out how well it’s working, why and how it falls over, and work through any obvious bugs. Then start experimenting with ways to make it operate at lower SNRs, such as more powerful FEC codes or even non-redundant techniques like Trellis decoding.
Now we have shown Codec 700C has sufficient quality for conversations over the air, I’m planning another iteration of the Codec 2 700C vocoder design to see if we can improve speech quality.
Links
Modems for HF Digital Voice Part 1.
More Eb/No to SNR worked examples.
Similar modem calculations were used to develop a 100 kbit/s telemetry system to send HD images from High Altitude Balloons.
Love the graphs!
Speaking of instrumenting. A solution for Ubuntu is the “man tmpfiles.d” or the systemd interface. Storing your malloc data in ram-drive shared memory rather than regular memory. A short tutorial (not sure how good it is, haven’t tried it yet) is at:
https://goo.gl/tDstv2
Windows probably has something similar, but I haven’t used it since the old XP days.
Just as an exercise I tried the shared-memory technique by just storing the vocoder models in memory. Course, the hard part would be reading the values in another application. I guess I need to add a bit that says updated. Hmm.
https://github.com/ObjectToolworks/vocoder700c-shm/blob/master/src/codec2.c#L72