The Spin auto-wah peak detector, part II

I really was hoping that this would be a tidy two parter... that I would have it all figured out by the time I started... but no. I'm still not quite sure what's going on in this code and so for this part at least, I am heavily guessing. Ultimately I will probably attach my scope to the FV-1 dev board and put some test signals in. I might try the simulator in SpinCAD (ElmGen, to be more accurate) but I'm not 100% sure it works correctly in all cases.

Caveats aside, last time, we finished off with the peak detector.

  • rdax lavg,1

  • wrax temp,0

  • rdax avg,1

  • maxx temp,1 ;filter a long average

  • wrax lavg,1

avg is the register of a 52.4 Hz corner frequency low pass filter. lavg is the register of a decay-only low pass filter with a feedback coefficient of 0.99999. I didn't do an exact calculation, but this decays to 20% of its initial value (100-20% fall time, not a standard used by anyone, but easy to calculate) in about 4 seconds at 32768 Hz sampling frequency. When I find my cheat sheet I'll add a more accurate analysis.

Because of the peak detector code, avg MIGHT be equal to lavg occasionally, but in general, it's going to be lower. So, avg <= lavg.

Here are the next few instructions.

  • sof 1,0.002 ;never let lavg go to zero

  • log 1,0

  • wrax temp,0

  • rdax avg,1

  • log 1,0

  • rdax temp,-1

  • mulx pot1

  • exp 1,0

The sof 1,0.002 instruction makes it so that the smallest value of ACC going into the log instruction is 0.002. A couple "whys" pop up here.

Why is it not sof 0.998, 0.002? Doing that would map the entire 0 - 1.0 range into 0.002 - 1.0. As it is, we just bumped it up and clipped off 0.002 of the top. It's not a big deal but one is left wondering why as it's just as efficient. I'll call this slightly adjusted lavg lavg'.

Also notice a few instructions later, we take the log of avg, but we do NOT add this offset. Intentional? Why? Why not? I don't know. I think this is a pretty big deal and it's nowhere near explained by the cryptic comments in the code.

Anyway, temp will now have the log of lower-range limited lavg.

Next, we get avg and take its log. We read the value of temp and multiply that by -1 and add to ACC. So ACC = (log(avg) - log(lavg')). That gets multiplied by pot1, and then we do an "exp" on that.

Let's just look at a couple limits, namely the endpoints. I'm going to assume that Pot1 goes to 1.0, even though it doesn't.

If pot1 = 0, then pot1 * (log(avg) - log(lavg')) = 0.

exp(0) = 1. So, with pot1 at zero, at the end of all this, regardless of the input signal, ACC = 1.0. It's probably important to realize that the output of exp is in S4.19 format. I just haven't figured out the significance yet.

If pot1 = 1.0, then ACC = exp(log(avg) - log(lavg')))

I know (or seem to remember) a couple of things.

  • exp(log(a) - log(b)) = a / b

So then after the exp command, ACC = avg/lavg'

That means we are dividing the peak value (which decays quickly) by the peak held slowly decaying value. When peaks are rising, these numbers track closely, but lavg' is 0.002 higher, so that ratio is a little less than 1.0. When the peak detector starts decaying, avg/lavg goes down. The next question is what is going on when there is no signal, and lavg' = 0.002.

I'm just going to leave it at that for now. I still don't quite get what is going on here. Maybe I did something wrong (I did, I just corrected it - I think). I've always had a hard time grasping the LOG and EXP instructions. So if you think you see a mistake somewhere, do let me know!

Last updated