Polish radio amateur SQ2BVN develops open-source CW decoder, ktorý kombinuje klasické DSP audio signal processing with a convolutional neural network based on TensorFlow. The goal of the project is not to replace the operator's ear in clean conditions - Goertzels will suffice for that detektor s adaptívnym prahom. Neurónová sieť má pridanú hodnotu tam, kde zlyhávajú klasické metódy: pri silnom QSB, QRM od susednej stanice, atmosférickom QRN a nepresnom ručnom kľúčovaní.
You will read in the article
A unified front-end as a foundation
The whole system is based on the principle of a single source of truth for DSP parameters. The configuration in the config.py file defines all the constants – the range of mel bands (400-1200 Hz), the number of mel filters (32), the window length (2.56 s at 128 frames at 20 ms) and the decibel scale with fixed DB_MIN and DB_MAX limits. All tools – training data generator, trainer, visualization and live path – call the same frontend.to_net_image() function and produce identical output. This eliminates the typical problem of ML projects where the training and production paths use different normalizations.
Important detail: the project deliberately does not use normalization to the maximum of the clip (REF=np.max), which would cause the output to depend on the rest of the recording. The decibel scale is absolute, which ensures reproducibility - the same tone at the same level will give the same pixel regardless of the surroundings.
Radio channel model
The training data generator simulates real-world propagation conditions on KV bands, including six effects: QSB (amplitude swing), QRM (passband jamming station), QRN (atmospheric discharges), imprecise manual keying with ±0-25% deviation, frequency drift ±8 Hz per clip, and spectrally colored floating-level noise. The effects can be turned on individually, which makes it possible to measure which of them the model handles the worst. The training set of empty clips (class 0) also contains QRM - this way the network learns that energy outside the tone is not a feature.
X-Ray – visual control of data
The xray.py and xray_all.py tools render the training samples as PNG tiles of 128 × 32 pixels with a shared dB scale. Below each tile is a white band indicating the boundaries of the marked character and colored indicators of active effects (QSB, QRM, QRN, keying). The default sorting – sort contrast starts from the heaviest samples. Visualization will detect issues with timing, character overhang, or too much background noise before they affect the accuracy of the model.
Network architecture and embedded deployment
The default architecture (–arch dpu) uses convolutional layers exclusively with about 624,000 parameters and a model size of about 1.5 MB. A reference architecture with bidirectional GRU exists for comparison, but it achieved the same 97.51% accuracy in testing - recursion did not improve and was four times slower. The receptive field of the convolutional network covers 110 frames (2.20 s), which is enough for the longest character including spaces.
The convolutional architecture is chosen with regard to deployment on the AMD Kria KV260 FPGA platform with the DPUCZDX8G accelerator and Vitis AI tools. DPU does not support recurrent layers, therefore the GRU variant is not deployable. For the mel front-end on the embedded target, there is a purely numpy reference implementation (melref.py) ready to be ported to C. Quantization to int8 for Vitis AI benefits from a fixed dB scale - the calibration range does not depend on the content of the clip.
The current model trained on 1.6 million samples (RTX 3050, 120 minutes) achieves a validation accuracy of 98.95% and decodes at 10-30 WPM. The limitation remains the narrow frequency range of 670-830 Hz - tuning to the right tone is essential and is provided by the tune.py module. Version 0.9.2 is available as Windows Installer, which does not require administrator rights and works with USB zvukovou kartou transceivera alebo mikrofónom.
