Calculating 1/(1+x) on the FV-1

Algorithm development and general DSP issues

Moderator: frank

Post Reply
DrAlx
Posts: 25
Joined: Wed Feb 20, 2019 11:01 am
Location: Surrey, UK

Calculating 1/(1+x) on the FV-1

Post by DrAlx »

The log() and exp() functions on the FV-1 can be used to calculate roots and powers but doing an inverse (i.e raising something to the power of minus one) is not straightforward.
You cannot take a log(), multiply it by -1, and then do an exp() because the log() function on the FV-1
only works on numbers >0 and <=1, and the exp() function on the FV-1 only map numbers to the range >0 and <=1.
A number and its inverse will always lie on opposite sides of 1, so the log-->multiply-->exp procedure will fail.

Here is a trick I came up with for inversion (and therefore division) which may be of interest.

Let's say you need to calculate y in the following expression

y = 1 / (1 + A*x)

where x varies from 0 to 1, and A is a constant > 0.

The denominator (1 + A*x) in this case is always >1. The first part of the trick involves manipulation of the expression.

Define:

X = 1-x

and

B = A/(1+A)

and we can then write

y =(B/A) /(1 - B*X)

The denominator (1 - B*X) is now always <= 1, so we can apply the log() operation to it on the FV-1.
We cannot multiply the log by -1 and then exp the result for the reason mentioned at the top of this post.
So why do we want to log it?

Well 1/(1-B*X) is the derivative (with respect to X) of the curve -ln(1-B*X)/B.
We can approximate that derivative by looking at closely spaced points on the curve
(with X separated by some small value "delta") as follows

1/(1-B*X) = [ log2(1 - B*X) - log2(1 - B*X - B*delta) ] * ln(2) / ( B * delta )


So we get this final approximation:

1 / (1 + A*x) = [ log2(1 - B*X) - log2(1 - B*X - B*delta) ] * ln(2) / ( A * delta )


Note: log2() means "log to base 2" which is what the FV-1 implements,
and ln() is the natural logarithm.

=================================================================
Here's a worked example:

If we want to calculate y in the following expression

y = 1 / ( 1 + 9 * x ) where x varies from 0 to 1

then we have A = 9, so put

X = (1-x)
B = 9/(1+9) = 0.9
delta = 0.01
ln(2)/(A * delta) = 7.70163

giving this approximation which can be implemented on the FV-1.

y = 7.70163 * [ log2(1-0.9*X) - log2(1-0.9*X-0.09) ]

The approximation is extremely good, but gives slightly larger values of y (about 5% larger) near x = 0.
A smaller value of delta (e.g. 0.001) would increase accuracy but the multiplier
on the front gets larger (e.g. 77.0163) and require too many SOF scalings to implement.

Note that there is a natural scaling between A and delta. For example, if we scale up A by a factor of 11 (from 9 to 99), and scale down delta by the same factor (from 0.1 to 0.0909), then the overall accuracy of the approximation remains the same. In other words we can get a good approximation to

y = 1 / ( 1 + 99 * x ) where x varies between 0 and 1

by setting X = (1-x) and evaluating

y = 7.70163 * [ log2(1-0.99*X) - log2(1-0.99*X-0.009) ]

=================================================================



I came up with the above method when working on a phaser.
The feedback factor "k" for a digital all-pass filter
(with one delay element of time T) roughly relates to
an analog all-pass filter with RC time constant given by

RC = T/(1-k)

I wanted to model a sinusoidal variation in RC, so I
wanted (1-k) to vary like

A /( 1 + Bx )

with B > 0 and x varying sinusoidally from 0 to 1.
DrAlx
Posts: 25
Joined: Wed Feb 20, 2019 11:01 am
Location: Surrey, UK

Re: Calculating 1/(1+x) on the FV-1

Post by DrAlx »

I should have just looked on the Spin knowledge base. There is a much easier way.

1/(1+9x) with x = 0 to 1
= 0.1 / (0.1 + 0.9x)
= exp( log(0.1) - log(0.1+0.9x) )

No need for fancy approximations
Post Reply