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

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

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

fftw测试结果,

audacity输出结果:

源码如下:

#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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/262558.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

工业5G路由器提升驾考效率,实现智慧驾考物联网

为了提高驾考的考试效率&#xff0c;更好地服务广大学员&#xff0c;车管所驻考场监控中心结合物联网技术采用智慧驾考系统&#xff0c;实现考场监控、考试员远程监考、学员视频实时回传、自动评判等功能&#xff0c;为驾考公平公正安全提供保障。 该系统由智能监控管理平台和…

百模大战中的AI行业:新趋势与未来发展

文章目录 每日一句正能量前言技术进步应用拓展行业变革人才竞争后记 每日一句正能量 人生最重要的价值是心灵的幸福&#xff0c;而不是任何身外之物。 前言 随着科技的迅猛发展&#xff0c;人工智能&#xff08;AI&#xff09;已经成为引领技术革命的重要驱动力之一。在当前的…

使用Java实现合并两个数组[归并排序]

package org.example;import java.util.Scanner;public class incorporateSort {public static void main(String[] args) {Scanner scannernew Scanner(System.in);System.out.println("请输入第一个数组的长度和元素(数组内部必须为升序)");int len1scanner.nextIn…

基于Java SSM框架实现宜百丰超市进销存购物商城系统项目【项目源码+论文说明】

基于java的SSM框架实现宜百丰超市进销存购物商城系统演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被…

协作机器人(Collaborative-Robot)安全碰撞的速度与接触力

协作机器人&#xff08;Collaborative-Robot&#xff09;的安全碰撞速度和接触力是一个非常重要的安全指标。在设计和使用协作机器人时&#xff0c;必须确保其与人类或其他物体的碰撞不会对人员造成伤害。 对于协作机器人的安全碰撞速度&#xff0c;一般会设定一个上限值&…

Chart.js:灵活易用的图表库 | 开源日报 No.121

chartjs/Chart.js Stars: 61.3k License: MIT Chart.js 是一个简单而灵活的 JavaScript 图表库&#xff0c;适用于设计师和开发者。 灵活性&#xff1a;Chart.js 提供了丰富多样的图表类型和配置选项&#xff0c;使用户能够根据自己的需求创建各种定制化的图表。易用性&#…

Linux入门攻坚——9、Linux程序包管理-1

Linux程序包管理&#xff08;1&#xff09; 如何在Linux上安装、查询、卸载、升级程序&#xff08;对于使用者很重要的知识点&#xff0c;使用Linux就是要使用其上的程序&#xff0c;如果程序都安装不上&#xff0c;谈何使用&#xff09; 程序从源代码到最终能够执行的代码需…

SWUST-会理财的小明

一波操作之后我发现我在乱写&#xff0c;发现原来利息是这样算的 然后我一波操作之后发现也不是这样算的。原来利息是这样算的 原来是幂运算&#xff01; 什么东西。。。 原来总金额就是本金*&#xff08;1利率&#xff09;^年限。利息就是总金额-本金&#xff01;&#xff01…

2023.12.18 制作py,shell脚本进行数据库操作与定时任务

目录 虚拟机中已有的两个库: bi_db和shopnc_db 1.在pycharm中,使用pymysql,连接数据库进行增删改查操作 1.1 查询 1.2 修改 1.3 删除 1.4 增加 2.使用pandas,操作pycharm对数据库进行操作 2.1 对mysql进行覆盖写入 2.2 对mysql进行追加写入 3.在linux中,进行自动化定…

ardupilot开发 --- 风机不停机巡检 篇

在哪里创建的siyi实例&#xff1f; 如何传递飞控的时间戳给siyi相机&#xff1f; AP_RTC_ENABLED在waf编译时配置为1&#xff1f;&#xff1f; 如何配置&#xff1f; 在lua脚本中如何获取这个时间AP::rtc().get_utc_usec(utc_usec)&#xff1f;&#xff1f;&#xff1f; inclu…

FPC柔性排线用什么胶水能固定到线路板上?

为了固定FPC柔性排线到线路板上&#xff0c;可以使用特殊用于电子组装的胶水。常用的胶水类型有&#xff1a; 1.氰基丙烯酸酯胶水&#xff08;Cyanoacrylate&#xff09; 被称为“超级胶水”或“快干胶水”。这种胶水对FPC通常有很好的附着力。 2.环氧树脂胶水 环氧树脂胶水…

c 试水解码jpeg图片比特流

找到一张采用霍夫曼通用DC,AC编码表的图片&#xff0c;提取出此图片的比特流准备对它解码&#xff0c;再反推怎样编码。 下图是此图片比特流前100个字节。解码是每次读一字节&#xff0c;对这8比特解码&#xff0c;如8比特不能解码&#xff0c;再读入一字节。因为霍夫曼表最多…

html/css实现简易圣诞贺卡

一、前言 HTML&#xff0c;全称HyperText Markup Language&#xff0c;即超文本标记语言&#xff0c;是用于创建网页的标准标记语言。HTML是一种标记语言&#xff0c;由一系列的元素标签组成&#xff0c;用于描述网页的结构和内容。 CSS&#xff0c;全称是“层叠样式表”&#…

Solon 开源框架,单月下载突破 250 万!!!

Solon 是什么开源项目&#xff1f; 一个&#xff0c;Java 生态型应用开发框架。它从零开始构建&#xff0c;有自己的标准规范与开放生态&#xff08;历时六年&#xff0c;已有全球第二级别的生态规模&#xff09;。与其他框架相比&#xff0c;它解决了两个重要的痛点&#xff…

linux下的进程组与会话的区别

进程组&#xff08;Process Group&#xff09;和会话&#xff08;Session&#xff09;是Unix/Linux操作系统中的两个概念&#xff0c;它们之间有一些关键区别&#xff1a; 定义和范围&#xff1a;一个进程组是一组相关进程的集合&#xff0c;它们具有相同的进程组ID&#xff08…

变分自动编码器【03/3】:使用 Docker 和 Bash 脚本进行超参数调整

一、说明 在深入研究第 1 部分中的介绍和实现&#xff0c;并在第 2 部分中探索训练过程之后&#xff0c;我们现在将重点转向在第 3 部分中通过超参数调整来优化模型的性能。要访问本系列的完整代码&#xff0c;请访问我们的 GitHub 存储库在GitHub - asokraju/ImageAutoEncoder…

最新国内免费使用GPT4教程,GPT语音对话使用,Midjourney绘画

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和用户进行创作交流。 然而&#xff0c;GP…

JS模块化规范之ES6及UMD

JS模块化规范之ES6及总结 前言ES6模块化概念基本使用ES6实现 UMD(Universal Module Definition)总结 前言 ESM在模块之间的依赖关系是高度确定的&#xff0c;与运行状态无关&#xff0c;编译工具只需要对ESM模块做静态分析&#xff0c;就可以从代码字面中推断出哪些模块值未曾被…

在 Windows 上恢复已删除文件的 9 种简单方法

本教程讨论永久丢失数据的原因以及在 Windows上恢复已删除文件的不同方法&#xff1a; 数据是提供给系统的任何形式的信息。它可以是从密码到记事本文件的任何内容。数据是当今世界的关键要素&#xff0c;因为它使我们的生活变得轻松。 我们每天都变得越来越依赖数据&#xf…

括号匹配问题

括号匹配问题是一个在算法和数据结构中常见的问题&#xff0c;主要目标是通过检查输入的括号序列是否平衡和闭合&#xff0c;以确定它们是否匹配。这涉及到各种类型的括号&#xff0c;如圆括号、花括号和大括号。 解决括号匹配问题的一种常见方法是使用栈。当遇到一个左括号时…