SmoothValue Timing

UrbanCyborg
Posts: 599
Joined: Mon Nov 15, 2021 9:23 pm

SmoothValue Timing

Post by UrbanCyborg »

Is there any way to find out if a SmoothValue object has timed out yet? I tried comparing GetSmoothValue()'s output with that of GetTargetValue(), but it doesn't seem to work correctly. On another note, what is the default time for SmoothValue()?

Reid
Cyberwerks Heavy Industries -- viewforum.php?f=76
ColinP
Posts: 953
Joined: Mon Aug 03, 2020 7:46 pm

Re: SmoothValue Timing

Post by ColinP »

Interesting. It would be nice to know exactly how SmoothValue works.

I just did a quick test comparing a SmoothValue object's output with the value of a knob that it's tracking and after the smoothing period the difference is zero. So my guess is that SmoothValue might be doing something like slew limitng rather than anything that produces an exponential/asymptotic decay.
User avatar
utdgrant
Posts: 541
Joined: Wed Apr 07, 2021 8:58 am
Location: Scotland
Contact:

Re: SmoothValue Timing

Post by utdgrant »

I attached a square wave LFO to R_Ware's Control and got it to wiggle the Out Level slider on Simple Amplifier (with 5V DC input).

This is the plot I recorded and opened inside Audacity:
SmoothValuePlot.jpg
SmoothValuePlot.jpg (42.95 KiB) Viewed 3385 times
This initially suggested an asymptotic curve to me, similar to an RC charge/discharge curve. However, when I zoomed in, it became apparent that the curve consisted of a series of straight-line interpolations. This was due to the Control module unconditionally sending out a new target value on a regular basis, so the slider position was generating a new Notify call, even if it hadn't changed. The default rate is 94 Hz. I reduced the Resolution control (knob Notify() call rate) down to 1Hz. This led to a single straight-line transition from one value to another:
SmoothValuePlotLinear.jpg
SmoothValuePlotLinear.jpg (43.56 KiB) Viewed 3385 times
Audacity reported the (default) transition time as being 25ms in length:
SmoothValuePlotLinearTimePeriod.jpg
SmoothValuePlotLinearTimePeriod.jpg (9.3 KiB) Viewed 3385 times
Note that this is a time value, not a rate value; the slope will be steeper for bigger jumps in value, and shallower for smaller jumps.

The main take-away for me is that if you perform a call to SmoothValue.SetValue(double value) before the previous smoothing period has elapsed, a new slope will be calculated from the current smoothed value to the new target value. Do that more frequently than the smooth time, and you will approach the target value asymptotically.
______________________
Dome Music Technologies
User avatar
utdgrant
Posts: 541
Joined: Wed Apr 07, 2021 8:58 am
Location: Scotland
Contact:

Re: SmoothValue Timing

Post by utdgrant »

It turns out that you can also set a rate value instead of a time value:

public void SetFixedTime​(double glideMilliseconds, double deltaValue)

Sets a fixed amount to glide to in a fixed amount of time. For example: SetFixedTime(1000, 1.0) will take 1 second to glide a distance of 1.0. Meaning a change from 0 to 5.0 would take 5 seconds.

Parameters:

glideMilliseconds - time in milliseconds.
deltaValue - the amount to change in glideMilliseconds.
______________________
Dome Music Technologies
ColinP
Posts: 953
Joined: Mon Aug 03, 2020 7:46 pm

Re: SmoothValue Timing

Post by ColinP »

Excellent work Grant. I was going to do more testing but you've saved me the time. :)

So it looks like it is calculating a delta when SetValue() is called and then just adding it every call to GetSmoothValue() until the target is hit. Presumably there's also some test to handle rounding error as the final value seems to be exactly right in my test.

However Reid reported that the end state didn't work correctly i.e. GetSmoothValue() != GetTargetValue() so I wonder what's going on there?

By the way I use y[ z ] = a * x[ z ] + ( 1 - a ) * y[ z - 1 ] sometimes to do smoothing and it produces the RC charge/discharge curve you showed. It's effectively a very simple one-pole IIR filter. But the asymptotic curve is often undesirable so the linear response makes more sense in this application as well as being cheaper providing the delta is only calculated at a low control rate.
UrbanCyborg
Posts: 599
Joined: Mon Nov 15, 2021 9:23 pm

Re: SmoothValue Timing

Post by UrbanCyborg »

Thanks mucho, guys. That really helps. I'm not sure why the difference isn't working in my case. Basically, I have a separate class and file that does the dirt in my main class, but doesn't have controls; those are in the main class and file. Sort of a Letter/Envelope pattern. So I'm doing a couple of kludges to make sure the final value for a slider in the outside class gets reported to the inner class eventually. If anyone has a better way of doing that, I'd love to hear it.

