Sunday 26 February 2017

Signal Processing on the Arduino

I've been doing some DSP on the Arduino

Since signal processing is so computationally intensive, we tend to associate it with powerful processors, like the mighty ARM of the DUE. However, it is entirely possible to do useful signal processing tasks - such as running digital filters, or even performing Fourier Transforms - on humble little processors like the ATmega328 on the Arduino. These past few days I've been doing just that.

The application is within music - specifically, on my new modular synthesizer. But don't look away just because you might not be interested in music, for underlying this is an entirely general application of real-time programming.

My synthesizer already had (as you might have seen) a couple of envelope generators, capable of producing exponential 'attack' and 'release' envelopes at the edges (or at the beginning) of a gate pulse. However, I wanted a more traditional 'ADSR' envelope generator with the capability to generate independent control of three time constants: attach, release and 'decay', as well as to manage the amplitude of a 'sustain' phase.

This type of circuit needs two core elements:
  1. a first-order circuit with three controllable time constants   
  2. logic to switch between the three exponential decay phases and manage the 'sustain' phase.
Ordinary ADSR circuits charge or discharge a capacitor at three different rates; an analog solution involving a simple, first-order differential equation (albeit with changing coefficients). The exponential voltage required in any phase is the voltage on the capacitor of a trivial RC filter.

It struck me that - given the requirement for the logic around the analog filter, the entire system might be better implemented by a micro-controller, replacing the analog 'filter' with its digital equivalent.

I certainly don't claim any novelty in this thought - indeed, it was reading about Tom Wiltshire's excellent Digital Envelope Generator which motivated me to give it a try. But the experiences of doing some more work back in PIC-land last week (more of that in a later post) reminded my just how dry and tedious that place can be, so I set about trying it on the homely little Arduino.

