解决使用傅里叶变换开源库fftw分析音频频谱结果与matlab或audacity不一致的问题

这篇具有很好参考价值的文章主要介绍了解决使用傅里叶变换开源库fftw分析音频频谱结果与matlab或audacity不一致的问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

找的一些demo输出结果与实际结果相差巨大,修复后效果如下:

采用一个采样率48000,精度16bit,单通道的46Hz,振幅为32767的正弦波测试(理论上应该得输出一个一模一样的正弦波)。输出如下图,可以看到和matlab或audacity差不多。

fftw测试结果,

fftw 处理音频,matlab,傅里叶分析

audacity输出结果:

fftw 处理音频,matlab,傅里叶分析

源码如下:

#include <iostream>
#include <fstream>
#include <fftw3.h>
#include <math.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stddef.h>
#include <sys/statvfs.h>

#include <time.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
uint64_t bag_get_boot_time() {
  struct timespec ts;

  uint64_t ret = 0;
  if(clock_gettime(CLOCK_MONOTONIC, &ts)!=0){
  //  LOGE(TAG,"CLOCK_GETTIME fatal ERR %s",strerror(errno));
    return 0;
  }
  ret  = (uint64_t)ts.tv_sec * 1000000U + ts.tv_nsec / 1000U;

  return ret;
}
uint64_t st;
uint64_t et1;
uint64_t et2;
// 读取WAV文件,并返回采样数据
bool readWavFile(const std::string& filename, double*& samples, int& sampleRate, int& numSamples)
{
    // 打开WAV文件
    std::ifstream file(filename, std::ios::binary);
    if (!file)
    {
        std::cerr << "无法打开WAV文件" << std::endl;
        return false;
    }
    // WAV文件头部格式(44字节)
    char header[44];
    file.read(header, 44);
    // 检查是否为PCM格式的WAV文件
    if (header[20] != 1)
    {
        std::cerr << "不支持非PCM格式的WAV文件" << std::endl;
        return false;
    }
    // 获取采样率和采样点数
    sampleRate = *(int*)&header[24];
    numSamples = *(int*)&header[40];
    numSamples = 4096;
    printf("--- %d %d\n",sampleRate,numSamples);
    // 分配内存并读取采样数据
    samples = new double[numSamples];
    
    // 读取16位有符号整型采样数据
    int16_t* buffer = new int16_t[numSamples];
    file.read((char*)buffer, sizeof(int16_t) * numSamples);
    st = bag_get_boot_time();
    // 转换为浮点型数据,并归一化到 [-1.0, 1.0] 范围内
    for (int i = 0; i < numSamples; ++i){
        samples[i] = static_cast<double>(buffer[i]) / 1.f;
      //  printf("%f ",samples[i]);
    }
    printf("\n");
    delete[] buffer;
    return true;
}
// 使用FFTW进行频域分析
void performFFT(const double* samples, int numSamples, int sampleRate)
{
    // 创建FFTW输入数组
    fftw_complex* in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * numSamples);
    // 创建FFTW输出数组
    fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * numSamples);
    // 创建FFTW计划
    fftw_plan plan = fftw_plan_dft_1d(numSamples, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
    // 将采样数据复制到输入数组中
    for (int i = 0; i < numSamples; ++i)
    {
        in[i][0] = samples[i];  // 实部
        in[i][1] = 0.0;         // 虚部(初始化为0)
    }
    // 执行频域变换
    fftw_execute(plan);
    // 输出频域结果(幅度谱)
    for (int i = 0; i < numSamples/2 ; ++i)
    {
        double frequency = static_cast<double>(i) * sampleRate / numSamples;
        double amplitude = sqrt(out[i][0] * out[i][0] + out[i][1] * out[i][1])*2/numSamples;
        std::cout << "频率:" << frequency << "Hz,振幅:" << amplitude ;
        printf(" db=%f %f %f\n",10*log10(amplitude/32768),out[i][0],out[i][1]);
    }
    // 清理内存和释放资源
    fftw_destroy_plan(plan);
    fftw_free(in);
    fftw_free(out);
}
int main()
{
    std::string filename = "/home/cf/myprj/shock_2.wav";
    double* samples;
    int sampleRate, numSamples;
   
    if (!readWavFile(filename, samples, sampleRate, numSamples))
        return 1;
    et1 = bag_get_boot_time();
    performFFT(samples, numSamples, sampleRate);
    et2 = bag_get_boot_time();
    printf("c1=%d c2=%d\n",et2-st,et1-st);
    delete[] samples;
    
    return 0;
}文章来源地址https://www.toymoban.com/news/detail-768024.html