I'm not sure the test really doesn't work, because there's something else going on that I can't account for yet: on repeated reads one of my SmoothValue objects assumes successively larger values, actually moving away from the set value. This feels like one of those situations where you've made some (unknown) code change a while back that breaks a number of things, but sotto voce, so they didn't show up right away. Just love those. Anyway, thanks for the assist. You guys are the best.

Reid
Cyberwerks Heavy Industries -- viewforum.php?f=76
User avatar
utdgrant
Posts: 541
Joined: Wed Apr 07, 2021 8:58 am
Location: Scotland
Contact:

Re: SmoothValue Timing

Post by utdgrant »

ColinP wrote: Sun Aug 20, 2023 4:56 pm So it looks like it is calculating a delta when SetValue() is called and then just adding it every call to GetSmoothValue() until the target is hit. Presumably there's also some test to handle rounding error as the final value seems to be exactly right in my test.

However Reid reported that the end state didn't work correctly i.e. GetSmoothValue() != GetTargetValue() so I wonder what's going on there?
Well, I'm always wary of using the equivalence operator with any kind of floating point variables. My day job is in embedded software and I'm used to working to MISRA standards, so I automatically get a shudder when I see a test for (doubleA == doubleB). I suspect that if you blindly accumulate 48 * 25 (= 1200) deltas, there is the possibility that you could end up one LSB out.

In fact, I'm so paranoid about comparing doubles, I always use nested if statements rather than a switch statement when decoding a VoltageSwitch position! (It's stupid - I know that if you assign an integer to a double, it will be accurately held as an extact integer up to 52 bits. However, old habits die hard.)
EnsembleSwitch.jpg
EnsembleSwitch.jpg (21.8 KiB) Viewed 3364 times
______________________
Dome Music Technologies
User avatar
utdgrant
Posts: 541
Joined: Wed Apr 07, 2021 8:58 am
Location: Scotland
Contact:

Re: SmoothValue Timing

Post by utdgrant »

UrbanCyborg wrote: Sun Aug 20, 2023 6:35 pm I'm not sure the test really doesn't work, because there's something else going on that I can't account for yet: on repeated reads one of my SmoothValue objects assumes successively larger values, actually moving away from the set value.
I can only offer a couple of guidelines:

1. Ensure that you're constantly performing GetSmoothValue() every iteration of ProcessSample, even if you throw the value away. This is necessary to ensure that the delta values are added to the running smoothed value at the correct rate.
2. Ensure that you only perform SetValue() less frequently than the glide timeout period (25ms / 40 Hz by default). Otherwise, you'll get that asymptotic effect shown above, effectively NEVER reaching the target value until the heat death of the universe. :lol:
______________________
Dome Music Technologies
ColinP
Posts: 953
Joined: Mon Aug 03, 2020 7:46 pm

Re: SmoothValue Timing

Post by ColinP »

UrbanCyborg wrote: Sun Aug 20, 2023 6:35 pm I'm not sure the test really doesn't work, because there's something else going on that I can't account for yet: on repeated reads one of my SmoothValue objects assumes successively larger values, actually moving away from the set value.
I suspect you've got some code unexpectedly calling SetValue() on the SmoothValue object there as it's hard to see how you could get that behaviour otherwise.

utdgrant wrote: Sun Aug 20, 2023 6:59 pm In fact, I'm so paranoid about comparing doubles, I always use nested if statements rather than a switch statement when decoding a VoltageSwitch position! (It's stupid - I know that if you assign an integer to a double, it will be accurately held as an extact integer up to 52 bits. However, old habits die hard.)
Nothing wrong with being paranoid sometimes. I often write similar JUST IN CASE code. And given the recent discussion on thread-safety such practice may help hold together code that otherwise might wobble when something weird happens once in a blue moon.

Another thing worth mentioning for less experienced programmers than Grant and Reid is that when you print out values when debugging, sometimes the priniting functions round the values to so many decimal places so it's possible that a floating point value is very slightly off but the numbers you see don't reflect this.
UrbanCyborg
Posts: 599
Joined: Mon Nov 15, 2021 9:23 pm

Re: SmoothValue Timing

Post by UrbanCyborg »

ColinP: I suspect you've got some code unexpectedly calling SetValue() on the SmoothValue object there as it's hard to see how you could get that behaviour otherwise.
That's the odd thing; there's only one call to SetValue() on that object, made from the Notification() call for the control the smoother is attached to. There are a number of calls to GetSmoothValue() for the object in various places, but that shouldn't modify the smoother's value. I know! Must be quantum noise! :?

Reid
Cyberwerks Heavy Industries -- viewforum.php?f=76
Post Reply

Return to “Module Designer”