A DSP audio processor aimed at radio amateurs
This project is a DSP audio processor, aimed at the radio amateurs. It's key features include:
It has audio input via line-in and USB, and audio output via line-out and headphone socket.
I built it as I had an SDR based transceiver with no built in noise reduction, and wanted to see what was possible to improve that situation. In the spirit of amateur radio, and because my background is in embedded programming, I didn't want to purchase a ready made unit, so I went about building and coding up my own.
As an added bonus, the CW decoders tend to be better than the one built into my transceiver, and auto detect key speed.
An expanded list of Features can be found below.
Here I should say, this project is 'built on the shoulders of giants'. All the technically challenging hard math innards of the code has been derived and extracted from other projects. My task was merely researching, collating and knitting together all the relevant parts into one functional unit with the features I was looking for. Without the work of the below mentioned, and many others, this project would have been orders of magnitudes more difficult, and have taken significantly longer to put together.
Honorable mentions then to:
and many others.
A history of versions can be found at the end of this document.
The basic hardware is built around a Teensy 4.0 board along with its matching audio daughtercard. In addition to that there is a 2x16 screen, a single LED, a rotary click encoder and a switch to enter reprogramming mode. That's it. Pretty simple.
The heavy lifting is done by the Teensy and its audio card. I used an I2C based Grove RGB LCD merely as that is what I had to hand. If I'd had a standard HD44780 style 2x16 display to hand then I probably would have driven that in 4bit mode instead. See below for more on hardware choices.
Note: In the circuit diagram, the LCD type shown is incorrect - only because the package I used to draw the diagram did not have the Grove RGB LCD I2C in its library. You get the idea - there are only two data wires going to the LCD (along with the two power connections). It should also be noted that, technically, the Grove RGB LCD is a 5V part, and the Teensy is a 3V3 part, so having the Teensy driving the display is probably not guaranteed to work. It works for me, but if you are purchasing anew you may wish to try and source a 3V3 tolerante display. As long as the display is supported by the "Arduino Menu" system, and you can find enough pins to wire it to the Teensy (there are a number spare I believe), then it should be easy to modify the initialisation code to handle the new display. Do ask me if you need some help.
Note: The LED resistor value is calculated to limit the current drawn from the Teensy 4.0, depending on your chosen LED. You may wish to re-calculate this value to suit your build, or possibly even better add some sort of LED driver/transitor switch circuit to further reduce the current draw from the Teensy. The Teensy 4.0 current draw, total for all pins, is specified as 10mA. Be careful.
Note: The rotary encoder I use - a KY-040 came on a module (pcb) that contained some pullups. They are now depicted on the schematic. Hopefully if you have a different or bare module this will help with the wiring up. if you get the DT and CLK pins wired around the wrong way it will just make the rotary encoder 'work backwards', e.g., go anticlockwise with respect to the menu system. You can either fix that by swapping the wiring over, or modifying the software to tell it the pins are the other way around.
Warning: If you are going to power the Teensy from an external power supply (such as the 7805 I used), and you still want to be able to use or program over the USB port, then you must snip a track on the Teensy board to separate the VIN and VUSB - see the Teensy 4.0 pinout diagram for details. If you do not make the modification I believe you are probably in danger of frying something.
I built my unit with the Grove RGB LCD and a KY-040 rotary encoder. Those were just what I had to hand or could get cheaply and easily - you may of course have other hardware to hand you wish to use. You will 'simply' have to modify the software setup to cater for the changes.
For the LCD, that will involve modifying the menu library code found at the bottom of the
menu.cpp
file, such as:
MENU_OUTPUTS(out,MAX_DEPTH
,GROVERGBLCD_OUT(lcd, {0, 0, 16, 2})
,NONE//must have 2 items at least
);
See the menu library web pages for more details.
For the encoder, hopefully it will work like most other rotary shaft encoders, and will 'just work',
as long as you wire it up to the correct pins. But if not, you may need to modify the encoder and
button code, both near the top of the menu.cpp
code:
#define encA 3
#define encB 2
#define encBtn 4
ClickEncoder clickEncoder(encA,encB,encBtn,2);
ClickEncoderStream encStream(clickEncoder,1);
and near the top of the DSPham.ino
file:
Encoder enc1(3, 2);
You can both modify which pins the encoder is wired to, which way around the pins are wired
(which effects clock/anti-clockwise rotation wrt to the menu). You may also need to change the
number of clicks per detent for your chosen encoder - that can be changed with the stepsPerNotch
parameter to the ClickEncoder
invocation. For reference, my encoder seems to have 30 detents
per 360 degrees, and 2 steps per click (60 steps for a 360 degree rotation).
The software is built using the Aruduino IDE along with the Teensyduino addon.
The software is architected around the flow of the excellent PJRC Teensy audio library, and its associated GUI design tool.
A key feature, and a powerful feature of the audio library, is that inbetween the two data queues we can, and do, apply other processing to the data flow, such as using the ARM CMSIS functions or open coding algorithms (as is done for some of the noise reduction code).
From Version 1.1 the audio path is run with a decimation of 4, bringing the path down to 11kHz sample rate. Although this saves us processing overhead, the main goal was to 'focus' the noise reduction algorithms to process just the audio spectrum (0-5.5kHz), rather than trying to process the whole CD quality spectrum (0-22kHz), if we'd not decimated the native 44kHz sample rate.
The display has two 'modes'. The default mode is to show the current status/setup, and if a decoder is active, then to display the output of the decoder.
The top line of the display shows either the name of the current settings slot, or the output of the active decoder.
The bottom line shows status information. The following table summarises the bottom line:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|S|F|N|N|A| |NR | |C P U|C|W |
|i|i|B|o|G| | | | | | | | |W|P |
|g|l|l|t|C| | | | | | | | |T|M |
|n|t|a|c| | | | | | | | | |u| | |
|a|e|n|h| | | | | | | | | |n| | |
|l|r|k| | | | | | | | | | |e| | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
the LED flashes in sync with CW tone detection.
The menu system is entered by clicking the rotary shaft encoder, and navigated with rotates and
clicks of the encoder. It is exited by using the Back
menu items within the menu itself. The
menu is hierachical. Exiting the top level menu takes you back to the status display.
The following top level menus are available:
The unit stores 11 'slots' of settings in the eeprom. The first six of these slots are initialised with some defaults:
All eeprom slots can be edited, modified and saved. The defaults can be restored if necessary, on either a slot by slot or full system basis.
One interesting feature of the 'settings' menu, due to the limited number of inputs, is you need to select the slot you wish to name/reset/save before you perform the action. Thus, first set the slot number you wish to edit, and then make your edits/saves/resets etc.
The following features are in the current code:
The project is built using the Arduino IDE with the Teensyduino addon. To save everybody having to build the project from source, Pre-built binaries are provided in the GitHub Releases, which can be burnt into the Teensy 4.0 using the Teensy Loader.
In order to build the project from sources, you will need a few extra libraries and to configure your Teensy 4.0 board correctly:
You also need to have all the sources, not just the .ino
file, in a directory named DSPham
. Note,
if you downloaded a zip
or tar.gz
file from GitHub, then it will most likely have placed the
source files in a subdirectory called DSPham-master
or DSPham-x.y
- I believe you must
rename that directory to be just DSPham
before you can build it with the Arduino IDE.
That should give you the correct setup and libraries to build and program the project. The most common
mistake I make is to not set up the correct 'USB Type' for the Teensy audio shield support, which tends
to end in errors such as Audio.h not found
etc.
If you are developing/improving/testing new features, then the ability to feed audio via the USB port is very useful, allowing you to develop without needing a rig wired up or running, and allowing you to feed the same audio time and again to make comparisions easier.
If you do build yourself one of these, then watch out for RF emissions! I initially had a lot of noise being injected into my system, and had to shield the case, add isolation and ferrites, but most importantly was to add a good set of smoothing and filtering capacitors to the 7805 PSU. Do not skimp on that, as I learnt.
If you do build one of these, and have any questions etc., feel free to ask. Probably the best place to ask is via a GitHub Issue, as then we get a recorded history to help others in the future.
If you want to contribute code and improvements, feel free! It might be an idea to ask me first though what I think, just in case that is a feature I've already tried, or am working on, or had already dismissed. No point duplicating work.
All submissions should come via Github pull requests. Requests, bugs etc. should be reported via Github issues.
This section details the version 'releases', and what changed. Releases can be found on the Release page.
Version | Date | Changes |
---|---|---|
v1.0 | 2021-02-10 | Initial release |
v1.1 | 2021-02-16 | Normalise FIRs. Decimate audio x4 |
v1.2 | 2021-03-16 | Fix FIR normalise bug. Add input clip indicator |
v1.3 | 2021-11-08 | CW decode enhance. Menu name slot edit enhance |
So you can get some idea of the performance of the unit, I've recorded and uploaded a couple of samples. The samples were recoded off my Xiegu G90 transciever, from an ~43ft long wire strung out in a fairly noisy urban environment:
1) The 20m whistle sample is an SSB conversation, with a constant tone whistle just inside its upper passband. The sample starts out for 10s in 'setting 2 - OFF', then moves to 'setting 3 - SG5K' for 10s, which is with the hardware AGC in the DSPham enabled. Then it moves to 'setting 4 - SSB', which has an SSB bandpass, notch and glitch filters, SG5K AGC and the Spectral noise reduction all enabled.
2) The VOLMET sample is a recording of a VOLMET weather broadcast on 5.450MHz. It conviniently has some RTTY type interference in the background. The sample starts out for 10s in 'setting 2 - OFF', then moves to 'setting 3 - SG5K' for 10s, which is with the hardware AGC in the DSPham enabled. Then it moves to 'setting 4 - SSB', which has an SSB bandpass, notch and glitch filters, SG5K AGC and the Spectral noise reduction all enabled.