到了这里,关于解决使用傅里叶变换开源库fftw分析音频频谱结果与matlab或audacity不一致的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 从傅里叶变换,到短时傅里叶变换,再到小波分析(CWT),看这一篇就够了(附MATLAB傻瓜式实现代码)

    本专栏中讲了很多时频域分析的知识,不过似乎还没有讲过时频域分析是怎样引出的。 所以本篇将回归本源,讲一讲从傅里叶变换→短时傅里叶变换→小波分析的过程。 为了让大家更直观得理解算法原理和推导过程,这篇文章将主要使用图片案例。 频谱分析可以告诉我们一

    2024年01月16日
    浏览(42)
  • Python中利用FFT(快速傅里叶变换)进行频谱分析

    本文将从实例的角度出发讲解fft函数的基本使用,不包含复杂的理论推导。 要对一个信号进行频谱分析,首先需要知道几个基本条件。 采样频率fs 信号长度N(信号的点数) 采样频率fs: 根据采样定理可知,采样频率应当大于等于被测信号里最高频率的2倍,才能保证不失真

    2024年01月17日
    浏览(51)
  • 使用 torch.stft 进行短时傅里叶变换

    python 常规的 stft 都是在 cpu 上进行计算,如果网络训练是在 GPU 上进行,那么就涉及到数据传输的问题,降低计算效率;而 torch 自带的 stft 可以直接在 GPU 上进行计算,因此可以节省计算时间。 运行结果如下:   根据结果可以发现输入跟短时傅里叶逆变换的的结果大小并不一

    2024年02月16日
    浏览(47)
  • Matlab信号处理3:fft(快速傅里叶变换)标准使用方式

    运行效果:

    2024年02月09日
    浏览(47)
  • [JavaScript]使用opencv.js实现基于傅里叶变换的频域水印(隐水印)

    PS:查了多方资料,都没有提到用 JavaScript 来实现频域水印的教程,故经过笔者的实践,遂写一篇教程来简单介绍。 通过了解频域水印的相关知识,我理解了频域水印就是先将图片进行傅里叶变换,得到频域图,然后将水印文字加到频域图中,在将频域图转换回去得到加了频

    2024年02月09日
    浏览(78)
  • 傅里叶级数和傅里叶变换之间的关系推理及应用

    傅里叶级数和傅立叶变换是傅里叶分析的两个主要工具,它们之间有密切的关系。 傅里叶级数是将一个周期函数分解为一系列正弦和余弦函数的和。它适用于周期性信号,可以将周期函数表示为一组振幅和相位不同的谐波分量的和。傅里叶级数展示了一个周期函数在不同频率

    2024年02月07日
    浏览(58)
  • python:使用Scikit-image对遥感影像进行傅里叶变换特征提取(fourier)

    作者:CSDN @ _养乐多_ 在本博客中,我们将介绍如何使用Scikit-Image来进行傅里叶变换特征提取(fourier),并且提供一个示例代码,演示了如何在单波段遥感图像上应用这些方法。 傅里叶变换特征提取是一种数学工具,用于将图像中的细节、纹理和边缘信息以不同频率的方式呈

    2024年02月07日
    浏览(49)
  • 傅里叶变换

    在计算机视觉中,有一个经典的变换被广泛使用——傅里叶变换。傅里叶变换是将时间域上的信号转变为频率域上的信号,进而进行图像去噪、图像增强等处理。 什么是时域(Time domain)?从我们出生,我们看到的世界都以时间贯穿,股票的走势、人的身高、汽车的轨迹都会

    2024年02月03日
    浏览(46)
  • 图傅里叶变换

    目录 什么是图信号? 如何理解图信号的”谱“? 图傅里叶变换是什么? 图傅里叶变换中特征值和图信号的总变差有什么关系? 让我们先总结一下,我们想要把图信号  正交分解到一组基  上; 那么怎么得到?可以通过对图的拉普拉斯矩阵 做特征分解得到,即. 于是   

    2024年02月06日
    浏览(43)
  • 【scipy 基础】--傅里叶变换

    傅里叶变换 是一种数学变换,它可以将一个函数或信号转换为另一个函数或信号,它可以将时域信号转换为频域信号,也可以将频域信号转换为时域信号。 在很多的领域都有广泛的应用,例如信号处理、通信、图像处理、计算机科学、物理学、生物学等。 它最大的功能是能

    2024年02月06日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包