德尔福和离散信号:获得固定静音的固定音量信号

时间:2011-12-13 13:31:51

标签: delphi signal-processing

这是我在此处How can I play a single tone or custom wave with Delphi?

提出的另一个问题的跟进

总而言之,我使用MMSystem的waveOutWrite()创建了一个离散信号,但它似乎没有像我预期的那样工作,或者我没有得到它。

我使用固定空格向缓冲区写了两个离散信号,如Samples[i] := round(vol*sin(2*Pi*AFreq*t));

对于信号,音量为1000,而“空格”为0伏特信号。

这就是我想要的东西,就像| ... | enter image description here

我收到Signal的所有错误还是我没有正确使用WinAPI?我希望每个固定信号在图上看起来都一样

P.S:我正在使用Windows的立体声混音,所以没有干扰 P.P.S:这是将Binary转换为Signal

的代码段
function CreateBinaryTone(BinaryString: String): TWaveformSamples;
var
  I: Integer;
  omega,
  dt: double;
  vol: double;
begin
  omega := 2*Pi*AFreq;
  dt := 1/Format.nSamplesPerSec;

  SetLength(Samples, Length(BinaryString));

  for I := 1 to Length(BinaryString) do
  begin
    { Discrete Time }
    Vol := StrToInt(BinaryString[I]) * 1000;
    Samples[I] := vol * sin(omega * dt * I);
  end;

  Result := Samples;
end;

2 个答案:

答案 0 :(得分:2)

您的位时间需要比载波(正弦)频率的周期长得多,并且采样率也需要超过载波频率的2倍。因此,您的样本生成循环可能需要更长的时间。

答案 1 :(得分:1)

我可能在这个线程上发布得很晚,但是,如果要点是创建一个可以产生离散而又连续的正弦/余弦信号而又不考虑时间的函数(例如没有可预测时间限制的实时操作),那很容易,但有效的方法!

首先,数学:

我们的朋友欧拉(Euler)为我们提供了一种使用复数描述正弦和余弦的方法。

Euler - Sin/Cos

通过在该方程式中添加时间变量,我们可以使其描述正弦波和余弦波

Euler - Sin/Cos Wave

在这个算术中,余弦波由该复数的实数部分表示 和我们的余弦波的虚部:

Euler - Actual Sin/Cos Presentation

现在,每次我们增加此时间变量时,就像我们将旋转量增加了一个小角度(我们称其为theta或θ)。这意味着我们下一步,与上一步具有一个角度加上这个小θ角

请记住,我们将ωt视为最后一步 θ的角度,作为需要添加的角度到最后一步的角度,以便生成新步骤

Euler - Next Step (1/2)

如果我们开发此等式的左侧,将会看到有趣的事情发生

Euler - Next Step (2/2)

我们知道,如果一个复数 z 与另一个复数 w 相等,则意味着它们的实部和虚部也相等。

Complex Numbers Equality

记住这一点,我们看到一个非常有趣的结论: 如果我们已经计算出了最后一步的正弦和余弦值,则可以通过添加此θ角来轻松地计算下一步,相应地使用以下方程式计算余弦和正弦值:

Euler - Next Step Calculation Equations

最后, 编码部分

现在,要创建这样的功能,您将需要一些东西:

  1. 2个全局双精度变量,表示最后一步的正弦和余弦
  2. 用于设置初始“步骤零”及其初始阶段的初始化函数
  3. 一个被调用并计算下一步的函数。

首先,声明:

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调用之前)以及每次您要重置wave时调用Init过程。

编辑:更正的图像+添加了被遗忘的初始化过程