Neither do I claim any novelty about the idea of doing it on an Arduino - somebody/several bodies must have done it on this platform before (indeed, I got a first version running using ADSR() from Mozzi, but I didn't like that for several reasons, most important of which was management of the sustain phase). Anyway, whatever the reasons, I wanted to have a bash for myself.

Let's take a look at my code first.

Here's the core first-order difference equation which - in any of the phases of operation - produces the required exponential envelope...

'envelope' is the main variable, which is updated every pass through the program to its next value, ready to be output to the DAC in the 'Set_DAC_4921()' subroutine. 'alpha' is actually the location of the single pole of the digital filter (remember - this is a first order digital filter) and it determines the 'time constant' of the exponential decay. 'drive' is a constant, driving the step response of the filter in this phase. The factor (1-alpha) is required to correct the overall gain of the filter to unity at zero frequency.

If you don't understand the math behind this stuff don't worry - you can read about it in a book if you like - or you can just be content to use the results. I've written the difference equation in the comment above in something close to 'conventional' notation, for those who do understand these things.

That was the first of the two 'core elements' - the digital filter implementing the exponential response. The second part is the logic. Here's a snapshot of part of that logic...

To be precise, it is the part of the logic which tests if the envelope is at the end of the attack phase. If it is the end, new values of 'drive' and 'alpha', relevant for the next phase - the decay phase - are loaded.

Enough dry talk of the inside of the code - if you want to see it all, you can download it from this github repository.

I had to give it a name and I followed the rather childish practice of choosing names which pick up on the involvement of the Arduino: 'ADSRduino'. Sorry.

Instead of talking, let's see some action.

You probably weren't impressed with the rather quantized image at the top of the post. What you didn't know was that entire envelope was less than 10ms long (shown in order to demonstrate that this system is appropriately fast - in fact, the sample rate [that's to say, the rate at which the difference equation is operated] is around 3.3kHz).

Here's a longer event (around 400ms long) along with the gate pulse from my keyboard which triggered it. It leaves time for envelope to move through the quantization steps of the DAC more slowly, making for a smoother trace.

Here's the same thing, annotated to make it clear what all this is about:

You can see that the attack phase starts when the note is gated and rises up to full value (actually 5V) then falls down in the decay phase to the sustain level. The note is sustained until the gate is released (unless it already has been released), after which the release phase begins.

The time constants for attack, decay and release - and the level for sustain, are adjustable via user potentiometers. To illustrate the point, here's another setting (with fast attack and lower sustain and, as it happens, I pressed down the key for longer, so the gate pulse and associated sustain phase is longer):

All of this is actually running on useful hardware. It started as a prototype on an Arduino UNO and then migrated onto a physically smaller NANO, which is seen here...

You can see both the original trimpots used for the ADSR controls and the new potentiometers on a front panel (made from double-sided copper-clad board, painted black to make it look fancy) - as well as sockets for the gate input and the output. There's also a switch to select a looping mode, in which the system can automatically re-trigger itself.

You can also just see (at the right-hand end of the breadboard) the little MCP4921 12-bit DAC used to output the envelope voltage.

The circuitry above was moved onto a piece of stripboard:

and assembled, using the bracket bent up from sheet steel, into a complete 'Eurorack' module:

You can find a schematic for the whole system here

It now does great service in the considerably extended modular synthesizer:

where it sits next to another Arduino-based module, running as a voltage-controlled digital wavetable oscillator, built upon resources from the Mozzi library.

Of course, as I mentioned at the top of this post, you can take the signal processing ideas on the Arduino further than first-order. I've been playing with a biquad structure on the Arduino within the loop() function...

(in which all the elements have their usual meaning). I found that it is easy to achieve a sample rate of 2 kHz which - although it isn't useful for audio frequency work - does make for some very useful filtering for signal detection etc. If you need to detect or monitor AF signals, the Fast Fourier and Hartley Transforms work very well at sample rates of tens of kHz - but that's a rather different kettle of fish.

Don't overlook the little ATmega328 when you're playing with a time-varying signal that takes you to the edge of a DSP application. You can run some genuine digital filtering algorithms (including floating point math to manage poles right up close to the unit circle) and have fun in the process.

...-.- de m0xpd

Saturday 4 February 2017

A Modular is Born

I should 'fess up'. I've been having a ball. I've been neglectful of the radio arts whilst working up my recent experiments with analog synthesizer elements into something more permanent.

In fact, you caught a glimpse of some of my synth modules on stripboard in my last post. Now, I've bent up some mounting brackets from sheet steel and made front panels (in standard 'Eurorack' size) to turn them into pukka modules.

Here, for example, is the evolution of my dual envelope generator module, the circuit of which was inspired by ideas on Ray Wilson's MFOS site...

Of course, once in these modules, bringing together some recipe on the bench isn't quite as untidy as it was before

but the real purpose of adopting the (3U) Eurorack standard is such that everything can be mounted in a standard card frame.

This ought to pose a challenge for a notorious cheapskate like m0xpd but - as ever -  it isn't what you know, it's who you know. In this instance, we're indebted to Nigel. A little judicious metalwork (to reduce the depth of the donor frame) and several modules later...

Here you see the current complement of modules, as labelled. With all the inter-connectivity afforded by those 3.5mm jack sockets, you very quickly learn the first rule of modular synthesizers: 'you can never have enough patch cables'.

Again, a challenge for the cheapskate (have you seen how much they want for patch cables?!?). Fortunately, I found a nice OM who is selling batches of old-school mono 3.5mm jack plugs on that familiar auction site for bait money - so I'm rolling my own patch cables.

In the image above you can see that the VCO is still in proto form, off to the left of the synth, because I'm still not happy with the performance of this simple oscillator with its (admittedly) simple circuit.

At least I've added a MIDI interface to drive the synth...

MIDI (from either a keyboard or from a sequencer on the computer, via the USB - MIDI interface) goes through the MIDI to TTL converter shown (which I knocked up with a 4N25 found in the junk box) and into the Arduino MEGA.

It is good that it's a MEGA because this flavour of Arduino has four UARTs, meaning that I can keep the connection to the PC (for e.g. programming) AND have another serial connection dedicated to MIDI. This isn't possible on (e.g.) the humbler Arduino UNO.

The Arduino MEGA is now running a MIDI to CV and Gate routine, with which I can make my new modular synthesizer generate all sorts of irritating and occasionally musical sounds.

So - not much radio action to report - but a whole lot of 'radiophonic' fun.

...-.- de m0xpd