带限表查找振荡器 C++

信息处理 过滤 海浪 振荡器
2022-02-19 21:54:29

我想创建一个带限表查找振荡器,其sin()功能与 C++ 中的函数非常相似,我将输入相位值并接收样本值。例如Sample s = saw(x);Sample s = square(x);

为了填充表格,我将首先生成一个过采样表,其中包含处于非频带受限状态的波的“X”因子。然后,我很可能通过某种 FIR 或 IIR 过滤器运行该表。然后我会以“X”因子抽取表格,然后希望有一个我可以从中读取的表格会产生频带限制信号。我还必须在表格中进行插值,以确保适应所有相位角。

我想知道这个理论是否可行?这意味着这会产生一个受频带限制的信号。

我将在下面模拟基本代码。

double saw(double phase){
    return interpolate(phase);//i know this is incomplete
}

double fillTable(){
    double table[size*oversampling];

    //fill table here. skipping for length of example

    for(int i =0;i<tableSize;++i){
        table[i]=filter(table[i]);
    }
    double table2[size];
    int x=0;
    for(int i =0;i<tableSize;++i){
        table2[i]=table[x];
        x+=oversampling;
    }
}

//usage
sample x = saw(phase);

我知道代码不完整且语法不正确,但我只想举例说明我希望能够做什么。

再说一遍。这会是乐队限制的吗?

2个回答

请注意,您不能使用纯(无状态)函数实现带限振荡器,例如:

Sample s = saw(x);

原因是函数必须知道 x 变化的速率才能生成具有正确带宽的信号

例如,假设您的采样率为 48kHz。如果您按此顺序调用您的函数:

saw(0.00000000);
saw(0.00000001);
saw(0.00000002);

您可以看到参数正在慢慢变化到别名不再是问题的程度,因此您的函数可能会返回类似的x / M_PI - 1内容(假设输入在 [0, 2 pi[ ; 输出在 [-1, 1] 中)而没有任何查找表。但是现在,如果你这样称呼它:

saw(0.0);
saw(3.0);
saw(6.0);

我们正在接近奈奎斯特频率,然后输出必须受到严重的频带限制——实际上更接近sin.

因此,仅通过原始锯的波形整形不能生成带限锯齿或正方形。您需要您的函数了解目标频率,以便做出正确的决定。

在您的代码中可以找到的另一个相关误解是您假设您只需要一个表。没有一种单一的“带限锯齿”波形适用于所有频率。对于低频,限带锯和朴素锯之间几乎没有区别。对于高频,带限锯实际上是一个正弦波。所以你必须定义你想为你的任务分配多少内存,并生成许多与各种频率相对应的带限表。在运行时,您可以根据信号的频率决定使用哪一个。如果这是一个音乐应用程序,您不想在音符音高上升时听到从一张桌子到另一张桌子的过渡,那么您 需要在此之上再添加一层插值,以从一张表交叉淡入到下一张表。一个典型的实现会使用一个八度或每 8 个半音的表。

请注意,如果用于填充表格的函数的频谱内容即使在更长的表格长度内也处于或高于奈奎斯特频率,则可能(可能会有)混叠噪声,随后的低通滤波将无法消除。与仅使用较短的表相比,混叠噪声的数量可能更少,但这取决于使用的表填充功能。

如果您打算使用此表产生周期性振荡,则必须将滤波器循环环绕在表周围,以考虑低通滤波器跨越周期边界的脉冲响应,否则最终会产生滤波器截断噪声。

更好的方法可能是计算您计划用来填充表格的周期函数的傅立叶系数,并使用这些系数通过仅将低于奈奎斯特的那些正弦分量(表格长度中的精确周期性)相加来合成表格表长度的频率。