Как создать пульсирующее значение из 0..1..0..1..0 и т. Д. Для заданной продолжительности? - PullRequest
2 голосов
/ 11 июня 2010

Я работаю над кодом, в котором у меня есть Time объект с членом time.Time.time дает мне время с момента запуска моего приложения в секундах (значение с плавающей запятой).Теперь я хочу создать пульсирующее значение от 0 до 1, а затем снова от 1 до 0, что будет продолжаться до тех пор, пока приложение не будет остановлено.передать его в качестве параметров для создания этого пульсирующего значения.

Как бы я создал это пульсирующее значение?

С уважением, Поллукс

Ответы [ 5 ]

12 голосов
/ 11 июня 2010

Вы упомянули об использовании sin (), так что, я думаю, вы хотите, чтобы он непрерывно пульсировал от 0 до 1.

Что-то вроде этого подойдет:

float pulse(float time) {
    const float pi = 3.14;
    const float frequency = 10; // Frequency in Hz
    return 0.5*(1+sin(2 * pi * frequency * time));
}

1/frequency = 0.1 second - это период между 1.

4 голосов
/ 11 июня 2010

Как насчет х = 1 - х?Или, если вы хотите, чтобы он основывался на времени, используйте Timer% 2

О, вам нужны значения от 0 до 1.как насчет Math.Abs ​​(100 - (Timer% 200)) / 100 Где таймер похож на DateTime.Now.TimeOfDay.TotalMilliseconds

Редактировать: Мои тесты показывают, что это большев два раза быстрее, чем метод Грех.Для 1 миллиона итераций метод sin занимает 0,048 секунды, а метод Abs - около 0,023 секунды.Кроме того, вы получаете разные формы волны из двух, конечно.Грех производит синусоидальную волну, а Абс - треугольную.

static void Main(string[] args)
{
   System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
   sw.Start();
   const int count = 1000000;
   float[] results = new float[count];
   for (int i = 0; i < count; i++)
   {
      results[i] = AbsPulse(i/1000000F);
      //results[i] = SinPulse(i / 1000000F);
   }
   sw.Stop();
   Console.WriteLine("Time Elapsed: {0} seconds", sw.Elapsed.TotalSeconds);
   char[,] graph = new char[80, 20];
   for (int y = 0; y <= graph.GetUpperBound(1); y++)
      for (int x = 0; x <= graph.GetUpperBound(0); x++)
         graph[x, y] = ' ';
   for (int x = 0; x < count; x++)
   {
      int col = x * 80 / count;
      graph[col, (int)(results[x] * graph.GetUpperBound(1))] = 'o';
   }
   for (int y = 0; y <= graph.GetUpperBound(1); y++)
   {
      for (int x = 0; x < graph.GetUpperBound(0); x++)
         Console.Write(graph[x, y]);
      Console.WriteLine();
   }
}

static float AbsPulse(float time)
{
   const int frequency = 10; // Frequency in Hz
   const int resolution = 1000; // How many steps are there between 0 and 1
   return Math.Abs(resolution - ((int)(time * frequency * 2 * resolution) % (resolution * 2))) / (float)resolution;
}

static float SinPulse(float time)
{
   const float pi = 3.14F;
   const float frequency = 10; // Frequency in Hz
   return 0.5F * (1 + (float)Math.Sin(2 * pi * frequency * time));
}
1 голос
/ 11 июня 2010

Я думаю, что синусоидальная функция была бы идеальной, но вам нужно отрегулировать период и масштаб.

Функция синус выдает результаты от -1 до 1, но вы хотите перейти от 0 до 1.Для правильного масштабирования вы хотите (sin(x)+1)/2.

Функция синуса начинается с нуля, переходит в 1 при пи / 2, снова в ноль при пи, -1 при 3 * пи / 2 и возвращается к нулю при2 * пи.Если масштабировать, то первый ноль будет при 3 * пи / 2, а первый максимум после этого будет при 5/2 * пи.Таким образом, x в предыдущей формуле равно (2*time + 3) * pi/2.

Собираем все вместе: (sin((2*time.time + 3) * pi/2) + 1) / 2

0 голосов
/ 11 июня 2010

Посмотрите на легкость функций. Они делают подобные вещи разными способами - линейными, поли, exp, sin и т. Д.

0 голосов
/ 11 июня 2010

Как часто вы хотите, чтобы он пульсировал?

Допустим, вы хотите перейти от 0 до 1 в течение 10 секунд.

float pulseValueForTime(int sec) {
    int pulsePoint = sec % 10;
    float pulsePercent = (float)pulsePoint / (float)10;
    float pulseInTermsOfPI = (pulsePercent * 2 * PI) - PI;
    float sinVal = MagicalSinFunction(pulseInTermsOfPI); // what framework you use to compute sin is up to you... I'm sure you can google that!
    return (sinVal + 1) / 2; // sin is between 1 and -1, translate to between 0 and 1
}
...