FFT算法(Java实现)

2023-11-05

FFT导论

转载自FFT导论


  • FFT是离散傅立叶变换的快速算法,可以将一个信号变换到频域。
  • 有些信号在时域上是很难看出什么特征的,但是如果变换到频域之后,就很容易看出特征了。这就是很多信号分析采用FFT变换的原因。另外,FFT可以将一个信号的频谱提取出来,这在频谱分析方面也是经常用的。

FFT物理意义

  • 一个模拟信号,经过ADC采样之后,就变成了数字信号。采样定理告诉我们,采样频率要大于信号频率的两倍。采样得到的数字信号,就可以做FFT变换了。

  • N个采样点,经过FFT之后,就可以得到N个点的FFT结果。为了方便进行FFT运算,通常N取2的整数次幂。

  • 假设采样频率为Fs,信号频率F,采样点数为N。那么FFT之后结果就是一个为N点的复数。每一个点就对应着一个频率点。这个点的模,就是该频率值下的幅值。

  • 具体跟原始信号的幅度有什么关系呢?假设原始信号的峰值为A,那么FFT的结果的每个点(除了第一个点直流分量之外)的模值就是A的N/2倍。而第一个点就是直流分量,它的模值就是直流分量的N倍。而每个点的相位呢,就是在该频率下的信号的相位。

  • 第一个点表示直流分量(即0Hz),而最后一个点N的再下一个点(实际上这个点是不存在的,这里是假设的第N+1个点,也可以看做是将第一个点分做两半分,另一半移到最后)则表示采样频率Fs,这中间被N-1个点平均分成N等份,每个点的频率依次增加。例如某点n所表示的频率为:

Fn=(n-1)*Fs/N。

  • 由上面的公式可以看出,Fn所能分辨到频率为为Fs/N,如果采样频率Fs为1024Hz,采样点数为1024点,则可以分辨到1Hz。1024Hz的采样率采样1024点,刚好是1秒,也就是说,采样1秒时间的信号并做FFT,则结果可以分析到1Hz,如果采样2秒时间的信号并做FFT,则结果可以分析到0.5Hz。**如果要提高频率分辨力,则必须增加采样点数,也即采样时间。**频率分辨率和采样时间是倒数关系。

假设FFT之后某点n用复数a+bi表示,那么这个复数的模就是

An=sqrt(a^2+ b^2),

相位就是

Pn=atan2(b,a)

根据以上的结果,就可以计算出n点(n≠1,且n<=N/2)对应的信号的表达式为:

An/(N/2)*cos(2*pi*Fn*t+Pn),即2*An/N*cos(2*pi*Fn*t+Pn)

对于n=1点的信号,是直流分量,幅度即为A1/N。

由于FFT结果的对称性,通常我们只使用前半部分的结果,即小于采样频率一半的结果。

实例说明

下面以一个实际的信号来做说明。假设我们有一个信号,它含有2V的直流分量,频率为50Hz、相位为-30度、幅度为3V的交流信号,以及一个频率为75Hz、相位为90度、幅度为1.5V的交流信号。用数学表达式就是如下:

S=2+3cos(2pi50t-pi30/180)+1.5cos(2pi75t+pi90/180)

式中cos参数为弧度,所以-30度和90度要分别换算成弧度。

我们以256Hz的采样率对这个信号进行采样,总共采样256点。按照我们上面的分析,Fn=(n-1)*Fs/N,我们可以知道,每两个点之间的间距就是1Hz,第n个点的频率就是n-1。我们的信号有3个频率:0Hz、50Hz、75Hz,应该分别在第1个点、第51个点、第76个点上出现峰值,其它各点应该接近0。从图中我们可以看到,在第1点、第51点、和第76点附近有比较大的值。我们分别将这三个点附近的数据拿上来细看:

1点: 512+0i

2点: -2.6195E-14 - 1.4162E-13i

3点: -2.8586E-14 - 1.1898E-13i

50点:-6.2076E-13 - 2.1713E-12i

51点:332.55 - 192i

52点:-1.6707E-12 - 1.5241E-12i

75点:-2.2199E-13 -1.0076E-12i

76点:3.4315E-12 + 192i

77点:-3.0263E-14 +7.5609E-13i

很明显,1点、51点、76点的值都比较大,它附近的点值都很小,可以认为是0,即在那些频率点上的信号幅度为0。

接着,我们来计算各点的幅度值。分别计算这三个点的模值,结果如下:

1点: 512

51点:384

76点:192

按照公式,可以计算出直流分量为:512/N=512/256=2;50Hz信号的幅度为:384/(N/2)=384/(256/2)=3;75Hz信号的幅度为192/(N/2)=192/(256/2)=1.5。可见,从频谱分析出来的幅度是正确的。

