(C++实现fft的方案)Matlab转C的方案总结

  • 导言
    • 方案对比
    • FFT翻译方案对比
    • C++的fft普通实现
    • 蝶形运算的fft
    • 注意

导言

 经过了很长一段时间的实验,总结下matlab转C给Qt使用的方案总结,这里的实验对象为matlab的fft函数。

方案对比

方案 基本原理 优点 缺点
matlab生成dll给qt调用 matlab将你写好的.m文件封装成.h.lib.dll,通过固定的调用步骤即api去调用它,这里生成的.h.lib相当于函数声明即入口,编译时会将其和我们的代码一起编译成exe,而.dll是函数具体实现,在运行时才会加载,而问题在于matlab生成的dll是很难避开matlab的库环境的,意思就是我们的dll文件是依赖于matlab的库 利于函数更新迭代,使用步骤简单,利于开发 当我们使用了matlab生成的dll,一般情况下客户机需要安装相应版本的matlab运行时库即删减版的matlab,但这样从用户的角度来看显然是不行的,且经过实验发现,qt环境调用matlab的dll存在较大问题,同样的环境配置的平台控制台程序能够调用,换成qt项目则出现未知错误
matlabCoder生成C源码 采用matlab自带的生成工具生成函数源码,源码包括使用样例,数据类型定义,数据检查,函数实现等 不依赖matlab的环境,可完全脱离matlab,速度和matlab相当甚至更快 源码可读性较差,奇怪变量较多,但代码严谨且巧妙值得学习,代码存在较大的冗余,我们正常情况下需要对其进行精简清晰(要先读很长一段时间)
根据公式自行翻译 根据公式采用实验对比进行转C 可读性好,与项目契合度高,利于后期迭代 速度绝大多数情况下是不如matlab的,即耗时长

FFT翻译方案对比

方案 基本原理 优点 缺点
根据公式老实翻译 复杂度为O(n2)数据量大时,尤其是频繁使用它时会慢的你怀疑人生 实现简单,根据公式来就行了 没经过算法优化的fft太慢
蝶形运算 具体原理百度,可以把复杂度降到O(nlogn) 速度显然更快,网上也很多代码实现 致命性缺点:限制输入长度必须是2的次幂大小的矩阵数组。且经过我在matlab的实验,扩充长度之后(补0),最后的数据是错误的
dobluestein算法 原理百度资料较少。大概是算出需要扩展的长度 并补0,算出sintab表和costab表,能力有限,希望有大侠教教我 ,这也是matlabCoder生成的源码的实际采用的算法 速度极快,无敌快,虽然可读性很差,但是matlab生成的C源码确实优化的很好,也有数据类型的功劳 自己实现难度较大,生成的源码可读性一言难尽

C++的fft普通实现

//快速傅里叶变换fftQVector<Complex> fft(const QVector<double> &real, const QVector<double> &imag) {/*real:向量实部imag:向量虚部这里仅实现对向量的快速傅里叶变换:Y = fft(X)计算公式可见matlab关于fft的介绍Y(k) = n∑(j=1) X(j)*Wn^(j-1)(k-1)X(j) = n∑(k=1)Y(k)*Wn^(j-1)(k-1)其中 Wn = e^((-2πi)/n) = cos(-2π/n)+sin(-2π/n)i*/QVector<Complex> out(real.size(), {0.0, 0.0});double fixed_factor = (-2 * PI) / real.size();for (int u = 0; u < real.size(); u++) {double uxf = u * fixed_factor;for (int x = 0; x < real.size(); x++) {//X(j)*Wn^(j-1)(k-1)double power = uxf * x;double temp = imag[x] * sin(power);out[u].real += real[x] * cos(power) - temp;out[u].imag += real[x] * sin(power) + temp;}}return out;}

蝶形运算的fft

