我可能在此线程上发帖较晚,但是,如果重点是创建一个函数,该函数可以在不考虑时间的情况下生成离散但连续的正弦/余弦信号(例如,没有可预测时间限制的实时操作),那么很容易,但有效的方法来做到这一点!
首先是数学:
我们的朋友欧拉为我们提供了一种使用复数来描述正弦和余弦的方法。
Euler - Sin/Cos
通过在这个方程中添加一个时间变量,我们可以使它描述一个正弦波和一个余弦波
Euler - Sin/Cos Wave
在这个 ecuatoin 中,我们的余弦波由这个复数的实部表示
以及虚部的余弦波:
Euler - Actual Sin/Cos Presentation
现在,每次我们增加这个时间变量,就好像我们增加了一个小角度的旋转(我们称之为 theta 或 θ)。这意味着我们的下一步,应该有我们上一步的角度加上这个小 θ 角
请记住,我们会将 ωt 作为我们的 最后一步 的角度,将 θ 作为需要添加的角度到我们最后一步的角度,以便生成新的步骤。
Euler - Next Step (1/2)
如果我们开发这个等式的左边,我们会看到那里发生了一些有趣的事情:
Euler - Next Step (2/2)
我们知道,如果一个复数z与另一个复数w相等,这意味着它们的实部和虚部也相等。
Complex Numbers Equality
考虑到这一点,我们看到了一个非常有趣的结论:
如果我们已经计算了上一步的 Sine 和 Cosine,我们可以通过添加这个 θ 角轻松计算下一步,相应地使用以下等式计算余弦和正弦:
Euler - Next Step Calculation Equations
最后,
编码部分
现在,为了创建这样的功能,你需要一些东西:
- 2个全局,Double变量,呈现上一步的sin和cos
- 一个初始化函数,用于设置初始“零步”及其初始阶段
- 当被调用时计算并产生下一步的函数。
首先,声明:
private
[...]
sine_last_cos: double;
sine_last_sin: double;
cosine_last_cos: double;
cosine_last_sin: double;
procedure SineInit(starting_phase: double);
procedure CosineInit(starting_phase: double);
function SineGen(amplitutde: double; sampling_rate: Integer; Freq: Double): double;
function CosineGen(amplitutde: double; sampling_rate: Integer; Freq: Double): double;
接下来是实现:
procedure Tmain.SineInit(starting_phase: double);
begin
sine_last_sin := sin(starting_phase*pi/180); //given phase is in deg, not rad
sine_last_cos := cos(starting_phase*pi/180);
end;
procedure Tmain.CosineInit(starting_phase: double);
begin
cosine_last_sin := sin(starting_phase*pi/180);
cosine_last_cos := cos(starting_phase*pi/180);
end;
function Tmain.SineGen(amplitutde: double; sampling_rate: Integer; Freq: Double): double;
var sin_theta: double;
cos_theta: double;
new_sin_step, new_cos_step: double;
begin
sin_theta := sin(2*pi*Freq/sampling_rate); //theta depend on sampling freq
cos_theta := cos(2*pi*Freq/sampling_rate); //as well as desirable freq
new_cos_step:= sine_last_cos*cos_theta - sine_last_sin*sin_theta;
new_sin_step:= sine_last_cos*sin_theta + sine_last_sin*cos_theta;
sine_last_sin:= new_cos_step;
sine_last_cos:= new_sin_step;
result := amplitutde *new_sin_step;
end;
function Tmain.CosineGen(amplitutde: double; sampling_rate: Integer; Freq: Double): double;
var sin_theta: double;
cos_theta: double;
new_sin_step, new_cos_step: double;
begin
sin_theta := sin(2*pi*Freq/sampling_rate); //theta depend on sampling freq
cos_theta := cos(2*pi*Freq/sampling_rate); //as well as desirable freq
new_cos_step:= cosine_last_cos*cos_theta - cosine_last_sin*sin_theta;
new_sin_step:= cosine_last_cos*sin_theta + cosine_last_sin*cos_theta;
cosine_last_sin:= new_cos_step;
cosine_last_cos:= new_sin_step;
result := amplitutde *new_sin_step;
end;
在本例中,每次启动程序(也就是在第一次 SineGen/CosineGen 调用之前)以及每次您想要重置波形时都应调用 Init 过程。
编辑:更正图像 + 添加被遗忘的初始化程序