Machine Decoding of Morse Code (CW) Signals

First, a plea to CW operators:

PLEASE PLEASE PLEASE take care over the SPACING of your code!!!

It is all too common to hear people trying to send Morse as fast as they can, as though this is some way of proving that they are a top-notch operator. Unfortunately, particularly with so many operators using electronic keyers, it is all too easy to run two (or more) characters together into a continuous stream of dots and dashes. To a signal processing & communications engineer like me, the merging of symbols together is known as Inter Symbol Interference and goes a long way towards destroying the transmitted information.

To illustrate this point, lets approximate the set of Morse characters to be of size 40 (26 letters + 10 numbers + a few punctuation). The combination of any two characters results in a 'composite' Morse symbol that belongs to a set of 1600 possible combinations (although many of these will be duplicates but we'll ignore this for now). The difficulty in decoding this composite symbol stems from its ambiguity: There are multiple ways in which the composite symbol can be split back into two characters. I believe the way that humans decode such Morse is by

Even though many humans can read such joined up Morse, the mental load of recognising the composite symbols from the (now very large) list of candidates is significantly higher than for the original Morse character set, due to the need to perform word and sentence analysis. When CW operators run multiple symbols together (and I hear this WAY too often), the result is a mess that typically can only work for 'rubber stamp' QSOs.

And here's my main point: If joined Morse characters can only be decoded by a human that can already predict the sentence, has any communication actually taken place? Think about this next time you are rushing frantically at the key...

The Benefits of Well Spaced Morse

Most computer CW decoders will do a significantly better job if the characters are spaced apart by the duration of 1 dash (= 3 dots). Humans learning Morse will also benefit greatly from a character spacing of more than this, as this will allow them additional time for 'slow recognition'.

The Stages Of Machine Morse Decoding

There are perhaps 3 stages to decoding Morse with a machine:

  1. Demodulate the raw CW audio signal (which is similar to Pulse Amplitude Modulation) into key-downs and key-ups
  2. Decode the Morse symbols
  3. (Optional) Add tier-2 intelligence, such as a word database

Step 1 is remarkably tricky. Pulse Amplitude Modulation (PAM) consists of a signal keying on and off. The receiver can quite easily measure the amplitude of the signal and if the SNR (signal to noise ratio) is good, thresholding this amplitude into key-downs and ups is also trivial. The difficulty comes when

The goal is to slice the signal at some threshold to determine key-downs and key-ups and this threshold must be adjusted according to varying signal conditions. Setting the threshold slightly above the noise floor is a logical choice but in order to avoid many stray triggers (remember that the noise voltage is Gaussian), the threshold must be placed sufficiently far above the noise floor. Unfortunatly, doing so makes it act as a squelch and will prevent the slicer from working with weak signals. This sensitivity floor can even cause problems with strong signals if fading is present as, even if the fades are short, the key down/up sequence will be damaged and lead to corrupted characters.

As far as I know there is no decent solution to the thresholding of PAM and this is probably why its use is limited to short range systems such as car key-fobs where the SNR is high. When decoding Morse, the human brain has the ability to reconstruct the rhythm of the transmitted signal in the presence of both noise and fades. I believe this is down to the powerful frequency selectivity of the human ear (~10Hz, in spite of the signal being keyed at a rate faster than this bandwidth will allow) and the ability to dead-reckon a dit or a dah based on the likelihood of the current Morse character (equivalent to Maximum-Likelihood error correction).

Step 2 can be implemented in the absence of step 3 quite easily: After a character gap of 1 dash, a new symbol is started. As key-downs and key-ups are received, a 'hash' code may be computed. The hashing algorithm is such that by the end of the character, the numeric value is unique and may be looked up in a (sparse) lookup-table. It is quite straight forward to integrate a frequency-tracking loop into the key-down / key-up processor so that changes in Morse speed can be accommodated.

Simple word checking can be applied to the output of step 2. However, better performance will be gained from merging the process of character identification with word checking so that likely candidates for any merged character pairs (or longer ?) can be looked up. This is all getting very complicated.

Example code to follow...


Last updated: 13.4.2016