开发者

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?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