#include <list>
#include <cmath>
#include <string>
#include <vector>
#include <iostream>#define PI acos(-1)
using namespace std;//定义复数结构
struct Complex
{double imag;double real;
};//复数乘法函数
Complex ComplexMulti(Complex One, Complex Two)
{//Temp用来存储复数相乘的结果Complex Temp;Temp.imag = One.imag * Two.real + One.real * Two.imag;Temp.real = One.real * Two.real - One.imag * Two.imag;return Temp;
}//此处的length为原序列的长度     将输入的任意数组填充,以满足快速傅里叶变换
void Data_Expand(double *input, vector<double> &output, const int length)
{int i = 1, flag = 1;while (i < length){i = i * 2;}//获取符合快速傅里叶变换的长度int length_Best = i;if (length_Best != length){flag = 0;}if (flag){//把原序列填充到Vector中for (int j = 0; j < length; ++j){output.push_back(input[j]);}}else{//把原序列填充到Vector中for (int j = 0; j < length; ++j){output.push_back(input[j]);}//把需要拓展的部分进行填充for (int j = 0; j < length_Best - length; j++){output.push_back(0);}}
}//此处的length为填充后序列的长度//将输入的实数数组转换为复数数组
void Real_Complex(vector<double> &input, Complex *output, const int length)
{for (int i = 0; i < length; i++){output[i].real = input[i];output[i].imag = 0;}
}//FFT变换函数//快速傅里叶变换函数
//input: input array
//StoreResult: Complex array of output
//length: the length of input array
void FFT(Complex *input, Complex *StoreResult, const int length)
{//获取序列长度在二进制下的位数int BitNum = log2(length);//存放每个索引的二进制数,重复使用,每次用完需清零list<int> Bit;//遍历序列的每个索引for (int i = 0; i < length; ++i){//flag用来将索引转化为二进制//index用来存放倒叙索引//flag2用来将二值化的索引倒序int flag = 1, index = 0, flag2 = 0;//遍历某个索引二进制下的每一位for (int j = 0; j < BitNum; ++j){//十进制转化为长度一致的二进制数,&位运算符作用于位,并逐位执行操作//从最低位(右侧)开始比较//example://a = 011, b1 = 001, b2 = 010 ,b3 = 100//a & b1 = 001, a & b2 = 010, a & b3 = 000int x = (i & flag) > 0 ? 1 : 0;//把x从Bit的前端压进Bit.push_front(x);//等价于flag = flag << 1,把flag的值左移一位的值赋给flagflag <<= 1;}//将原数组的索引倒序,通过it访问Bit的每一位for (auto it : Bit){//example:其相当于把二进制数从左到右设为2^0,2^1,2^2//Bit = 011//1: index = 0 + 0 * pow(2, 0) = 0//2: index = 0 + 1 * pow(2, 1) = 2//3: index = 2 + 1 * pow(2, 2) = 6 = 110index += it * pow(2, flag2++);}//把Data[index]从DataTemp的后端压进,其实现了原序列的数据的位置调换//变换前:f(0), f(1), f(2), f(3), f(4), f(5), f(6), f(7)//变换后:f(0), f(4), f(2), f(6), f(1), f(5), f(3), f(7)StoreResult[i].real = input[index].real;StoreResult[i].imag = input[index].imag;//清空BitBit.clear();}//需要运算的级数int Level = log2(length);Complex Temp, up, down;//进行蝶形运算for (int i = 1; i <= Level; i++){//定义旋转因子Complex Factor;//没有交叉的蝶形结的距离(不要去想索引)//其距离表示的是两个彼此不交叉的蝶型结在数组内的距离int BowknotDis = 2 << (i - 1);//同一蝶形计算中两个数字的距离(旋转因子的个数)//此处距离也表示的是两个数据在数组内的距离(不要去想索引)int CalDis = BowknotDis / 2;for (int j = 0; j < CalDis; j++){//每一级蝶形运算中有CalDis个不同旋转因子//计算每一级(i)所需要的旋转因子Factor.real = cos(2 * PI / pow(2, i) * j);Factor.imag = -sin(2 * PI / pow(2, i) * j);//遍历每一级的每个结for (int k = j; k < length - 1; k += BowknotDis){//StoreResult[k]表示蝶形运算左上的元素//StoreResult[k + CalDis]表示蝶形运算左下的元素//Temp表示蝶形运算右侧输出结构的后半部分Temp = ComplexMulti(Factor, StoreResult[k + CalDis]);//up表示蝶形运算右上的元素up.imag = StoreResult[k].imag + Temp.imag;up.real = StoreResult[k].real + Temp.real;//down表示蝶形运算右下的元素down.imag = StoreResult[k].imag - Temp.imag;down.real = StoreResult[k].real - Temp.real;//将蝶形运算输出的结果装载入StoreResultStoreResult[k] = up;StoreResult[k + CalDis] = down;}}}
}int main()
{//获取填充后的Data;vector<double> Data;//进行FFT的数据,此处默认长度为2的幂次方//double Datapre[] = {1, 2, 6, 4, 48, 6, 7, 8, 58, 10, 11, 96, 13, 2, 75, 16};double Datapre[] = { 100, 2, 56, 4, 48, 6, 45, 8, 58, 10 };//数据扩充Data_Expand(Datapre, Data, 10);//将输入数组转化为复数数组Complex array1D[16];//存储傅里叶变换的结果Complex Result[16];//变为复数形式Real_Complex(Data, array1D, 16);//快速傅里叶变换FFT(array1D, Result, 16);//基于范围的循环,利用auto自动判断数组内元素的数据类型for (auto data : Result){//输出傅里叶变换后的幅值cout << data.real << "\t" << data.imag << endl;}return 0;
}

注意

该文章仅个人学习使用,欢迎大家一起交流学习

