Need help with log for 1/X block

Algorithm development and general DSP issues

Moderator: frank

Post Reply
Digital Larry
Posts: 338
Joined: Mon Nov 12, 2012 1:12 pm
Contact:

Need help with log for 1/X block

Post by Digital Larry »

I've always been really bad at the log/exp functions.

Here's what I'm trying to do.

I want a control that operates over a given range of the pot, but does not go to zero.

For example. if the ratio is 2, then pot 0->1 is output 0.5->1.0.
For a ratio of ten, Pot 0->1 maps to 0.1->1.0.

Now I also want another output that implements y = 1/(x * ratio).

So for example, as the pot is going from 0 to 1,
Output A goes linearly from 1/ratio to 1.0.
Output B follows y = 1/((output A)*ratio)

When pot = 0,
Output A = 1/ratio
Output B = 1

When pot = 1,
Output A = 1.0
Output B = 1/ratio

Here's my code fragment so far.

Code: Select all

rdax    input,1    ;read input signal 
sof	scale, offsetVal
wrax    fullRange,1    ;output to fullRange pin
log 1.0, logOffset
exp 1.99, -0.1875   [b]<<<====== ??????????[/b]
wrax    ratioOut,0    ;output to ratioOut pin
This is SpinCAD Builder code showing how scale and offfset are calculated from the given ratio invRatio.

Code: Select all

equ scale 0.2
// number1 is used in calculations
// get scale and offset for fullRange Output
equ number1 1.0
@divideDouble offsetVal number1 invRatio   // offsetVal = 1/invRatio
equ offsetVal 0.9
@minusDouble scale number1 offsetVal // scale = 1 - offsetVal
The variables such as scale, number1, and offsetVal have to be given initial values in order to maintain syntax. If they show up in a subsequent assignment, they'll be immediately overwritten.

Code: Select all

equ logOffset 0.4
@ratioToLogOffset logOffset invRatio 
ratioToLogOffset is an xtend function I just wrote that is like this:

Code: Select all

def genRatioToLogOffset(RatioToLogOffset mp) {
	'''
		double threshold = 1.0/«mp.ratio»;
		double «mp.varName» = Math.log(threshold) / (16 * Math.log(2.0));
	'''
}
This generates intermediate Java code that helps make the calculation.

We calculate the "threshold" as 1/ratio.
Then the code substitution winds up saying in essence,
logOffset = Math.log(threshold)/(16 * Math.log(2.0));
Which I THINK is how we get the FV-1 corrected base 2 log.

BUT that said, I am not dealing with the EXP instruction correctly. Under some circumstances, I do see the two outputs switching places, but the one using the 1/X function is not going the full width. I also tried:

Code: Select all

EXP 1.0, 0 
but that was even worse.

Maybe one of you nice people who knows these instructions better than I seem to can help? Don't worry about the SpinCAD Builder part of it. Even if I had two examples showing the right values for the log and exp coefficients, say for ratio = 2 and ratio = 10.

equ ratio 4
equ offsetVal 1/ratio
equ scale 1 - offsetVal

rdax input,1 ;read input signal
sof scale, offsetVal
wrax fullRange,1 ;output to fullRange pin
log AAA, BBB
exp CCC, DDD
wrax ratioOut,0 ;output to ratioOut pin


Thanks,

DL
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Re: Need help with log for 1/X block

Post by frank »

The important thing about LOG/EXP and POT ranging is to remember the following equations:

X^N = EXP2(N*LOG2(x))

1/X = X^(-1) = EXP2((-1)*LOG2(x))

If you want a POT to range A to B (where 0<A<B) as the POT ranges 0 to 1.0 then you need to do:
POT*(B - A) + A

Of course you need to make sure that all these things stay in range of the processing core so you may need to do some scaling to make it work.

I suggest reading AN 9 for the FXCore http://experimentalnoize.com/manuals/FX ... s/an-9.pdf which covers scaling in cases N is larger.
Frank Thomson
Experimental Noize
Digital Larry
Posts: 338
Joined: Mon Nov 12, 2012 1:12 pm
Contact:

