My Morse Decoder first run was successful. Building the prototype quickly gets you on the learning curve faster.
Starting with the source code provided by OZ8SMA, I built a breadboard prototype. I modified his code into separate modules for all the steps in the decoding process. Consequently, I will be able to experiment with different changes to improve performance.
One of the first changes was to search for a graphics library that would be super efficient in updating the display. I found a customized version of the Adafruit GFX library that implements vertical scrolling in hardware. This scrolling display terminal is described in an Instructable. It provides significant speed improvement.
On the hardware side, I use a voltage divider to create DC offset for the incoming audio. Because the audio from the line out of my receiver is around 400 millivolts (peak-to-peak), this creates a signal of 1.65 V plus/minus 0.4 volts for the Arduino to sample. The DC offset circuit is shown in the top left above.
Morse Decoder First Run – Early Learnings
One of the first things I learned was that line out audio from different receivers varies a lot. From 400 millivolts down to 100 millivolts peak-to-peak. As a result, the magnitude of a tone measured by the Goertzel filter also varies a lot. I found that the automatic threshold detection algorithm used by OZ8SMA did not perform well across the various audio levels.
So, I am going to experiment with different threshold and detection techniques. To accomplish this, I will attach an rotary encoder to the Morse Decoder so I can make various adjustments while the program is running.
void AutoThresholdOriginal() { // Original OZ8SMA code // int magnitudelimit = 100; (starting value) // int magnitudelimit_low = 100; // It tries to adjust magnitudelimit according // to the average strength of signal tones. // "magnitude" is the output of Goertzel filter if (magnitude > magnitudelimit_low) { magnitudelimit = (magnitudelimit + ((magnitude - magnitudelimit) / 6)); } if (magnitudelimit < magnitudelimit_low) magnitudelimit = magnitudelimit_low; if (magnitude > magnitudelimit*0.6) RealState = HIGH; else RealState = LOW; } void AutoThresholdFixed() { // An alternative is to set a fixed threshold // ranging from 200 for low audio up to // 4000 for high audio. This level can be // set with a rotary encoder if (magnitude > ThresholdFixed) { RealState = HIGH; } else { RealState = LOW; } // The benefit of this approach is simplicity. On // a good strong signal, it works perfectly. }