0

我正在做一个项目,该项目需要我进行输入,执行 DFT(离散傅立叶变换),然后从这些值中获取零交叉的数量。

我编写了一个算法,但是,它使用复数,我不知道如何对它们进行操作/执行计算。这是代码:

#include <iostream>
#include <complex>
#include <vector>

using namespace std;

const double PI = 3.14159265358979323846;

vector< complex<double> > DFT(vector< complex<double> >& theData)
{
    // Define the Size of the read in vector
    const int S = theData.size();

    // Initalise new vector with size of S
    vector< complex<double> > out(S, 0);
    for(unsigned i=0; (i < S); i++)
    {
        out[i] = complex<double>(0.0, 0.0);
        for(unsigned j=0; (j < S); j++)
        {
            out[i] += theData[j] * polar<double>(2, (-2 * PI * i * j / S));
        }
    }

    return out;
}

int main(int argc, char *argv[]) {
    vector< complex<double> > numbers;

    numbers.push_back(128);
    numbers.push_back(127);

    vector< complex<double> > testing = DFT(numbers);

    for(unsigned i=0; (i < testing.size()); i++)
    {
        cout << testing[i] << endl;
    }
}

现在,如果我想执行例如:

if(testing[i] >= 0)
{
    // blah blah
}

然后它会返回一个错误。有什么想法或建议吗?是否可以在不使用复数的情况下创建 DFT?

4

4 回答 4

2

给你指示的人并没有告诉你在 DFT/FFT 的结果上计算零交叉。那将毫无意义。(如果他们告诉你这样做,他们是无能为力的。我允许你嘲笑他们给你如此荒谬的指示)。相反,他们告诉您计算原始数据的零交叉,并查看数据的 FFT。

然而,

  • 过零率是语音识别的一个非常糟糕的起点。也许你可以得到它的某个地方。稍微夸张一点,我可以说过零是你能做的最不稳健的 DSP 分析。不过也很简单,而且语音识别的研究已经进行了很长时间,所以说不定也有一些研究。更新/更正:这有点夸张。实际上我相信很多语音识别技术确实使用过零,但是你应该首先知道你在做什么,因为它不是很健壮并且对诸如倍频程错误等多种错误不敏感。当您使用过零时,最好先低通(可能是激进地)。一定要考虑其他因素。

  • 了解 FFT 的输出是这里经常被问到的问题,所以我写了一篇博客文章。通常人们会尝试跟踪音高,实际上您也应该这样做,但是您可以从 FFT 中获得其他信息,例如频率质心,以及在语音中很重要的不同频率的相对强度。从这里开始:http: //blog.bjornroche.com/2012/07/frequency-detection-using-fft-aka-pitch.html

  • 您可能还想考虑简单地过滤重要的语音频率(要找出这些是什么,请从“发音方式”的维基百科条目开始。例如,通过点击 Sibilant 的链接,您将了解到“[s] 有大约 8,000 Hz 的最大声学强度。Neeto!)您可以从 FFT 或通过过滤获得该信息。每个都有优点和缺点。您可能想查看语音识别文献以了解它们的用途。

于 2012-09-21T04:00:04.633 回答
0

傅里叶变换(例如DFT )返回复数,因此您无法真正绕过它们。

根据您的应用程序,您可以安全地忽略复数的虚部,并将 DFT 的输出视为实数序列。

您可以对复数执行大量操作。有些可能与您的应用程序相关,有些则不相关。花一些时间来更好地理解复数是值得的。

最后,,不使用复数是不可能创建 DFT 的。您可以将 DFT 的复数输出转换为实数,但在此过程中您会丢失信息。您需要了解复数以及 DFT 在您的应用程序中的使用方式,以便能够确定是否适合执行任何此类转换。

于 2012-09-20T20:05:55.943 回答
0

我有一个类似的问题,我放弃了对 C++ 复数双精度数使用向量容器,因为 FFT 库不能很好地支持它,最终使用了一个普通的旧数组。您会发现您尝试做的大部分事情都可以正常工作。

 std::complex<double>*  in=new std::complex<double> [N];

例如,所有算法都可以像使用任何其他数组一样工作,abs(in[i])或者in[i] *pi 只是确保使用数学库的 C++ 版本

对于您的具体问题,您必须检查C++ 参考,您可以使用 real 和 imag 函数来查看它是否大于零

然后确保(如果您使用 fftw)

对所有复数使用重新解释转换(如果它们是复数,则输入和输出)

    p = fftw_plan_dft_c2r_1d(N, reinterpret_cast<fftw_complex*>(in), out,FFTW_ESTIMATE);  

   fftw_execute(p);
于 2012-09-20T20:09:56.460 回答
0

DFT 将始终使用复数,至少对于其输出而言。如果输入描述了一段时间内的一些信号,那么输出描述了根据频率的信号。每个复数可以写成极坐标形式,然后分成表示幅度的绝对值和表示相位的角度。也许是您感兴趣的幅度;如果是这样,您将需要计算绝对值,但它们也都是非负的。

DFT有多种适用于实数的变体。在这方面,我想到了离散余弦变换。不确定这在您的应用程序中是否有用。

请注意,像FFTW这样的库可能会比您的代码更快地计算 DFT。只要您的输入大小是 2 的幂,即使是自写的FFT也可能值得考虑。但所有这些都与您的实际问题无关。

于 2012-09-20T20:11:32.240 回答