(C++实现fft的方案)Matlab转C的方案总结相关推荐

  1. matlab最优方案,matlab中文【应对方案】

    喜欢使用电脑的小伙伴们一般都会遇到win7系统matlab中文的问题,突然遇到win7系统matlab中文的问题就不知道该怎么办了,其实win7系统matlab中文的解决方法非常简单,按照1:matl ...

  2. matlab fft谱分析实验报告,数字信号处理实验报告-FFT算法的MATLAB实现.doc

    数字信号处理实验报告-FFT算法的MATLAB实现.doc 数字信号处理 实验报告实验二FFT算法的MATLAB实现一.实验目的通过本实验的学习,掌握离散傅立叶变换的理论,特别是FFT的基本算法以及其 ...

  3. 计算机控制pud,控制系统状态空间实施方案计算机控制技术课程实施方案

    <控制系统状态空间实施方案计算机控制技术课程实施方案>由会员分享,可在线阅读,更多相关<控制系统状态空间实施方案计算机控制技术课程实施方案(12页珍藏版)>请在人人文库网上搜索 ...

  4. 启明云端方案分享| ESP32-S2 摄像头 WIFI方案应用于智能猫眼

    提示:启明云端从2013年起就作为Espressif(乐鑫科技)大中华区合作伙伴,我们不仅用心整理了你在开发过程中可能会遇到的问题以及快速上手的简明教程.同时也用心推出了基于乐鑫的相关应用方案!希望你 ...

  5. 计算机职业规划备选方案,大学生职业生涯规划-备选方案

    <大学生职业生涯规划-备选方案>由会员分享,可在线阅读,更多相关<大学生职业生涯规划-备选方案(7页珍藏版)>请在人人文库网上搜索. 1.职业规划的评估与备选49职业" ...

  6. 5G时代下的室内定位方案越来越精准-室内定位方案-新导智能

    剖析5G室内掩盖网络的根本需求,并提出室内定位方案,详细剖析其体系架构及作业原理.外场试点成果表明,混合组网计划具有智能运维.弱掩盖剖析.室内定位.人流量剖析.易于扩展.弹性扩容.室内定位精度到达3m ...

  7. 国产M0核风机量产程序开发方案… FOC电机控制开发方案…3电阻采样

    国产M0核风机量产程序开发方案- FOC电机控制开发方案-3电阻采样 出售一份基于国产M0核MCU平台, 风机量产程序,包含龙博格电机观测器,SVPWM,顺逆风启动,五段式与七段式调制等源码,完全可以 ...

  8. x小学计算机知识竞赛方案,竞赛方案精编小学竞赛方案

    小学可以开展的竞赛活动多种多样,以下是小编精心收集整理的小学竞赛活动,下面小编就和大家分享,来欣赏一下吧. 小学竞赛活动1 一.活动主题 思考,让生活更美好. 二.活动目的 1.通过这次活动,让更多同 ...

  9. 200瓦PFC方案200瓦pfc控制器方案,采用ucc28019a

    200瓦PFC方案200瓦pfc控制器方案,采用ucc28019a. 提供全套图纸. 编号:4730651783360342asdf2013_2229

最新文章

  1. 赵劲松:预知潜在风险,做化工安全科技创新的引领者
  2. SpringBoot 源码解析 —— SpringApplication 源码分析
  3. 虚拟机玩转缓存服务器,Nginx服务器中浏览器本地缓存和虚拟机的相关设置
  4. 华工软院17级“软件需求分析”课程大作业
  5. C#学习笔记——读写ini文件
  6. Spring boot 配置tomcat后 控制台不打印SQL日志
  7. python+flask编写一个简单的登录接口例子
  8. 关闭IE窗口时执行事件
  9. kafka中处理超大消息的一些考虑
  10. 计算机网络数据链路层之扩展以太网(含以太网交换机及虚拟局域网)
  11. python 多继承冲突_python:super()对多继承的影响
  12. msys64安装使用
  13. Deecamp20 项目提交【如何用pcdet(second)跑自己的数据】
  14. macpro如何清理磁盘空间_如何在Mac上清除磁盘空间(2020年最佳技巧)
  15. 全球知名虚拟服务器,国外十大虚拟主机
  16. java简单实现求平方根
  17. 新手实践:人生模拟器(1)
  18. 读书笔记---阶级逆袭——三代人的卵巢彩票
  19. 信息泄露能算高危漏洞吗
  20. Altium Designer 18 原理图编译出现off grid错误处理方法

热门文章

  1. 今日头条安卓_安卓手机运存越来越大,却还是不堪重负?一个APP开发者的自述...
  2. Mask RCNN详解
  3. 二叉搜索树(BST-Tree)(C++全)
  4. GB9706.1-2007+2020和IEC60601-1:2005 3.0+2012 3.1标准主要差异解析
  5. 李宏毅机器学习笔记(2016年的课程):Support Vector Machine (SVM)
  6. 微擎联动的小程序本地测试获取获取用户信息失败
  7. java基于SpringBoot+Vue+nodejs社区团购系统 element
  8. docker镜像latest具体是哪个版本
  9. 利用Animation控件制作帧动画过程详解
  10. 教你如何把“住房公积金”取出来?