C++数学函数生成

标签 c++ math trigonometry

在从事一个项目时,我发现需要准确地生成各种波浪。我认为简单的正弦波是最容易开始的,但看来我错了。我制作了一个简单的程序,它生成样本的 vector,然后播放这些样本,以便用户听到波形,作为测试。相关代码如下:

vector<short> genSineWaveSample(int nsamples, float freq, float amp) {
  vector<short> samples;
  for(float i = 0; i <= nsamples; i++) {
    samples.push_back(amp * sinx15(freq*i));
  }
  return samples;
}

我不确定这是什么问题。我知道由 short 组成的 vector 可能存在一些问题,但这正是我的音频框架想要的,而且我对这种库没有经验,所以不知道会发生什么。

症状如下:

  • 频率不正确
    • 即:给定 freq=440,A4 不是播放的音符
  • 奇怪的扭曲
    • 大多数频率不会产生干净的波。 220、440、880都是干净的,其他大部分都是失真的
  • 大部分频率都大幅上移

任何人都可以就我可能做错的地方提出建议吗?

这是我到目前为止尝试过的:

  • 制作我自己的正弦函数,以获得更高的准确性。
    • 我对 sin(x) 使用了 15 次泰勒级数展开
  • 更改了采样率,从 256 到 44100 之间的任何值,考虑到上述错误,听不到任何变化,波形只是更加失真。

谢谢。如果有任何信息可以帮助您,我将有义务提供。

最佳答案

我怀疑您向 sin15x 函数传递了不正确的值。如果您熟悉信号处理的基础知识 Nyquist frequency是您可以忠实地重建(或在您的情况下构造)采样信号的最小频率。定义为信号中存在的最高频率分量的 2 倍。

这对您的程序意味着,您需要在每个循环中为您想要重现的最高频率至少提供 2 个值。在 20Khz 下,您每秒需要 40,000 个样本。看起来您只是在用值打包一个 vector ,然后让回放程序整理时间。

我们假设您使用 44.1Khz 作为播放采样频率。这意味着产生一秒钟 1kHz 波的代码片段看起来像

DataStructure wave = new DataStructure(44100) // creates some data structure of 44100 in length

for(int i = 0; i < 44100; i++)
{
  wave[i] = sin(2*pi * i * (frequency / 44100) + pi / 2) // sin is in radians, frequency in Hz
}

您需要除以频率,而不是乘法。要看到这一点,请以传递 22,050 Hz 频率值的情况为例。对于 i = 0,您得到 sin(0) = 1。对于 i = 1,sin(3pi/2) = -1 等等。这为您提供了 1、-1、1、-1... 的重复序列,这是以 44.1Khz 采样的 22,050Hz 波的正确表示。这在您降低频率时起作用,但每个周期获得越来越多的样本。有趣的是,这并没有什么不同。每个周期采样 2 个样本的正弦波与每秒采样 1000 次的正弦波一样准确。这没有考虑噪音,但对于大多数用途来说效果很好。

我建议研究数字信号处理的基础知识,因为它是一个非常有趣的领域并且非常有助于理解。

编辑:这假设所有这些参数都被评估为 float 。

关于C++数学函数生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36962650/

相关文章:

sql - 编辑累积平均评级

linux - 在 bash 中将笛卡尔坐标转换为极坐标

ios - 如何将 UIStepper 值乘以 Textfield 值 ios?

python - 用公式计算反三角函数

c - GCC 使用的函数 rem_pio2f() 是什么?

c++ - 子目录中带有 protobuf 文件的 CMake

c++ - 如何修复错误 : unknown type name ‘namespace’

c++ - 从字符串中删除空行c++

swift - SceneKit 相机围绕一个对象旋转

c++ - 如何停止在所有桌面上显示 C/C++ WINAPI 窗口?