Re: Need help with log for 1/X block

Post by Digital Larry »

Thanks Frank, it turns out that my example is really exactly the same as the one in the knowledge base. And while the description there is correct, it is very dense (for example some of it is explaining intermediate results of the LOG instruction, which is not obvious at first). I'd better write down more details because it took me about 12 years to get it! Also I struggle with text only descriptions. Draw a few graphs and it clears right up. Well okay 4 days later it started to.

Here's a patch which uses it.

So-called oil can delay where the LFO speed is supposed to sync with the delay time. My previous implementations of the inverse value to drive the LFO used the "SOF" function, which, while accurate at the endpoints, was not accurate anywhere else. Nobody ever called me out on it! But now I'm coming clean.

Here's the idea behind the "ratio" block. You choose a ratio, let's say 5 to 1.
There is a control input, nominally expected to go to a pot which ranges from 0 to 1. The first output goes from 1/ratio to 1.0. In this example, 1/5 = 0.2 to 1.0. So that is your ratio of 1 to 5. The second output is SUPPOSED to go from 1.0 to 1/ratio over the same output range. The curve it's supposedly implementing is y = 1/(ratio * x). You don't drive it from the pot. You drive it from the scaled linear output that doesn't go to zero.

Now just briefly, let's recall that, when followed by EXP 1.0, 0, the "C" parameter in LOG C,D performs "power" operations including square root and 1/x if C = -1.0. And "D" performs multiplication. And there is this magical "16" involved that you'd really better find a way to remember. So here, C = -1.0 and D = -1(log2(ratio)/16). Ratio going between, say, 2 and 100. The corresponding "Threshold" going between 0.5 and 0.01.

It embraces my credo of "possibly too much". For example if you crank the middle pot your sound will dissolve into distorted mush but you should be able to recover by backing off a bit. And the modulation width probably allows you to set more than you'd ever really want to use. Because I think people should get their money's worth, you know? Don't leave them hanging imagining how it would sound with TOO MUCH!

I'm going to do a bit more testing but it seems close.

DL

Code: Select all

