EDIT - Here's a new function that includes staying at 1.0 between outDuration
and the the next inDuration
. Note that I've changed your function signature - the input parameters are now inDuration
, holdDuration
, and outDuration
. The function stays at 0 between inDuration
and outDuration
for holdDuration
samples, then stays at 1.0 after outDuration
for another holdDuration
samples. The ramps are half-Hann functions again, you can change them as desired.
public static double Calculate(UInt64 currentCounter, uint inDuration, uint holdDuration, uint outDuration)
{
UInt64 curTime;
double ret;
curTime = currentCounter % (inDuration + 2*holdDuration + outDuration); //this wrapping should really be handled by the caller
if (curTime < inDuration)
{
ret = 0.5 * (1.0 - Math.Cos(2.0 * Math.PI * (inDuration - curTime) / (2.0 * inDuration)));
}
else if (curTime < inDuration + holdDuration)
{
ret = 0.0;
}
else if (curTime < inDuration + holdDuration + outDuration)
{
ret = 0.5 * (1.0 - Math.Cos(2.0 * Math.PI * (curTime - inDuration - holdDuration) / (2.0 * outDuration)));
}
else
{
ret = 1.0;
}
return ret;
}
This has the same periodicity features as the previous version.
Here's a graph showing two cycles of the function. The test loop was
for (ctr = 0; ctr < 20000; ctr++)
Calculate(ctr, 2500, 2250, 3000);
First version
I'm a big fan of the Hann function for stuff like that. It's continuous and differentiable, if that's a concern. Here's a simple implementation:
public static double Calculate(UInt64 currentCounter, uint duration, uint inDuration, uint outDuration)
{
UInt64 curTime;
double ret;
//should check that inDuration + outDuration <= duration
curTime = currentCounter % duration; //this wrapping should really be handled by the caller
if (curTime < inDuration)
{
ret = 0.5 * (1.0 - Math.Cos(2.0 * Math.PI * (inDuration - curTime) / (2.0 * inDuration)));
}
else if (curTime >= (duration - outDuration))
{
ret = 0.5 * (1.0 - Math.Cos(2.0 * Math.PI * (outDuration + duration - curTime) / (2.0 * outDuration)));
}
else
{
ret = 1.0;
}
return ret;
}
Here's a sample graph. This was generated with the loop
for (ctr = 0; ctr < 10000; ctr++)
Calculate(ctr, 10000, 2500, 3000);
The function descends from 1.0 to 0 from index 0
to inDuration
, stays at 0 until index duration-outDuration
, then ascends to 1.0 at index duration
, so it is exactly periodic in 'duration' samples.
I didn't understand your comment "Between out and in it is 1 for some time." Don't you need another parameter to specify the hold time?