C++数学函数生成

C++ mathematical function generation

本文关键字:函数 C++      更新时间:2023-10-16

在一个项目中,我遇到了准确生成各种波浪的需求。我原以为简单的正弦波是最容易开始的,但似乎我错了。我制作了一个简单的程序,生成样本的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的矢量可能会有一些问题,但这正是我的音频框架想要的,而且我对这种库缺乏经验,所以不知道会发生什么。

症状如下:

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

有人能就我可能做错了什么给出建议吗?

以下是我迄今为止所尝试的:

  • 制作我自己的正弦函数,以获得更高的精度。
    • 我对sin(x)使用了15次泰勒级数展开
  • 改变了采样率,从256到44100,在给定上述误差的情况下,听不到任何变化,波只是更加失真

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

我怀疑您向sin15x函数传递了不正确的值。如果你熟悉信号处理的基本原理,奈奎斯特频率是你可以忠实地重建(或在你的情况下构建)采样信号的最小频率。定义为信号中存在的最高频率分量的2x。

这对你的程序意味着,你需要在每个周期的最高频率的最后2个值,你想复制。在20Khz时,每秒需要40000个样本。看起来你只是在用值包装一个向量,并让播放程序对时间进行排序。

我们将假设您使用44.1Khz作为播放采样频率。这意味着一个产生1秒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
}

你需要除以频率,而不是相乘。为了看到这一点,以通过22050 Hz频率值的情况为例。对于i=0,你得到sin(0)=1。对于i=1,sin(3pi/2)=-1等等。这会给你一个1,-1,1,-1的重复序列…这是以44.1Khz采样的22050Hz波的正确表示。这在频率下降时有效,但每个周期会得到越来越多的样本。有趣的是,这并没有什么区别。以每个周期2个样本采样的正弦波与每秒采样1000次的正弦波一样精确地重新创建。这没有考虑噪音,但对于大多数目的来说,效果足够好。

我建议研究数字信号处理的基础知识,因为这是一个非常有趣的领域,理解起来非常有用。

编辑:这假设所有这些参数都被计算为浮点数。

从根本上说,您缺少了一条信息。您没有指定要采集样本的时间。这也可以被认为是您的系统播放样本的速率。不过,就目前而言,大致朝着这个方向走会让你离得更近。

samples.push_back(amp * std::sin(M_PI / freq *i));