How to implement this oscillation function
What would be a fast way to implent this osscilation function. A signature would look like this:
public static double Calculate(UInt64 currentCounter, uint duration, uint inDuration, uint outDuration)
And the result should be a double that as currentCounter advances, oss开发者_如何学JAVAciates between 0 and 1. The osscialtion speed is defines by the duration
parameter (the number of ticks for a single osccilation). Similarily the ascent and descent speed is defines via inDUration
and outDuration
(inDUration
+ outDuration
).
alt text http://img252.imageshack.us/img252/9457/graphuf.jpg
The x-Axis of this graph would of course be currentCounter
.
As the commenter points out, you have to know the functions.
The program structure would be something like:
// Use modulo to get the counter within the range of the first duration
var phaseCounter = currentCounter % duration;
// Use the appropriate function
if( phaseCounter < inDuration )
{
return InFunction( phaseCounter, inDuration );
}
if( phaseCounter > duration - outDuration )
{
// Normalize the phaseCounter to the domain of definition for OutFunction()
var outDurationOffset = duration - outDuration;
return OutFuntion( phaseCounter - outDurationOffset, outDuration );
}
return 0;
As you can see, you have to fill out InFunction()
and OutFunction()
.
They both get two parameters, the x position in their domain of definition and their domain of definition. This way it should be easy to implement the functions.
EDIT:
The quadratic function could be an example for your InFunction
:
double InFunction( uint current, uint range )
{
return Math.Pow( ( current / range ) - 1, 2 );
}
By dividing current by range you get a value between 0 and 1 - which will make sure that the result is between 0 and 1, too (as you specified).
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);
alt text http://img16.imageshack.us/img16/4443/oscfnxn2.png
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);
Graph with duration = 10000, in = 2500, out = 3000 http://img269.imageshack.us/img269/2969/oscfnxn.png
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?
精彩评论