SmoothValue Timing
-
- Posts: 625
- Joined: Mon Nov 15, 2021 9:23 pm
Re: SmoothValue Timing
It strikes me that it would be nice if SmoothValue either had a function to call to find out if it had converged, or, even better, the ability to attach a call-back function that would be called upon convergence. Unfortunately, the class has nothing like that, and doesn't inherit anything like that from its only parent, java.lang.Object.
As for not trusting every bit of a floating-point value, Grant, I first ran into that writing an integration routine for the IBM 1130, many, many moons ago. That machine had floats that had three undocumented bits that basically just inherited whatever was in core for that location previously (real core, too). But it doesn't hurt to be reminded, inasmuch as I was doing that test with a simple comparison. Guess all I can do in this case is make a SWAG as to how much precision is reasonable, and do an epsilon/delta kind of test.
Reid
As for not trusting every bit of a floating-point value, Grant, I first ran into that writing an integration routine for the IBM 1130, many, many moons ago. That machine had floats that had three undocumented bits that basically just inherited whatever was in core for that location previously (real core, too). But it doesn't hurt to be reminded, inasmuch as I was doing that test with a simple comparison. Guess all I can do in this case is make a SWAG as to how much precision is reasonable, and do an epsilon/delta kind of test.
Reid
Cyberwerks Heavy Industries -- viewforum.php?f=76
-
- Posts: 625
- Joined: Mon Nov 15, 2021 9:23 pm
Re: SmoothValue Timing
The weirdness never ends. I had moved the SmoothValue test and associated notification of changed value for the inner class to the GUI Timer notification, on the grounds that that was the sort of thing best left out of ProcessSample(). So in light of recent discussions, I moved it back into ProcessSample(). The drifting SmoothValue went away, and the test appears to work. For that, I am camping happily. However, I still have no idea why that would have made the difference it did. Color me confused and gibbering.
Reid
Reid
Cyberwerks Heavy Industries -- viewforum.php?f=76
Re: SmoothValue Timing
SmoothValue might be something quite simple like this...
Code: Select all
void SetValue( double targetValue )
{
target = targetValue;
delta = ( target - current ) / period;
}
double GetSmoothValue()
{
if( Math.abs( target - current ) <= Math.abs( delta ) )
current = target; // handle terminal rounding error
else
current += delta;
return current
}
Re: SmoothValue Timing
Every call to GetSmoothValue() has the side-effect of adding the delta value to the running total (As illustrated by Colin's speculative implementation).UrbanCyborg wrote: ↑Mon Aug 21, 2023 9:58 pm There are a number of calls to GetSmoothValue() for the object in various places, but that shouldn't modify the smoother's value.
This is why it must be called once (and only once) per ProcessSample(). If you need to refer to the smoothed value multiple times during one iteration of ProcessSample(), then copy the value to a local variable.
______________________
Dome Music Technologies
Dome Music Technologies
-
- Posts: 625
- Joined: Mon Nov 15, 2021 9:23 pm
Re: SmoothValue Timing
At this point, I've got a number of methods that piggyback on each other, but at the root of things depend on calls to GetSmoothValue(). Guess I need to rationalize that hierarchy to depend on one saved value. Still, that wouldn't explain why the drift went away when I moved one two-line bit of code into ProcessSample(), where it runs once (admittedly, with some possible repetitions internally).utdgrant: Every call to GetSmoothValue() has the side-effect of adding the delta value to the running total (As illustrated by Colin's speculative implementation).
This is why it must be called once (and only once) per ProcessSample(). If you need to refer to the smoothed value multiple times during one iteration of ProcessSample(), then copy the value to a local variable.
Reid
Cyberwerks Heavy Industries -- viewforum.php?f=76
-
- Posts: 625
- Joined: Mon Nov 15, 2021 9:23 pm
Re: SmoothValue Timing
Come to think of it, I doubt SmoothValue works that way, exactly. There's no reason GetSmoothValue() should modify the running total; that should be handled independently of any user-level call. Otherwise, a SmoothValue object that wasn't queried in some fashion for a while would never advance. And if there is an advance mechanism built-in, it would only be poor coding practice to have a side-effect modification. That's tantamount to misuse of a C-language preprocessor construct in a function call.
Reid
Reid
Cyberwerks Heavy Industries -- viewforum.php?f=76
Re: SmoothValue Timing
That's precisely what DOES happen. If you only call GetSmoothValue() when you want to actually use it, it will have only added one delta value since the last time, regardless of how much 'real time' has passed. That aspect bit me a few times when I started programming in VMD. You've got to watch out for conditional paths within ProcessSample(), too, in case a GetSmoothValue() call is skipped.UrbanCyborg wrote: ↑Tue Aug 22, 2023 6:59 pm Come to think of it, I doubt SmoothValue works that way, exactly. There's no reason GetSmoothValue() should modify the running total; that should be handled independently of any user-level call. Otherwise, a SmoothValue object that wasn't queried in some fashion for a while would never advance.
The safest construct I've found is to unconditionally call GetSmoothValue() for all smoothed variables right at the start of ProcessSample(), and assign the returned values to local variables. Use those local variables' values during the remainder of ProcessSample(). Additionally, if you want to use a smoothed value outside of ProcessSample() (in a branch of Notify(), for example), you will have to use a variable with wider scope. i.e. one that can be written to within ProcessSample() and then read within Notify().
______________________
Dome Music Technologies
Dome Music Technologies
Re: SmoothValue Timing
I had to make sure I wasn't going mad, so I knocked up a testbed module.
Increasing the value of the Divider knob will call SmoothValue.GetSmoothValue() once every dividerValue calls of ProcessSample().
Increasing the value of the Multiplier knob will call SmoothValue.GetSmoothValue() multiplierValue times for every call of ProcessSample().
Here is the body of ProcessSample()
And here is a video of it in action (no sound):
YouTube link
Glide time has been set to 1000.0ms (1.0 sec) instead of the default 25ms for demonstration purposes.
Increasing the value of the Divider knob will call SmoothValue.GetSmoothValue() once every dividerValue calls of ProcessSample().
Increasing the value of the Multiplier knob will call SmoothValue.GetSmoothValue() multiplierValue times for every call of ProcessSample().
Here is the body of ProcessSample()
Code: Select all
public void ProcessSample()
{
// add your own code here
int i;
dividerCount--;
if (dividerCount == 0)
{
dividerCount = dividerValue;
for (i=0; i<multiplierValue; i++)
{
latestSmoothedVoltage = smoothedVoltage.GetValue();
}
}
outputJack.SetValue(latestSmoothedVoltage);
}
YouTube link
Glide time has been set to 1000.0ms (1.0 sec) instead of the default 25ms for demonstration purposes.
______________________
Dome Music Technologies
Dome Music Technologies
-
- Posts: 625
- Joined: Mon Nov 15, 2021 9:23 pm
Re: SmoothValue Timing
That's amazing. Thanks for figuring that out; I'd never have guessed it, as I think I made pretty clear.
Reid
Reid
Cyberwerks Heavy Industries -- viewforum.php?f=76
Re: SmoothValue Timing
As I've said before, it took a lot of wailing and gnashing of teeth to work out what was happening when I first tried to use the SmoothValue class!UrbanCyborg wrote: ↑Wed Aug 23, 2023 12:47 am That's amazing. Thanks for figuring that out; I'd never have guessed it, as I think I made pretty clear.
I wanted to double-check my reasoning, so building a quick experiment was the only option.
______________________
Dome Music Technologies
Dome Music Technologies