Синусоида, которая медленно увеличивает частоту от f1 до f2 в течение заданного времени

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

Я написал эту программу для увеличения частоты от 0 до 10 Гц, но проблема в том, что частота меняется после завершения 360 градусов. Если я попытаюсь изменить частоту между 0 и 360 градусами, то переход не будет плавным и будет резким.

Это уравнение грех, которое я использовал у = Амплитуда * грех (частота * фаза)

int main(int argc, char *argv[]) {

double y, freq,phase;
int count; // for convenience of plotting in matlab so all the waves are spread on x axis.
  for (freq = 0; freq < 10; freq+=1) {
      for (phase = 0; phase < 360; phase++) { // phase is 360 degrees
      y = 3 * sin((count*6.283185)+(freq*(phase*(3.14159/180))));   
    printf("%f %f %f \n", freq, phase, y);
   }
  count++;
  }
return EXIT_SUCCESS;
}
  1. Как плавно изменить частоту за определенный период времени?
  2. я должен смотреть на преобразования Фурье?

4 ответа

Решение

Если вы хотите, чтобы угловая частота (w=2 pi f) изменялась линейно во времени, то dw/dt = a а также w = w0 + (wn-w0)*t/tn (где t идет от 0 до tn, w идет от w0 в wn). фаза является интегралом этого, поэтому phase = w0 t + (wn-w0)*t^2/(2tn) (как говорит Оли)

void sweep(double f_start, double f_end, double interval, int n_steps) {
    for (int i = 0; i < n_steps; ++i) {
        double delta = i / (float)n_steps;
        double t = interval * delta;
        double phase = 2 * PI * t * (f_start + (f_end - f_start) * delta / 2);
        while (phase > 2 * PI) phase -= 2 * PI; // optional
        printf("%f %f %f", t, phase * 180 / PI, 3 * sin(phase));
    }
}

(где интервал равен tn, а дельта равна t/tn).

Вот вывод для эквивалентного кода Python (1-10 Гц в течение 5 секунд):

1-10 Гц в течение 5 секунд

from math import pi, sin

def sweep(f_start, f_end, interval, n_steps):
    for i in range(n_steps):
        delta = i / float(n_steps)
        t = interval * delta
        phase = 2 * pi * t * (f_start + (f_end - f_start) * delta / 2)
        print t, phase * 180 / pi, 3 * sin(phase)

sweep(1, 10, 5, 1000)

Кстати, если вы слушаете это (или смотрите на это - все, что связано с человеческим восприятием), я подозреваю, что вы хотите не линейное увеличение, а экспоненциальное. но это другой вопрос...

Как плавно изменить частоту за определенный период времени?

Гладкая синусоида требует непрерывной фазы. Фаза - это интеграл от частоты, поэтому если у вас есть линейная функция для частоты (то есть увеличение с постоянной скоростью от f1 до f2), то фаза будет квадратичной функцией времени.

Вы можете вычислить математику с помощью ручки и бумаги, или я могу сказать вам, что результирующий сигнал называется линейным чирпом.

Стоит ли искать преобразования Фурье?

Преобразование Фурье линейного ЛЧМ само по себе является линейным ЛЧМ, поэтому, вероятно, нет.

Это должно быть довольно просто. Вместо того, чтобы думать об изменении частоты, подумайте о том, чтобы заставить объект вращаться быстрее и быстрее. Угловое расстояние, которое он преодолел, может быть X через N секунд, но будет больше, чем 2X (может быть, 4X) через 2N секунды. Так что придумайте формулу для углового расстояния (например, alpha = k1 * T + k2 * T**2) и возьмите синус этого углового расстояния, чтобы найти значение сигнала в любое время T.

+ (void) appendChirp:(int[])sampleData size:(int)len 
    withStartFrequency:(double)startFreq withEndFrequency:(double)endFreq 
    withGain:(double)gain {

double sampleRate = 44100.0;

for (int i = 0; i < len; i++) {

    double progress = (double)i / (double)len;
    double frequency = startFreq + (progress * (endFreq - startFreq));
    double waveLength = 1.0 / frequency;

    double timePos = (double)i / sampleRate; 
    double pos = timePos / waveLength;
    double val = sin(pos * 2.0 * M_PI); // -1 to +1 

    sampleData[i] += (int)(val * 32767.0 * gain);
}

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