# Guidance on Low Frequency Oscilator (LFO) implementation

Started by February 28, 2004
```Hi, guys.

I need your advice on the implementation of an LFO, with variable Fo
(oscillation frequency), in the range 0.01Hz <= Fo <= 2.0 Hz, sampling
at Fs = 44.1kHz.

To be done with an ADSP-21065L in floating point (EzKit).

Due to these ranges, a LUT (look up table) doesn't seem to be a viable
solution.

At this moment, I have implemented an oscillator based on the
relation:

cos(A+B) = 2cos(A)cos(B)-cos(B-A)

With A = 2*pi*Fo/Fs

For initialization, or when Fo is changed, I calculate cos(B) using
25th order McLaurin series, giving me an error of < 0.0007% for |x| <=
PI/2... But there is a little, but significative problem: the smaller
the value of Fo, the closer its cosine is to 1, and the oscillator
doesn't oscillate at all!!! Even for Fo = 1.0, I don't get the right
oscillation frequency, it's somewhat higher.

However, I've found that for Fo >= 100 Hz. the oscillation frequency
is exactly what is expected!!!!! I tried with Fo up to 20000 Hz, with
no problemas at all.

That makes me thing of using different approaches, coupled with my
existing oscillator design, now running at higher ("valid") Fo:

1. Mixing its output with another oscillator and using the relation:

cos(A)*cos(B) = 1/2[cos(A-B)+cos(A+B)]

Then filtering to get rid of cos(A+B), and scaling. A and B should
chosen in such a way that A-B = Fo. One drawback seems to be the fact
that, due to the fact that Fo is really small, A and B should be very
close, and I am not sure if the final effect will be to have an
oscillator at exactly Fo.

2. Runnimng the oscillator at a frequency N times Fo, then
downsampling by N.

All of your opinions and suggestions are _VERY_ welcome.

Regards,

JaaC
```
```On Sun, 29 Feb 2004 13:59:29 +1300, Jaime Andres Aranguren Cardona wrote:

Since you are using floating point arithmetic, it may be worthwhile using
( cos(A)-1 ) as a term and compensating for the -1 term by adding in
cos(B). (I read "A" as being the increment)
Another technique which may be useful is to create a coarse waveform at a
much lower frequency (eg Fs/64) to lock the freuency to the correct value
and extrapolate from this. Hope this is of some use.
> Hi, guys.
>
> I need your advice on the implementation of an LFO, with variable Fo
> (oscillation frequency), in the range 0.01Hz <= Fo <= 2.0 Hz, sampling
> at Fs = 44.1kHz.
>
> To be done with an ADSP-21065L in floating point (EzKit).
>
> Due to these ranges, a LUT (look up table) doesn't seem to be a viable
> solution.
>
> At this moment, I have implemented an oscillator based on the relation:
>
> cos(A+B) = 2cos(A)cos(B)-cos(B-A)
>
> With A = 2*pi*Fo/Fs
>
> For initialization, or when Fo is changed, I calculate cos(B) using 25th
> order McLaurin series, giving me an error of < 0.0007% for |x| <=
> PI/2... But there is a little, but significative problem: the smaller
> the value of Fo, the closer its cosine is to 1, and the oscillator
> doesn't oscillate at all!!! Even for Fo = 1.0, I don't get the right
> oscillation frequency, it's somewhat higher.
>
> However, I've found that for Fo >= 100 Hz. the oscillation frequency is
> exactly what is expected!!!!! I tried with Fo up to 20000 Hz, with no
> problemas at all.
>
> That makes me thing of using different approaches, coupled with my
> existing oscillator design, now running at higher ("valid") Fo:
>
> 1. Mixing its output with another oscillator and using the relation:
>
> cos(A)*cos(B) = 1/2[cos(A-B)+cos(A+B)]
>
> Then filtering to get rid of cos(A+B), and scaling. A and B should
> chosen in such a way that A-B = Fo. One drawback seems to be the fact
> that, due to the fact that Fo is really small, A and B should be very
> close, and I am not sure if the final effect will be to have an
> oscillator at exactly Fo.
>
> 2. Runnimng the oscillator at a frequency N times Fo, then downsampling
> by N.
>
> All of your opinions and suggestions are _VERY_ welcome.
>
> Regards,
>
> JaaC

--
(no SPAM no space)
```
```Jaime Andres Aranguren Cardona wrote:

> I need your advice on the implementation of an LFO, with
> variable Fo (oscillation frequency), in the range 0.01Hz <= Fo
> <= 2.0 Hz, sampling at Fs = 44.1kHz.

> At this moment, I have implemented an oscillator based on the
> relation:
>
> cos(A+B) = 2cos(A)cos(B)-cos(B-A)
>
> With A = 2*pi*Fo/Fs

> the smaller the value of Fo, the closer
> its cosine is to 1, and the oscillator doesn't oscillate at
> all!!! Even for Fo = 1.0, I don't get the right oscillation
> frequency, it's somewhat higher.

The recursive system has roundoff problems when the poles are very
near DC, z = 1. I suggest you run the LFO at quite a low rate and
resample. Depending on just what is modulated how ;) you might not
need an exact value for each audio sample, and could get away with
lower-order interpolation over subblocks of a few to a few dozen
samples -- use your ears there. The LFO and similar things would be
computed in between. The process adds one subblock length to the
control latency, though.

What do you use the LFO for? In a synth, note-on LFO phase may
actually be relevant.

Martin

--
-= Send your critique by email. =-

2 + 2 = 5, for sufficiently large values of 2
```
```Jaime Andres Aranguren Cardona wrote:
> Hi, guys.
>
> I need your advice on the implementation of an LFO, with variable Fo
> (oscillation frequency), in the range 0.01Hz <= Fo <= 2.0 Hz, sampling
> at Fs = 44.1kHz.
>
> To be done with an ADSP-21065L in floating point (EzKit).
>
> Due to these ranges, a LUT (look up table) doesn't seem to be a viable
> solution.

Question:

Why wouldn't DDS be the simplest way to do this?  Must floating point be
used?  Is it some sort of homework problem?

Just curious.

Good day!

--
_____________________
Christopher R. Carlen
Suse 8.1 Linux 2.4.19

```
```Chris Carlen wrote:

> Jaime Andres Aranguren Cardona wrote:
>
>> Hi, guys.
>>
>> I need your advice on the implementation of an LFO, with variable Fo
>> (oscillation frequency), in the range 0.01Hz <= Fo <= 2.0 Hz, sampling
>> at Fs = 44.1kHz.
>>
>> To be done with an ADSP-21065L in floating point (EzKit).
>>
>> Due to these ranges, a LUT (look up table) doesn't seem to be a viable
>> solution.
>
>
>
> Question:
>
> Why wouldn't DDS be the simplest way to do this?  Must floating point be
> used?  Is it some sort of homework problem?
>
> Just curious.
>
> Good day!

Chris,

I'm confident that Jaime would make it clear if his problem were
homework.

Jaime,

Is there a reason that  sin(n+1) = A*sin(n) + B*cos(n)
and                     cos(n+1) = A*cos(n) - B*sin(n),

where A = cos(delta) and B = sin(delta), both constants for any given
frequency. A quick normalization step keeps the amplitude at unity.
You've seen this before, but I could repeat it in detail if you need me
to. At the frequencies that interest you, approximating cos(delta) as 1
and sin(delta) as delta might be completely acceptable.

Jerry
--
Engineering is the art of making what you want from things you can get.
&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;&#2013266095;

```
```Hello,

First of all, thank you all for comments and suggestion.

Jerry Avins <jya@ieee.org> wrote in message news:<404276ee\$0\$3079\$61fed72c@news.rcn.com>...
> Chris Carlen wrote:
>
> > Jaime Andres Aranguren Cardona wrote:
> >
> >> Hi, guys.
> >>
> >> I need your advice on the implementation of an LFO, with variable Fo
> >> (oscillation frequency), in the range 0.01Hz <= Fo <= 2.0 Hz, sampling
> >> at Fs = 44.1kHz.
> >>
> >> To be done with an ADSP-21065L in floating point (EzKit).
> >>
> >> Due to these ranges, a LUT (look up table) doesn't seem to be a viable
> >> solution.
> >
> >
> >
> > Question:
> >
> > Why wouldn't DDS be the simplest way to do this?  Must floating point be
> > used?  Is it some sort of homework problem?

Well, floating point is what I have in '065L (32bit fixed point too).
No, no homework problem. OK, I admit it, it seems to be.

> >
> > Just curious.
> >
> > Good day!
>
> Chris,
>
> I'm confident that Jaime would make it clear if his problem were
> homework.
>

Thanks, Jerry.

> Jaime,
>
> Is there a reason that  sin(n+1) = A*sin(n) + B*cos(n)
> and                     cos(n+1) = A*cos(n) - B*sin(n),
>
> where A = cos(delta) and B = sin(delta), both constants for any given
> frequency. A quick normalization step keeps the amplitude at unity.
> You've seen this before, but I could repeat it in detail if you need me
> to.

I have the article from DSP Tricks section in IEEE SP Mag, by Clay S.
Turner, titled "Recursive Discrete-Time Sinusoidal Oscillators" (what
a great article!), which I suppose will clarify many doubts to me.

Indeed, I also thought of using the approach you suggest (coupled,
standard quadrature oscillator, in C. S. Turner's words), but as with
my first approach, I thought it would also require of double precision
arithmetic to run fine at those low frequencies.

> At the frequencies that interest you, approximating cos(delta) as 1
> and sin(delta) as delta might be completely acceptable.

That's the good news, then!!! I'll try with it, and will post my
results back. I did MATLAB simulation with god results, but as the
internal representation is in doubles (or am I wrong), I thought of
changing the approach. Maybe the Fixed Point Toolbox might help, I'll
try.

Anyway, I've tried other approaches. For example, usage of a (not too
big) table. Fo = 50Hz, Fs=44.1kHz. But reading it with one of the
onchip timers at a slower rate, to update a variable. This variable is
read at 44.1kHz. With this approach I can have waveform at a lower Fo,
sampled at 44.1kHz. But the waveform looks like a stairway, I'll need
some sort of interpolation or lowpass filtering.

All of your comments regarding this approach, and the others, or any
otherr one, are very welcome. I need them!

And again, TIA.

Regards,

JaaC

>
> Jerry
```
```Is this any help..

Just use complex multiplication..

X'(N+1)=X(N).P where P  = exp(j.2.pi.F/Fs)
|X| = 1 (nominally)

then normalise to keep magnitude stable..

delta = ((|X'|^2) - 1)/2  (delta is real)
X = X' - delta.X'

I've never generated such low frequencies though. My guess is you'd be
better off with 32 bit fixed point arithmetic (rather than floating
point). I think you'll need 32 bits because the phase change per sample
for O.O1 Hz at 44.1 KHz Fs is v.small (1.4E-6 radians according to my
calculations).

Also, I don't think you need anything fancy to calculate the sin and
cos of such small values, just use..
sin(x)=x
cos(x)=1-(x^2)/2

Regards
--

Jaime Andres Aranguren Cardona wrote:

> Hi, guys.
>
> I need your advice on the implementation of an LFO, with variable Fo
> (oscillation frequency), in the range 0.01Hz <= Fo <= 2.0 Hz, sampling
> at Fs = 44.1kHz.
>
> To be done with an ADSP-21065L in floating point (EzKit).
>
> Due to these ranges, a LUT (look up table) doesn't seem to be a viable
> solution.
>
> At this moment, I have implemented an oscillator based on the
> relation:
>
> cos(A+B) = 2cos(A)cos(B)-cos(B-A)
>
> With A = 2*pi*Fo/Fs
>
> For initialization, or when Fo is changed, I calculate cos(B) using
> 25th order McLaurin series, giving me an error of < 0.0007% for |x| <=
> PI/2... But there is a little, but significative problem: the smaller
> the value of Fo, the closer its cosine is to 1, and the oscillator
> doesn't oscillate at all!!! Even for Fo = 1.0, I don't get the right
> oscillation frequency, it's somewhat higher.
>
> However, I've found that for Fo >= 100 Hz. the oscillation frequency
> is exactly what is expected!!!!! I tried with Fo up to 20000 Hz, with
> no problemas at all.
>
> That makes me thing of using different approaches, coupled with my
> existing oscillator design, now running at higher ("valid") Fo:
>
> 1. Mixing its output with another oscillator and using the relation:
>
> cos(A)*cos(B) = 1/2[cos(A-B)+cos(A+B)]
>
> Then filtering to get rid of cos(A+B), and scaling. A and B should
> chosen in such a way that A-B = Fo. One drawback seems to be the fact
> that, due to the fact that Fo is really small, A and B should be very
> close, and I am not sure if the final effect will be to have an
> oscillator at exactly Fo.
>
> 2. Runnimng the oscillator at a frequency N times Fo, then
> downsampling by N.
>
> All of your opinions and suggestions are _VERY_ welcome.
>
> Regards,
>
> JaaC

```
```Adrian Hey <ahey@NoSpicedHam.iee.org> wrote in message news:<c1uhki\$7os\$1\$8302bc10@news.demon.co.uk>...
> Is this any help..
>
> Just use complex multiplication..
>
>         X'(N+1)=X(N).P where P  = exp(j.2.pi.F/Fs)
>                             |X| = 1 (nominally)
>
> then normalise to keep magnitude stable..
>
>   delta = ((|X'|^2) - 1)/2  (delta is real)
>   X = X' - delta.X'

Your suggestion seems to be interesting. However, I have a doubt: what
do you mean by X'? Maybe a dumb question, excuse me, please.

>
> I've never generated such low frequencies though. My guess is you'd be
> better off with 32 bit fixed point arithmetic (rather than floating
> point). I think you'll need 32 bits because the phase change per sample
> for O.O1 Hz at 44.1 KHz Fs is v.small (1.4E-6 radians according to my
> calculations).

Good suggestion. However, the rest of the processing is done in
floating poin format. I think it wont be a problem to do the LFO
generation in 32 bit, bixed point, then to use the assembler
instructions to switch the obtained values to floating point. Or I
could use 40 bit floating point (32 bit mantissa, 8 bit exponent)

>
> Also, I don't think you need anything fancy to calculate the sin and
> cos of such small values, just use..
>  sin(x)=x
>  cos(x)=1-(x^2)/2

Up to which values of x is this aproximation valid? My higher F will
be 2 Hz, equivalent to 2.85e-4 radians... I think it's still small
enough. but want to be sure.

>
> Regards
> --

JaaC
```
```> > At the frequencies that interest you, approximating cos(delta) as 1
> > and sin(delta) as delta might be completely acceptable.
>
> That's the good news, then!!!

Well, I knew they are acceptable as an aproximation... good news if
this aproximation works fine for the LFO. I'll try

JaaC
```
```Hello,

Jaime Andres Aranguren Cardona wrote:

> Adrian Hey <ahey@NoSpicedHam.iee.org> wrote in message
> news:<c1uhki\$7os\$1\$8302bc10@news.demon.co.uk>...
>> Is this any help..
>>
>> Just use complex multiplication..
>>
>>         X'(N+1)=X(N).P where P  = exp(j.2.pi.F/Fs)
>>                             |X| = 1 (nominally)
>>
>> then normalise to keep magnitude stable..
>>
>>   delta = ((|X'|^2) - 1)/2  (delta is real)
>>   X = X' - delta.X'
>
>
> Your suggestion seems to be interesting. However, I have a doubt: what
> do you mean by X'? Maybe a dumb question, excuse me, please.

X' is the un-normalised complex oscillator output. Assume has the
correct phase but (slightly) incorrect magnitude (due to finite
precision arithmetic and any small errors in |P|). Say..

X'=X.(1+delta) where |X|=1 and delta is a small scalar value

We want to calculate X from X'. Multiplying both sides by (1-delta)
X'.(1-delta)=X

So if we can calculate delta we can also calculate X from X'. We
|X'|^2 = (|X|^2).(1+2.delta) = 1+2.delta
so..
delta = ((|X'|^2)-1)/2

You could just use..

X = X'.(1-delta)

but the  (1-delta) factor may be >1, which would be unrepresantable in
a format like "1.31", so instead use..
X = X' - delta.X'

>> I've never generated such low frequencies though. My guess is you'd be
>> better off with 32 bit fixed point arithmetic (rather than floating
>> point). I think you'll need 32 bits because the phase change per sample
>> for O.O1 Hz at 44.1 KHz Fs is v.small (1.4E-6 radians according to my
>> calculations).
>
> Good suggestion. However, the rest of the processing is done in
> floating poin format. I think it wont be a problem to do the LFO
> generation in 32 bit, bixed point, then to use the assembler
> instructions to switch the obtained values to floating point. Or I
> could use 40 bit floating point (32 bit mantissa, 8 bit exponent)

I think 40 bit floating point should be as good as (but no better than)
32 bit fixed point. Normal single precision floating point (24 bit
mantissa) would be worse.

>>
>> Also, I don't think you need anything fancy to calculate the sin and
>> cos of such small values, just use..
>>  sin(x)=x
>>  cos(x)=1-(x^2)/2
>
> Up to which values of x is this aproximation valid? My higher F will
> be 2 Hz, equivalent to 2.85e-4 radians... I think it's still small
> enough. but want to be sure.

Well I dunno exactly. Your oscillator output won't be perfect, it will
have non-zero bandwidth due to imprecise arithmetic (which I guess you
could model as random phase drift in the output samples). It shouldn't
be to hard to quantify these effects (I won't try it here though).
But ultimately this, and your precision & stability requirements will
determine whether 32 bit arithmetic is good enough (and whether or not
the above approximations are good enough).

Regards
--