然后再来计算相位信息。直流信号没有相位可言,不用管它。先计算50Hz信号的相位,atan2(-192, 332.55)=-0.5236,

结果是弧度,换算为角度就是180*(-0.5236)/pi=-30.0001。再计算75Hz信号的相位,atan2(192, 3.4315E-12)=1.5708弧度,换算成角度就是180*1.5708/pi=90.0002。可见,相位也是对的。

根据FFT结果以及上面的分析计算,我们就可以写出信号的表达式了,它就是我们开始提供的信号。

总结

假设采样频率为Fs,采样点数为N,做FFT之后,某一点n(n从1开始)表示的频率为:Fn=(n-1)*Fs/N;该点的模值除以N/2就是对应该频率下的信号的幅度(对于直流信号是除以N);该点的相位即是对应该频率下的信号的相位。相位的计算可用函数atan2(b,a)计算。atan2(b,a)是求坐标为(a,b)点的角度值,范围从-pi到pi。要精确到xHz,则需要采样长度为1/x秒的信号,并做FFT。要提高频率分辨率,就需要增加采样点数,这在一些实际的应用中是不现实的,需要在较短的时间内完成分析。解决这个问题的方法有频率细分法,比较简单的方法是采样比较短时间的信号,然后在后面补充一定数量的0,使其长度达到需要的点数,再做FFT,这在一定程度上能够提高频率分辨力。


Java实现

转载自FFT算法

仅为整理之用

public class FFT {

  int n, m;

  // Lookup tables. Only need to recompute when size of FFT changes.
  double[] cos;
  double[] sin;

  public FFT(int n) {
      this.n = n;
      this.m = (int) (Math.log(n) / Math.log(2));

      // Make sure n is a power of 2
      if (n != (1 << m))
          throw new RuntimeException("FFT length must be power of 2");

      // precompute tables
      cos = new double[n / 2];
      sin = new double[n / 2];

      for (int i = 0; i < n / 2; i++) {
          cos[i] = Math.cos(-2 * Math.PI * i / n);
          sin[i] = Math.sin(-2 * Math.PI * i / n);
      }

  }

  public void fft(double[] x, double[] y) {
      int i, j, k, n1, n2, a;
      double c, s, t1, t2;

      // Bit-reverse
      j = 0;
      n2 = n / 2;
      for (i = 1; i < n - 1; i++) {
          n1 = n2;
          while (j >= n1) {
              j = j - n1;
              n1 = n1 / 2;
          }
          j = j + n1;

          if (i < j) {
              t1 = x[i];
              x[i] = x[j];
              x[j] = t1;
              t1 = y[i];
              y[i] = y[j];
              y[j] = t1;
          }
      }

      // FFT
      n1 = 0;
      n2 = 1;

      for (i = 0; i < m; i++) {
          n1 = n2;
          n2 = n2 + n2;
          a = 0;

          for (j = 0; j < n1; j++) {
              c = cos[a];
              s = sin[a];
              a += 1 << (m - i - 1);

              for (k = j; k < n; k = k + n2) {
                  t1 = c * x[k + n1] - s * y[k + n1];
                  t2 = s * x[k + n1] + c * y[k + n1];
                  x[k + n1] = x[k] - t1;
                  y[k + n1] = y[k] - t2;
                  x[k] = x[k] + t1;
                  y[k] = y[k] + t2;
              }
          }
      }
  }
}

#使用说明

Usage Notes

This function replaces your inputs arrays with the FFT output.

Input

N = the number of data points (the size of your input array, must be a power of 2)
X = the real part of your data to be transformed
Y = the imaginary part of the data to be transformed

i.e. if your input is (1+8i, 2+3j, 7-i, -10-3i)

N = 4
X = (1, 2, 7, -10)
Y = (8, 3, -1, -3)

Output

X = the real part of the FFT output
Y = the imaginary part of the FFT output
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FFT算法(Java实现) 的相关文章

