Как реализовать эту функцию колебаний - PullRequest
2 голосов
/ 28 ноября 2009

Какой бы быстрый способ реализовать эту функцию осцилляции. Подпись выглядела бы так:

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

И результат должен быть в два раза больше, чем по мере продвижения currentCounter, осцилляции между 0 и 1. Скорость осцилляции определяется параметром duration (число тактов для одного осцилляции). Точно так же скорость подъема и спуска определяется через inDUration и outDuration (inDUration + outDuration).

альтернативный текст http://img252.imageshack.us/img252/9457/graphuf.jpg

Ось X этого графика, конечно, будет currentCounter.

Ответы [ 2 ]

2 голосов
/ 28 ноября 2009

Как указывает комментатор, вы должны знать функции.
Структура программы будет выглядеть примерно так:

// 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 в области определения и область определения. Таким образом, должно быть легко реализовать функции.

EDIT:
Квадратичная функция может быть примером для вашего InFunction:

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

Делив ток на диапазон, вы получаете значение от 0 до 1, что также гарантирует результат от 0 до 1 (как вы указали).

1 голос
/ 29 ноября 2009

РЕДАКТИРОВАТЬ - Вот новая функция, которая включает в себя пребывание в 1,0 между outDuration и следующим inDuration. Обратите внимание, что я изменил вашу сигнатуру функции - теперь входные параметры inDuration, holdDuration и outDuration. Функция остается в 0 между inDuration и outDuration для holdDuration семплов, затем остается равной 1,0 после outDuration для других holdDuration семплов. Пандусы снова являются функциями Half-Hann, вы можете изменить их по своему усмотрению.

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

альтернативный текст http://img16.imageshack.us/img16/4443/oscfnxn2.png

Первая версия
Я большой поклонник функции Ханна для подобных вещей. Это непрерывно и дифференцируемо, если это проблема. Вот простая реализация:

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

График с длительностью = 10000, вход = 2500, выход = 3000 http://img269.imageshack.us/img269/2969/oscfnxn.png

Функция понижается с 1,0 до 0 с индекса 0 до inDuration, остается на 0 до индекса duration-outDuration, затем поднимается до 1,0 с индексом duration, поэтому она является точно периодической в ​​выборках продолжительности.

Я не понял вашего комментария "Между ними и в течение некоторого времени 1". Вам не нужен другой параметр для указания времени удержания?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...