; oil-can-with-2-LFOs-A.spcd - stereo output
; Patch saved from SpinCAD Designer version 1039
; Pot 0:  Delay time 133ms - 500 msec.  Turns the LFO speed down on two choruses attached to output taps which are a few msec apart.
; Pot 1: Feedback level.  Turns down delay level when all the way down.
; Pot 2: Modulation width.
; 
; 
; ----------------------------
;------ Pot 0
;------ Smoother
RDAX POT0,1.0000000000
RDFX REG0,0.0001500000
WRAX REG0,0.0000000000
;------ Ratio
RDAX REG0,1.0000000000
SOF 0.6666666667,0.3333333333
WRAX REG1,1.0000000000
LOG -1.0,-0.09906015629507227
EXP 1.0,0.0
WRAX REG2,0.0000000000
;------ Input
;------ Feedback Output
;------ Pot 2
;------ Scale/Offset
RDAX POT2,1.0000000000
SOF 0.9000000000,0.1000000000
WRAX REG4,0.0000000000
;------ Multiply
RDAX REG1,1.0000000000
MULX REG4
WRAX REG5,0.0000000000
;------ Pot 1
;------ ThreeTap
RDAX REG3,0.8912509381
MULX POT1
RDAX ADCL,1.0000000000
WRA 0,0.0
CLR
OR $007FFF00
MULX REG1
SOF 0.4753189087,0.0250473022
WRAX ADDR_PTR,0.0000000000
RMPA 1.0
WRAX REG6,0.0000000000
CLR
OR $007FFF00
SOF 0.4662878494,0.0245719833
WRAX ADDR_PTR,0.0000000000
RMPA 1.0
WRAX REG7,0.0000000000
;------ Chorus
SKP RUN ,1
WLDS 0,50,64
RDAX REG5,0.0078311260
WRAX SIN0_RANGE,0.0000000000
RDAX REG2,0.1968884540
WRAX SIN0_RATE,0.0000000000
LDAX REG6
WRA 16396,0.0
CHO RDA,0,REG | COMPC,16793
CHO RDA,0,0,16794
WRAX REG8,0.0000000000
;------ Phase_Invert
RDAX REG8,-1.0000000000
WRAX REG9,0.0000000000
;------ Clip
RDAX POT1,1.0000000000
SOF -2.0000000000,0.0000000000
SOF -2.0000000000,0.0000000000
SOF -1.5775000000,0.0000000000
SOF -1.0000000000,0.0000000000
WRAX REG10,0.0000000000
;------ LPF 1P
RDAX REG8,1.0000000000
RDFX REG12,0.3426232845
WRAX REG12,0.0000000000
;------ Scale/Offset
RDAX POT2,1.0000000000
SOF 0.5700000000,0.4300000000
WRAX REG13,0.0000000000
;------ Chorus
SKP RUN ,1
WLDS 1,50,64
RDAX REG5,0.0138833125
WRAX SIN1_RANGE,0.0000000000
RDAX REG2,0.3937769080
WRAX SIN1_RATE,0.0000000000
LDAX REG7
WRA 17192,0.0
CHO RDA,1,REG | COMPC,17757
CHO RDA,1,0,17758
WRAX REG14,0.0000000000
;------ Cube gain
RDAX REG12,1.0000000000
WRAX REG15,-0.9333300000
MULX REG15
MULX REG15
RDAX REG15,1.0000000000
SOF 1.5000000000,0.0000000000
WRAX REG16,0.0000000000
;------ HPF 1P
RDAX REG16,1.0000000000
RDFX REG18,0.0150000000
WRAX REG18,-1.0000000000
RDAX REG16,1.0000000000
WRAX REG17,0.0000000000
;------ FB In 2
RDAX REG17,0.9400000000
WRAX REG3,0.0000000000
;------ Multiply
RDAX REG13,1.0000000000
MULX REG10
WRAX REG19,0.0000000000
;------ Scale/Offset
RDAX REG19,1.0000000000
SOF 0.9200000000,0.0800000000
WRAX REG20,0.0000000000
;------ Mixer 4:2
RDAX ADCL,1.0000000000
WRAX REG21,0.0000000000
RDAX REG8,0.4466835922
MULX REG20
RDAX REG21,1.0000000000
WRAX REG21,0.0000000000
RDAX ADCR,1.0000000000
WRAX REG22,0.0000000000
RDAX REG14,0.4466835922
MULX REG20
RDAX REG22,1.0000000000
WRAX REG22,0.0000000000
;------ Output
RDAX REG21,1.0000000000
WRAX DACL,0.0000000000
RDAX REG22,1.0000000000
WRAX DACR,0.0000000000
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Re: Need help with log for 1/X block

Post by frank »

I think we are looking at a range issue here, if we look at your code:

Code: Select all

;------ Ratio
RDAX REG0,1.0000000000
SOF 0.6666666667,0.3333333333
WRAX REG1,1.0000000000
LOG -1.0,-0.09906015629507227
EXP 1.0,0.0
And assuming I understand it, the smoothed POT ranges from 0.333 to 0.999 which is then fed to the LOG/EXP block.
Assume POT= 0 so the value we get to LOG is 0.3333, then the steps taken are (and it has been a long time since I did this so I may be wrong):
LOG2(0.3333) is -1.584964
-1.584964 * -1.0 = 1.584964
1.584964 -0.0990601562950722 = 1.485904
EXP2(1.485904) = 2.800926
2.800926 > 1.0 so saturate to 1.0

You are doing a 1/X with the X < 1.0 so 1/X > 1.0 and when you convert back to linear from log you are saturating.