随机推荐

  • 187_零线和火线

    火线 英文简写L LIVE 一般为红色或黄色或绿色 零线 英文简写N NEUTRAL 一般为蓝色 零线火线 专指 民用电的供电线路 市电的交流供电电压为220伏特 V 不同的国家不一样 中国是220V 它包括一根零线 N 和一根火线 L 零
  • 钉钉企业内部H5微应用、免登流程与真机调试

    官方文档 https ding doc dingtalk com 项目作为企业内部应用 H5微应用接入 免登 官方免登流程文档 https ding doc dingtalk com doc dev ep7bpq 简单来说 前端通过钉钉提供
  • Spring Cloud Alibaba 项目搭建流程

    Spring Cloud Alibaba 项目搭建 1 项目结构搭建 springcloudalibaba xmn pom xml gateway server 1030 网关 user common 公共类 order server 10
  • ElasticSearch条件查询,高亮查询,聚合查询,以及映射关系

    1 在上一篇文章中我们已经做过了创建索引和简单的文档数据的增删改查 今天我们的核心是文档数据的查询 当然在后期我们也会用java数据来操作数据 上一期 我们的索引库是shopping 今天我们再来回忆一下 这就是查询索引库中 所有的信息 接
  • 使用electron 将网页打包成应用程序

    需求 将一个已经上线的后台管理系统 只兼容Chrome 打包成一个不需要谷歌浏览器就可以运行的软件 需要安装 npm install electron g npm install electron packager g WinRAR解压工具
  • 最高分数的学生姓名

    include
  • JDBC第三讲

    目录 三 Dao模式 1 Dao模式概念 2 Dao模式的组成 3 具体代码 3 1 BaseDao 3 2 Dao接口 3 3 Dao接口的实现 3 4 实体类 3 5 测试类 三 Dao模式 1 Dao模式概念 前面我们在使用JDBC时
  • Jetpack学习之MVVM实战

    MVVM架构与Jetpack MVVM即Model View ViewModel的缩写 它的出现是为了将图形界面与业务逻辑 数据模型进行解耦 MVVM也是Google推崇的一种Android项目架构模型 而Jetpack组件 大部分是为了能
  • 小干货:Linux 系统的备份恢复

    作者 LeoLan s Blog https reurl cc gm5ZkQ tar 命令 副本 本机备份整个系统 以后还原还是还原到本机 注意根目录下要有充足的可用空间用于备份 cd tar gz格式 tar cvpzf system b
  • visual studio 2019账号登陆不上去问题解决

    网上多数解决方案是选择账户选项 然后把嵌入式web改为系统式web 但我用打开登陆选项 发现我就是系统式web 所以此方法行不通 但我观察到登陆选项中有设备代码选项 于是我就选了此选项 然后选择了登陆 此时它跳出来一个选项 根据提示只要在另
  • 单片机——独立按键控制

    1 基本定义与初始化 include
  • 2021秋招复习——计算机网络

    文章目录 总流程 浏览器缓存 资源缓存的位置 三级缓存原理 浏览器缓存的分类 强缓存 协商缓存 Last Modify If Modify Since ETag If None Match 浏览器缓存的优点 DNS 什么是DNS DNS解析
  • 边缘检测Sobel、laplacian、canny算子

    1 图像边缘检测 图像边缘检测对于分析图像中的内容 实现图像中物体的分割 定位等具有重要的作用 边缘检测大大减少了源图像的数据量 剔除了与目标不相干的信息 保留了图像重要的结构属性 常用的图像边缘检测方法分为以下两种 一阶导数的边缘算子 通
  • Linux PWM 驱动实验

    一 PWM 驱动简析 1 设备树下的 PWM 控制器节点 I MX6ULL 有 8 路 PWM 输出 因此对应 8 个 PWM 控制器 所有在设备树下就有 8 个PWM 控制器节点 这 8 路 PWM 都属于 I MX6ULL 的 AIPS
  • [Codeforces] combinatorics (R1600) Part.7

    Codeforces combinatorics R1600 Part 7 题单 https codeforces com problemset tags combinatorics 1201 1600 1534C Little Alawn
  • 用Python爬虫技术怎么挣点小钱,这四种方法可行

    提醒 抓取的数据如果要商业化 要小心知识产权问题噢 还要提醒一点 抓取和处理这些数据的代价要小于人工处理的代价 使用爬虫代替人工才有价值 我利用Python爬虫技术赚点小钱方式 在正式聊Python爬虫技术之前 先来说说挣钱的事 说说作为一
  • react组件的render方法

    一个组件类必须要实现一个 render 方法 这个 render 方法必须要返回一个 JSX 元素 必须要用一个外层的 JSX 元素把所有内容包裹起来 返回并列多个 JSX 元素是不合法的 错误的写法 render return div 第
  • 计算机显示丢失d3dcompiler,无法启动此程序提示缺少d3dcompiler文件怎么解决

    有用户说他在打开某个程序时 系统却提示说无法启动此程序提示缺少d3dcompiler文件的情况 这可能是在系统更新时出现错误导致的 那么无法启动此程序提示缺少d3dcompiler文件怎么解决呢 很简单安装一个更新包即可解决 下面小编给大家
  • [培训-无线通信基础-7]:信道均衡器(信道估计、信道均衡)

    作者主页 文火冰糖的硅基工坊 https blog csdn net HiWangWenBing 本文网址 https blog csdn net HiWangWenBing article details 118832368 目录 引言
  • FFT算法(Java实现)

    FFT导论 转载自FFT导论 FFT是离散傅立叶变换的快速算法 可以将一个信号变换到频域 有些信号在时域上是很难看出什么特征的 但是如果变换到频域之后 就很容易看出特征了 这就是很多信号分析采用FFT变换的原因 另外 FFT可以将一个信号的