sine wave that slowly ramps up frequency from f1 t

2019-01-09 07:53发布

问题:

I'm writing a c program to generate a sinusoidal wave that slowly ramps up frequency from f1 to f2 for a giving time interval.

I have written this c program to ramp the frequency from 0 to 10 Hz but the problem is that the frequency changes after completion of 360 degrees. If I try to change the frequency between 0 and 360 degree that the transition is not smooth and it is abrupt.

This is the equation the sin that I have used y = Amplitude*sin(freq*phase)

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. How do I change frequency smoothly for a given time period?
  2. should I be looking into Fourier transformations?

回答1:

if you want angular frequency (w=2 pi f) to vary linearly with time then dw/dt = a and w = w0 + (wn-w0)*t/tn (where t goes from 0 to tn, w goes from w0 to wn). phase is the integral of that, so phase = w0 t + (wn-w0)*t^2/(2tn) (as oli says):

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

(where interval is tn and delta is t/tn).

here's the output for the equivalent python code (1-10Hz over 5 seconds):

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)

ps incidentally, if you're listening to this (or looking at it - anything that involves human perception) i suspect you don't want a linear increase, but an exponential one. but that's a different question...



回答2:

How do I change frequency smoothly for a given time period?

A smooth sinusoid requires continuous phase. Phase is the integral of frequency, so if you have a linear function for frequency (i.e. a constant-rate increase from f1 to f2), then phase will be a quadratic function of time.

You can figure out the maths with pen and paper, or I can tell you that the resulting waveform is called a linear chirp.

Should I be looking into Fourier transformations?

The Fourier transform of a linear chirp is itself a linear chirp, so probably no.



回答3:

It should be fairly simple. Rather than thinking of varying the frequency, think of making an object spin faster and faster. The angular distance it has traveled might be X after N seconds, but will be more that 2X (maybe 4X) after 2N seconds. So come up with a formula for the angular distance (eg, alpha = k1 * T + k2 * T**2) and take the sine of that angular distance to find the value of the waveform at any time T.



回答4:

+ (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);
}

}