Tuesday, 16 December 2014

Introducing the Lissajous waveforms

Introduction

I recently discovered a family of periodic functions based on the Lissajous curves that have many desirable properties when it comes to sound synthesis.
First of all the functions are smooth. This means that last harmonics fall off exponentially leading to a pleasant round sound and less aliasing artifacts. Secondly they come with two parameters that control the timbre of the sound making it sharper in various ways.

Lissajous waveforms

A Lissajous curve is defined by the parametric equation:
x = A sin(a t + δ)
y = B sin(b t)
For example taking A = B = 1, a = 2, b=3, δ = π/2 we end up with the following figure:
This a two-dimensional curve so we need some way of reducing it to a function of one variable. Here we choose to take the angle measured from the x-axis counter-clockwise:
In other words we're aplying the atan2(y, x)-function to the parametric equation. The result looks something like this:
Oops! There are at least three things wrong here. The obvious flaw is that the graph is clearly not smooth. This is caused by atan2 being a multi-valued function that is reduced to a single value. In other words the first problem is angle wrapping. To unwrap the angle in this case we simply add 2π to the result if the parameter t is in the range from 0 to π and the angle is negative and subtract 2π if t is in the range from π to 2π and the angle is positive.
The second problem is that the period is 2π. This is easy to fix by scaling t.
The third problem is normalization. It turns out that after unwrapping the angle the maximum value of the function is 5π/4 at t = π/2 . Simply dividing the function by this value solves the problem.
After fixing everything we end up with this waveform:
A nice and smooth waveform that sounds like a soft triangle wave:

Adding timbre control

For fixed a and b the Lissajous curve comes with three interesting parameters A, B and δ, but because we're only interested in the angle traced by the figure we can ignore it's size and replace A and B with a sharpness parameter S.
A = 1 + S
B = 1 - S
By varying S away from zero we can make the waveform more or less sharp:
S = 0.75
The positive and negative values of S change the waveform in different ways:
S = -0.75
Sweeping the sharpness from 1 to -1 sounds like this:

Bias control

The value of δ = π/2 is special in that it makes the a=2, b=3 waveform as smooth as possible. Other values are however possible. Take δ = 2 for example. The resulting Lissajous curve looks like this:
And the resulting Lissajous waveform looks like this:
In effect we have biased the waveform to lean more to the right. There is is a limit to how much the δ parameter can be changed. If the the Lissajous curve crosses zero or winds around zero on the wrong side the angle unwrapping breaks down. The exact range that δ can take depends on a and b. From δ we can derive a bias parameter that varies in the range from -1 to 1 with 0 representing the smoothest achievable waveform.
Sweeping the bias from 1 to -1 sounds like this:

 

The problem of normalization

As you may see from the graphs the maximum value of the waveform differs from one when S differs from zero. It turns out that the maximum can be expressed in terms of elementary functions, but save for the a=1, b=1 case the expression is prohibitively huge. I'm therefore leaving full normalization out from the implementation.

The odd-odd case

We've dealt with an even-odd case above with a=2, b=3. Having one of these parameters even has the fortunate side-effect that the curve never makes a full rotation around zero without making one back. This in turn limits the angle to a finite range. In the case that both a and b are odd the situation is different and the angle keeps increasing (or decreasing) without limit. Take a=1, b=3 for example:
The graph of the angle looks like this:

We can see that the angle keeps decreasing on average and that the shape repeats twice with every "period".
The fix this we subtract the average angle and divide the frequency by two. In this case the result looks like this:
and sounds like this:

The sharpness as bias parameters work in the same way as they do in the even-odd case. Here's a sharpness sweep:

Implementation

That wraps up the theory of the Lissajous waveforms. For larger a and b the specifics of angle unwrapping and normalization get increasingly complex and sometimes it is necessary to find the maximum value numerically instead of reasoning it out from a graph.

This Gist contains Python implementation of all the unique Lissajous waveforms up to a ≤ b ≤ 6:


2 comments:

  1. Awesome blog. The lissajous function sounds very nice. Have you checked out serge wave folding? it's just a sinus amplified and passed through a number of mirrors/ping pong maths, so that it folds gradually as you increase the amplitude and adds an sweet series of harmonics to the sine.

    ReplyDelete
  2. Thank you!
    I hadn't heard of Serge. Need to check that out.

    ReplyDelete