Найти начальную точку (время) каждого цикла в синусоиде

Я пытаюсь достичь синусоиды, постепенно меняющейся от 8Hz в 2Hz над 5 секунды:

IMG

Эта форма волны была создана в Cool Edit. Я дал ему стартовую частоту 8Hzконечная частота 2Hz и продолжительность 5 секунд. Синусоида постепенно изменяется от одной частоты к другой в течение заданного времени.

У меня вопрос, как я могу точно найти время начала каждого цикла (выделено красной точкой), используя цикл FOR?

Псевдокод:

time   = 5 //Duration
freq1  = 8 //Start frequency
freq2  = 2 //End frequency

cycles = ( (freq1 + freq2) / 2 ) * time //Total number of cycles

for(i = 0; i < cycles; i++) {
    /* Formula to find start time of each cycle */
}

1 ответ

Решение

Это обратное мышление для этой проблемы, которая приводит к безумию в программе. Не говоря уже о том, что отдельные волны не будут синусоидальными, потому что частота меняется (они будут слегка искажены), чего вы не достигнете с вашим генератором, а также очень мала вероятность того, что сигнал окончания остановится на нуле через 5 секунд. Вместо этого сделайте непрерывную волну греха с переменной частотой:

  1. Сначала вычислите фактическую частоту

    Подойдет линейная интерполяция (если вам не нужны другие изменения)

    f=f0+(f1-f0)*t/T
    

    где:

    f0=8 [Hz] start frequency
    f1=2 [Hz] stop frequency
    T =5 [s]  change time
    t =<0,T> is actual time in [s]
    
  2. вычислить данные синусоидальной волны

    for (t=0.0,angle=0.0;t<=T;t+=dt)
     {
     f=f0+((f1-f0)*t/T); // actual frequency
     signal=Amplitude*sin(angle); // your signal put it in a array or output somewhere ...
     angle+=6.283185307179586476925286766559*dt*f; // update phase
     while (angle>6.283185307179586476925286766559) // cut just to avoid floating rounding problems
      angle-=6.283185307179586476925286766559;
     }
    

    куда dt [s] это временной шаг, с которым вы хотите сэмплировать ваш сигнал. Если вы генерируете это в реальном времени и выводите в реальное HW, вы можете использовать timer или измерить время напрямую (с помощью performance counters в Windows или RDTSC или что у вас есть в распоряжении)

    Если вы получили заранее определенное количество образцов n для этого тогда

    dt=T/double(n-1);
    

    Вот пример вывода (n=image width):

    пример

    Если вам также нужно количество периодов, добавьте приращение счетчика внутри angle резать while loop И также есть ваша нулевая точка (но если частота выборки слишком мала или вам нужна высокая точность, вам нужно интерполировать реальную нулевую позицию).

Другие вопросы по тегам