Note the "magical 16" is really to align the binary points as the result of a LOG operation is a S4.19 number so you need to supply a number in the same format to make sure all the bits align.
Frank Thomson
Experimental Noize
Digital Larry
Posts: 338
Joined: Mon Nov 12, 2012 1:12 pm
Contact:

Re: Need help with log for 1/X block

Post by Digital Larry »

>>>
LOG2(0.3333) is -1.584964
-1.584964 * -1.0 = 1.584964
1.584964 -0.0990601562950722 = 1.485904
EXP2(1.485904) = 2.800926
2.800926 > 1.0 so saturate to 1.0
>>>
Hi Frank,

I think what is missing here is the /16 step.

1.584964/16 = 0.09906025. That's pretty close to the 0.09906015-etc. and may be down to rounding error.

So with this value the adjusted log comes out to zero and the exp is one, but not saturation. Should be right at the threshold of where saturation occurs. The intention is to not have any saturation of the 1 /(ratio * x) over the full rotation of the pot, and I think this achieves that because you never let the input "x" (NOT the pot value) go below (1/ratio). Ratio = 3 in the code example.

DL
frank
Posts: 1244
Joined: Wed Oct 19, 2005 12:26 pm
Contact:

Re: Need help with log for 1/X block

Post by frank »

I never think of it as a /16, I always treat it as a log number being directly entered so try:

Code: Select all

;------ Ratio
RDAX REG0,1.0000000000
SOF 0.6666666667,0.3333333333
WRAX REG1,1.0000000000
LOG -1.0,-1.584964
EXP 1.0,0.0
Frank Thomson
Experimental Noize
Digital Larry
Posts: 338
Joined: Mon Nov 12, 2012 1:12 pm
Contact:

Re: Need help with log for 1/X block

Post by Digital Larry »

Hi Frank,

My code is actually working. I think there's probably something wrong with the SpinCAD simulation of either log or exp. I went back to the actual board. I dropped in two oscillators panned L/R that I programmed for about 4000 Hz. Then I added the ratio block, set ratio to 5, and sent the outputs to the frequency scale inputs of the oscillators.

If I record this into my DAW, then look at a spectral display, the high and low points change place (within visual resolution) when I move the pot from 0 to 1. As they are moving back and forth in the middle, they appear evenly distributed around a single center point on a log frequency display. I think this means the square root of their product is at that point.

The only thing I'm not quite sure about is why the output frequency doesn't go all the way to 4000, it's more like 3000. But maybe the oscillator itself is off or I'm not paying close enough attention to sample rates.

Caution, this code puts out full level sine waves.

Code: Select all

; ratio-test-2-oscillators.spcd
; null
; Pot 0: 
; Pot 1: 
; Pot 2: 
; 
; 
; ----------------------------
;------ Pot 0
;------ Ratio
RDAX POT0,1.0000000000
SOF 0.8000000000,0.2000000000
WRAX REG0,1.0000000000
LOG -1.0,-0.14512050593046014
EXP 1.0,0.0
WRAX REG1,0.0000000000
;------ Oscillator
SKP RUN ,3
WRAX REG2,0.0000000000
SOF 0.0000000000,-1.0000000000
WRAX REG3,0.0000000000
RDAX REG2,0.5355900000
MULX REG1
RDAX REG3,1.0000000000
WRAX REG3,-0.5355900000
MULX REG1
RDAX REG2,1.0000000000
WRAX REG2,0.0000000000
;------ Oscillator
SKP RUN ,3
WRAX REG4,0.0000000000
SOF 0.0000000000,-1.0000000000
WRAX REG5,0.0000000000
RDAX REG4,0.5355900000
MULX REG0
RDAX REG5,1.0000000000
WRAX REG5,-0.5355900000
MULX REG0
RDAX REG4,1.0000000000
WRAX REG4,0.0000000000
;------ Output
RDAX REG2,1.0000000000
WRAX DACL,0.0000000000
RDAX REG4,1.0000000000
WRAX DACR,0.0000000000

Post Reply