如何实现这种振荡功能

时间:2009-11-28 08:47:49

标签: c# algorithm math

实现这种osscilation函数的快速方法是什么。 签名看起来像这样:

public static double Calculate(UInt64 currentCounter, uint duration, uint inDuration, uint outDuration)

结果应该是当currentCounter前进时的两倍,在0和1之间osscination。osscialtion speed由duration参数(单个oscclation的滴答数)定义。类似地,上升和下降速度通过inDUrationoutDurationinDUration + outDuration)来定义。

alt text http://img252.imageshack.us/img252/9457/graphuf.jpg

此图表的x轴当然是currentCounter

2 个答案:

答案 0 :(得分:2)

正如评论者指出的那样,你必须知道这些功能 程序结构类似于:

// 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;

如您所见,您必须填写InFunction()OutFunction() 它们都获得两个参数,即定义域中的x位置及其定义域。这样就可以很容易地实现这些功能。

修改
quadratic function可能是InFunction示例

double InFunction( uint current, uint range )
{
  return Math.Pow( ( current / range ) - 1, 2 );
}

通过将电流除以范围得到0到1之间的值 - 这将确保结果在0和1之间(如您所指定)。

答案 1 :(得分:1)

编辑 - 这是一个新功能,包括在outDuration和下一个inDuration之间保持1.0。请注意,我已更改了您的功能签名 - 输入参数现在为inDurationholdDurationoutDuration。对于inDuration个样本,函数在outDurationholdDuration之间保持为0,然后在outDuration之后对于另一个holdDuration样本保持为1.0。坡道再次是半汉族功能,你可以根据需要改变它们。

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;
}

它具有与先前版本相同的周期性功能。

这是显示该功能的两个周期的图表。测试循环是

for (ctr = 0; ctr < 20000; ctr++)
    Calculate(ctr, 2500, 2250, 3000);

alt text http://img16.imageshack.us/img16/4443/oscfnxn2.png

第一个版本
对于像这样的东西,我是Hann function的忠实粉丝。如果这是一个问题,它是连续的和可区分的。这是一个简单的实现:

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;
}

这是一个示例图表。这是通过循环生成的

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

函数从索引0下降到0到inDuration,保持为0直到索引duration-outDuration,然后在索引duration上升到1.0,所以它是在'持续时间'样本中完全是周期性的。

我不明白你的评论“在一段时间之间,它之间是1。”你不需要另一个参数来指定保持时间吗?