当前位置: 首页 > news >正文

快速傅里叶变换(FFT)中的振幅和相位

快速傅里叶变换(FFT)是一种高效计算离散傅里叶变换(DFT)的算法,它将时域信号转换为频域表示,包含振幅和相位信息。

振幅(Amplitude)

FFT结果的振幅表示信号在不同频率分量上的强度:

  1. 对于复数FFT结果X[k],振幅计算为:

    Amplitude[k] = |X[k]| = sqrt(Re(X[k])^2 + Im(X[k])^2)
  2. 对于实值信号的N点FFT,通常只需要前N/2+1个点(由于对称性)

  3. 要得到物理上有意义的振幅值,通常需要:

    • 对于非直流分量(k≠0):Amplitude[k] × 2/N

    • 对于直流分量(k=0):Amplitude[0] × 1/N

相位(Phase)

相位表示各频率分量在时间上的偏移:

  1. 相位角计算为:

    Phase[k] = atan2(Im(X[k]), Re(X[k]))

    其中atan2是四象限反正切函数,结果范围在[-π, π]之间

  2. 相位信息对于信号重构、时延估计等应用非常重要

示例代码

#include <iostream>
#include <vector>
#include <cmath>
#include <complex>
#include <fftw3.h>const double PI = 3.14159265358979323846;// 计算信号的FFT并返回振幅和相位
void computeFFT(const std::vector<double>& signal,std::vector<double>& amplitudes,std::vector<double>& phases,int sampleRate)
{int N = signal.size();// 分配输入输出数组fftw_complex* in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * N);fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * N);// 准备输入数据(实数信号)for(int i = 0; i < N; ++i) {in[i][0] = signal[i]; // 实部in[i][1] = 0.0;       // 虚部}// 创建FFT计划fftw_plan plan = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);// 执行FFTfftw_execute(plan);// 计算振幅和相位(只计算前N/2+1个点,因为对称)int outputSize = N/2 + 1;amplitudes.resize(outputSize);phases.resize(outputSize);for(int k = 0; k < outputSize; ++k) {// 计算复数幅度double real = out[k][0];double imag = out[k][1];double magnitude = sqrt(real*real + imag*imag);// 振幅(考虑FFT缩放)amplitudes[k] = magnitude / (N/2);if(k == 0) amplitudes[k] /= 2; // DC分量特殊处理// 相位(弧度)phases[k] = atan2(imag, real);}// 清理资源fftw_destroy_plan(plan);fftw_free(in);fftw_free(out);
}// 生成测试信号(包含多个频率分量)
void generateTestSignal(std::vector<double>& signal, int sampleRate, int numSamples)
{signal.resize(numSamples);double dt = 1.0/sampleRate;// 信号包含50Hz和120Hz分量for(int i = 0; i < numSamples; ++i) {double t = i * dt;signal[i] = 0.7 * sin(2*PI*50*t) + sin(2*PI*120*t + PI/3); // 120Hz分量有相位偏移}
}int main() {const int sampleRate = 1000;  // 采样率1kHzconst int numSamples = 1024;  // 采样点数// 1. 生成测试信号std::vector<double> signal;generateTestSignal(signal, sampleRate, numSamples);// 2. 计算FFT、振幅和相位std::vector<double> amplitudes, phases;computeFFT(signal, amplitudes, phases, sampleRate);// 3. 输出结果(前50个频率点)std::cout << "频率(Hz)\t振幅\t相位(rad)\n";for(int k = 0; k < 50; ++k) {double freq = k * sampleRate / numSamples;std::cout << freq << "\t" << amplitudes[k] << "\t" << phases[k] << "\n";}return 0;
}

输出结果:

程序将输出频率、振幅和相位信息。对于我们的测试信号(包含50Hz和120Hz分量),输出中应该能看到:

  • 在50Hz处有振幅约0.7,相位约0(因为50Hz分量没有初始相位偏移)

  • 在120Hz处有振幅约1.0,相位约π/3(1.0472弧度)

 振幅和相位计算

for(int k = 0; k < outputSize; ++k) {double real = out[k][0];double imag = out[k][1];// 振幅计算double magnitude = sqrt(real*real + imag*imag);amplitudes[k] = magnitude / (N/2);if(k == 0) amplitudes[k] /= 2; // DC分量特殊处理// 相位计算phases[k] = atan2(imag, real);
}

频率轴计算

频率分辨率为 sampleRate/N,第k个点对应的频率为:

double freq = k * sampleRate / numSamples;

http://www.dtcms.com/a/277087.html

相关文章:

  • 【计算机网络架构】环型架构简介
  • 在 C# 中调用 Python 脚本:实现跨语言功能集成
  • ADB 调试日志全攻略:如何开启与关闭 `ADB_TRACE` 日志
  • CS课程项目设计1:交互友好的井字棋游戏
  • 详解Linux下多进程与多线程通信(二)
  • 【QT】使用QSS进行界面美化
  • 异或为什么叫异或
  • 【读书笔记】《Effective Modern C++》第3章 Moving to Modern C++
  • Datawhale AI夏令营——基于带货视频评论的用户洞察挑战赛
  • 【PTA数据结构 | C语言版】简单计算器
  • 17.使用DenseNet网络进行Fashion-Mnist分类
  • LabVIEW调用外部DLL
  • 深度学习图像分类数据集—七种树叶识别分类
  • 零基础 “入坑” Java--- 十、继承
  • ARC 03 从Github Action job 到 runner pod
  • PPO(近端策略优化)
  • 华为HarmonyOS 5.0深度解析:跨设备算力池技术白皮书(2025全场景智慧中枢)
  • 【C++】list及其模拟实现
  • C++--List
  • AI交互中的礼貌用语:“谢谢“的效用与代价分析
  • 【操作系统-Day 5】通往内核的唯一桥梁:系统调用 (System Call)
  • MVC 参考手册
  • C++值类别与移动语义
  • linux shell从入门到精通(一)——初识Shell程序
  • opencv中contours的使用
  • Spring Boot RESTful API 设计指南:查询接口规范与最佳实践
  • Docker从环境配置到应用上云的极简路径
  • 【Docker基础】Dockerfile指令速览:文件与目录操作指令详解
  • 【深度学习新浪潮】什么是新视角合成?
  • Python----OpenCV(图像分割——彩色图像分割,GrabCut算法分割图像)