SmoothValue Timing

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

Re: SmoothValue Timing

Post by UrbanCyborg »

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
Cyberwerks Heavy Industries -- viewforum.php?f=76
UrbanCyborg
Posts: 625
Joined: Mon Nov 15, 2021 9:23 pm

Re: SmoothValue Timing

Post by UrbanCyborg »

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
Cyberwerks Heavy Industries -- viewforum.php?f=76
ColinP
Posts: 1000
Joined: Mon Aug 03, 2020 7:46 pm

Re: SmoothValue Timing

Post by ColinP »

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 
}
User avatar
utdgrant
Posts: 625
Joined: Wed Apr 07, 2021 8:58 am
Location: Scotland
Contact:

Re: SmoothValue Timing

Post by utdgrant »

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.
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.
______________________
Dome Music Technologies
UrbanCyborg
Posts: 625
Joined: Mon Nov 15, 2021 9:23 pm

Re: SmoothValue Timing

Post by UrbanCyborg »

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.
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).

Reid
Cyberwerks Heavy Industries -- viewforum.php?f=76
UrbanCyborg
Posts: 625
Joined: Mon Nov 15, 2021 9:23 pm

Re: SmoothValue Timing

Post by UrbanCyborg »

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
Cyberwerks Heavy Industries -- viewforum.php?f=76
User avatar
utdgrant
Posts: 625
Joined: Wed Apr 07, 2021 8:58 am
Location: Scotland
Contact:

Re: SmoothValue Timing

Post by utdgrant »

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.
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.

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
User avatar
utdgrant
Posts: 625
Joined: Wed Apr 07, 2021 8:58 am
Location: Scotland
Contact:

Re: SmoothValue Timing

Post by utdgrant »

I had to make sure I wasn't going mad, so I knocked up a testbed module.
SmoothValueTestbed.jpg
SmoothValueTestbed.jpg (28.16 KiB) Viewed 9295 times
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);

}
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.
______________________
Dome Music Technologies
UrbanCyborg
Posts: 625
Joined: Mon Nov 15, 2021 9:23 pm

Re: SmoothValue Timing

Post by UrbanCyborg »

That's amazing. Thanks for figuring that out; I'd never have guessed it, as I think I made pretty clear. :oops:

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

Re: SmoothValue Timing

Post by utdgrant »

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. :oops:
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! :roll:
I wanted to double-check my reasoning, so building a quick experiment was the only option.
______________________
Dome Music Technologies
Post Reply

Return to “Module Designer”