QT下利用FFTW实现功率谱密度分析(周期图法)

写在前面

出于项目需求,需要在QT的msvc 2015编译环境下实现功率谱密度估计

所以这个需求很直接的关键词就是

1. C++

2. QT

3. 傅里叶变换

4. 功率谱密度估计

但是在网上搜索了很久,没有一个非常直接的答案。所以我觉得很有必要写一篇文章来说明,在QT msvc2015 32bit环境下如何实现功率谱密度估计

本文并没有经过严格编辑,但代码是已经可以跑通的,如果我的说明描述存在问题,请见谅。

环境 or 需求

Win7 64bit

QT msvc2015 32bit

FFTW3 ( fftw-3.3.5-dll32 )  官网:http://www.fftw.org/

QCustomPlot 官网:https://www.qcustomplot.com

正式开始

fftw3、qcustomplot、qt的使用方法以及功率谱密度估计的原理在这里就不赘述了,我们直奔主题——如何用代码实现。

原理

对于一个信号的功率谱密度估计,我采用的是originlab当中使用的原理,如下图:

(链接:https://www.originlab.com/doc/Origin-Help/FFT1-Algorithm)

代码

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "fftw3.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    int N = 10000; //采集点数目
    int Fs = 100000; //采集频率,这里是100kHz,也就是每隔10us采集一个点
    double sens = 1.90648; //这里是我项目里面的一个灵敏度因子,可以当作一个常数来看待

    QString fileName = "C:/Users/CMCS-LZC/Desktop/QT_vs_test_FFT/FFT_test/cmpms_test_D.txt"; //选择路径
    QFile file(fileName);
    QVector<double> array; //用来保存信号
    QVector<double> array_x; //画图的时候使用,array_x作为横坐标,array作为纵坐标
    if(file.open(QIODevice::ReadOnly))
    {
        QTextStream stream(&file);
        while(!file.atEnd())
        {
            double buf;
            QStringList list=stream.readAll().split("\n");
            QListIterator<QString> li(list);
            while(li.hasNext())
            {
                buf=li.next().toDouble();
                double temp = (buf/sens) * 1e-6 ;
                array.append(temp);
            }
        }
    }

    //进行傅里叶变换
    fftw_complex *in, *out;
    in = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * N);
    out = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * N);

    for (int i = 0; i < N; i++)
    {
        in[i][0] = array[i];
        in[i][1] = 0;
        array_x.append(i);
    }

    fftw_plan my_plan;
    my_plan = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
    fftw_execute(my_plan);

    QVector<double> data_power;
    QVector<double> data_power_x;
    QVector<double> data_freq;

    //功率谱密度估计
    for( int i = 82; i < 4905; i++) //这里的i的区间可以自由选择。
    {
        data_power.append((out[i][0] * out[i][0] + out[i][1] * out[i][1])/(Fs*N));
//        data_cali_psd_frequency.append((2*Pi*i)/(N*T));
        data_freq.append(i*10);
        data_power_x.append(i-82);
    }
    fftw_destroy_plan(my_plan);
    fftw_free(in);
    fftw_free(out);
    //傅里叶变换结束,功率谱密度估计计算结束

    // 求积分来计算弹簧系数
    int length_psd = data_power.length();
    double area = 0;
    for(int i = 0; i<(length_psd-1); i++)
    {
        area = area + 0.5 *( (data_freq[i+1]-data_freq[i]) * (data_power[i] + data_power[i+1]) );
    }
    qDebug()<<"area is "<<area;

    // 计算弹簧系数
    double k_b = 1.38 * 1e-23;
    double Temperature = 300;
    double springconstant = 0.764 * (k_b * Temperature ) / area ; // N/m ,锥形针0.764,矩形针0.817
    qDebug()<<"Spring Constant is "<<springconstant*1e3 <<"pN/nm";

    ui->plot_1->addGraph();
    ui->plot_1->graph(0)->setData(array_x, array);
    ui->plot_1->rescaleAxes(true);

    ui->plot_2->addGraph();
    ui->plot_2->graph(0)->setData(data_freq, data_power);
    ui->plot_2->rescaleAxes(true);

}

MainWindow::~MainWindow()
{
    delete ui;
}

运行结果

 结语

本文所做的功率谱密度估计使用的是周期图法,是实现起来较为简单的一种方法。

有任何问题,请说明来意,email(lzc2079@qq.com)给我。

 

 

 

  • 8
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
嗯,您想用C++fftw3库实现功率谱密度的计算,是吗?那么,我可以给您提供一个简单的示例代码,帮助您实现这个功能。 在使用fftw3计算功率谱密度之前,您需要了解一些基本的概念和步骤。在此简单介绍一下: 1. 读取音频数据:首先,您需要将音频数据读取到内存中,可以使用标准的C++文件读写函数来实现。 2. 进行FFT变换:使用fftw3库中提供的函数进行FFT变换,生成频域数据。 3. 计算功率谱密度:根据FFT变换得到的频域数据,计算其幅度的平方,即可得到功率谱密度。 以下是一个简单的示例代码,帮助您实现功率谱密度的计算: ``` #include <iostream> #include <fstream> #include <cmath> #include <fftw3.h> using namespace std; int main() { // 读取音频数据 ifstream fin("audio.dat", ios::binary); if (!fin) { cout << "Failed to open audio file!" << endl; return 1; } fin.seekg(0, ios::end); int size = fin.tellg(); fin.seekg(0, ios::beg); double* audio = new double[size / sizeof(double)]; fin.read((char*)audio, size); fin.close(); // 进行FFT变换 int N = size / sizeof(double); fftw_complex* in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * N); fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * N); fftw_plan plan = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE); for (int i = 0; i < N; i++) { in[i][0] = audio[i]; in[i][1] = 0; } fftw_execute(plan); fftw_destroy_plan(plan); fftw_free(in); // 计算功率谱密度 double* psd = new double[N]; for (int i = 0; i < N; i++) { psd[i] = pow(out[i][0], 2) + pow(out[i][1], 2); } fftw_free(out); // 输出结果 ofstream fout("psd.dat", ios::binary); fout.write((char*)psd, sizeof(double) * N); fout.close(); delete[] audio; delete[] psd; return 0; } ``` 在以上代码中,我们首先使用 ifstream 类从二进制文件中读取音频数据,然后使用 fftw3 库中的函数进行 FFT 变换,并计算功率谱密度。最后,将计算结果输出到二进制文件中。 请注意,以上代码仅供参考,您需要根据自己的实际情况进行修改和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值