正弦波,在给定时间内将频率从 f1 缓慢上升到 f2

问题描述 投票:0回答:5

我正在编写一个 C 程序来生成一个正弦波,该正弦波在给定的时间间隔内将频率从 f1 缓慢上升到 f2。

我编写了这个 C 程序来将频率从 0 斜坡到 10 Hz,但问题是频率在完成 360 度后发生变化。如果我尝试在 0 到 360 度之间更改频率,过渡会不平滑且突然。

这是我使用的 sin 方程 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. 如何在给定时间段内平滑地更改频率?
  2. 我应该研究傅立叶变换吗?
c++ c algorithm math waveform
5个回答
14
投票

如果您希望角频率 (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)
(如 oli 所说):

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 代码的输出(5 秒内 1-10Hz):

1-10 Hz 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)

顺便说一句,如果你正在听这个(或看着它 - 任何涉及人类感知的东西),我怀疑你不想要线性增长,而是指数增长。但这是另一个问题...


9
投票

如何在给定时间段内平滑地更改频率?

平滑的正弦曲线需要连续相位。相位是频率的积分,因此如果频率具有线性函数(即从 f1 到 f2 的恒定速率增加),那么相位将是时间的二次函数。

您可以用笔和纸算出数学公式,或者我可以告诉您所得到的波形称为 线性调频脉冲

我应该研究傅立叶变换吗?

线性调频脉冲的傅里叶变换本身就是线性调频脉冲,所以可能不是。


2
投票

应该相当简单。与其考虑改变频率,不如考虑让物体旋转得越来越快。 N 秒后它所行进的角距离可能是 X,但 2N 秒后将超过 2X(也许是 4X)。因此,提出一个角距离公式(例如,alpha = k1 * T + k2 * T**2),并取该角距离的正弦值来找到任意时间 T 处的波形值。


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

}

0
投票
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>

// This function generates a sine wave from a start frequency to an end frequency over a specified length of time.
// The output is a 16-bit integer stream representing the sine wave, written to stdout.
void generate_sine_wave(float start_freq, float end_freq, float length, int samplerate) {
    // Calculate the change in frequency per sample
    float delta_freq = (end_freq - start_freq) / (length * samplerate);
    float phase = 0.0;
    float freq = start_freq;

    // Generate each sample of the sine wave
    for (int i = 0; i < length * samplerate; i++) {
        // Calculate the current sample value
        float sample = sinf(2 * M_PI * freq * i / samplerate + phase);
        // Increment the frequency for the next sample
        freq += delta_freq;

        // Convert the sample value to a 16-bit integer and write it to stdout
        int16_t output = sample * INT16_MAX;
        fwrite(&output, sizeof(int16_t), 1, stdout);
    }
}

int main(int argc, char *argv[]) {
    // Check for the correct number of arguments
    if (argc != 5) {
        // If the number of arguments is incorrect, print a usage message and exit with an error code
        fprintf(stderr, "Usage: %s start_freq end_freq length samplerate\n", argv[0]);
        return 1;
    }

    // Parse the command-line arguments
    float start_freq = atof(argv[1]); // Start frequency in Hz
    float end_freq = atof(argv[2]); // End frequency in Hz
    float length = atof(argv[3]); // Length of the sine wave in seconds
    int samplerate = atoi(argv[4]); // Sample rate in Hz

    // Call the function to generate the sine wave
    generate_sine_wave(start_freq, end_freq, length, samplerate);

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.