我正在编写一个 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;
}
如果您希望角频率 (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):
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 的恒定速率增加),那么相位将是时间的二次函数。
您可以用笔和纸算出数学公式,或者我可以告诉您所得到的波形称为 线性调频脉冲。
我应该研究傅立叶变换吗?
线性调频脉冲的傅里叶变换本身就是线性调频脉冲,所以可能不是。
应该相当简单。与其考虑改变频率,不如考虑让物体旋转得越来越快。 N 秒后它所行进的角距离可能是 X,但 2N 秒后将超过 2X(也许是 4X)。因此,提出一个角距离公式(例如,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);
}
}
#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;
}