IQ 信号 FFT 频谱分析:从原理到实现

IQ 信号 FFT 频谱分析 实现原理详细步骤

IQ 数据说明
一、单路实信号表示(完全不用正交两路)
核心特点:仅使用一路实数采样,不区分 I/Q 两路信号

  1. 时域实采样(Real Sampling)

直接对中频 / 射频信号进行实数采样:s(t)=A(t)cos(ω0​t+φ(t))
相位信息隐含在信号过零点中,直观可见的只有幅度包络。
典型应用:AM 检波、基础频谱分析、示波器观测。

  1. 幅度 / 包络(Envelope)

表达式:A(t)=I2+Q2​
缺陷:完全丢失相位信息,无法用于 QAM、PSK 等调制方式的解调。

  1. 相位(Phase)

表达式:φ(t)=arctan2(Q,I)
典型应用:FM/PM 解调、相位同步。

  1. 功率 / 平方律检测
    P(t)=I2+Q2与幅度仅相差一个平方关系,同样不携带独立相位信息。

信号链路与 IQ 正交基本概念

天线接收的原始射频(RF)为单路高频实信号,本身不存在正交结构。
混频降频后得到中频(IF),仍为单路实信号;经正交处理后成为中频正交信号(IF IQ)。
继续混频至 0Hz,得到零中频(Zero-IF),即常用的 IQ 正交基带数据。
本振区分:
余弦本振 → I 路
正弦本振 → Q 路

步骤 1:原始 IQ 数据读取(文件解析)

原理说明

IQ 信号在 txt 文件中以实数交替存储(I0, Q0, I1, Q1, …, In, Qn),需先读取文件并校验数据有效性,确保能正确拆分 I/Q 分量。

代码对应逻辑


import numpy as np

# 读取txt中所有实数数据
x = np.loadtxt(filename)  

# 数据合法性校验
if x.size < 2:
    raise ValueError("数据太短,至少需要2个数(I0,Q0)。")
if x.size % 2 != 0:
    x = x[:-1]  # 奇数长度时截断最后一个数,保证I/Q成对

工程考量

  • 校验数据长度:避免因数据残缺导致后续 I/Q 拆分失败;

  • 截断奇数长度数据:是「容错设计」,兼容实际采集时可能的末尾数据丢失问题。


步骤 2:I/Q 分量拆分与复数信号构造

原理说明

IQ 信号的本质是复信号(I 为实部,Q 为虚部),需从交替的实数序列中拆分 I、Q 通道,再组合为复数形式,才能正确表征射频信号的相位和幅度信息。

代码对应逻辑


# 步长2取所有I分量(第0、2、4...位)
i = x[0::2].astype(np.float64)  
# 步长2取所有Q分量(第1、3、5...位)
q = x[1::2].astype(np.float64)  
# 组合为复信号:实部=I,虚部=Q
iq = i + 1j * q  
# 转为complex64(平衡精度与内存)
return iq.astype(np.complex64)  

工程考量

  • 先转float64再计算:避免低精度运算导致的误差;

  • 最终转complex64:复数单精度足够满足射频信号分析需求,且内存占用仅为complex128的一半。


步骤 3:IQ 信号预处理(去直流分量)

原理说明

直流分量(信号均值)会导致频谱中零频处出现强峰值,掩盖有用信号,需通过「减去信号均值」消除直流分量。

代码对应逻辑


# 统一数据类型
y = np.asarray(iq, dtype=np.complex64)  
if remove_dc:
    # 去直流:减去复信号的均值(实部/虚部分别去直流)
    y = y - np.mean(y)  

原理补充

复信号均值计算:np.mean(y) = mean(Re(y)) + 1j*mean(Im(y)),减去均值后,实部(I)和虚部(Q)的直流分量均被消除。


步骤 4:窗函数选择与生成

原理说明

直接对非周期信号做 FFT 会产生「频谱泄露」(能量扩散到相邻频率),窗函数通过「加权信号两端」(使信号平滑过渡到 0)降低泄露,不同窗函数的泄露抑制 / 频率分辨率 trade-off 不同。

代码对应逻辑


def make_window(window, n):
    # 兼容大小写输入(如"Hann"和"hann")
    window = window.lower()  
    if window in ("hann", "hanning"):
        return np.hanning(n)  # 汉宁窗(默认,泄露抑制好)
    if window == "hamming":
        return np.hamming(n)  # 汉明窗(主瓣更窄)
    if window == "blackman":
        return np.blackman(n)  # 布莱克曼窗(泄露抑制最优,分辨率最低)
    if window in ("rect", "rectangle"):
        return np.ones(n)  # 矩形窗(无加权,分辨率最高,泄露最严重)

工程考量

  • 统一转为小写:提升接口易用性,避免因输入大小写导致的错误;

  • 窗长度与信号长度一致:保证每个采样点都能被加权。


步骤 5:FFT 点数自适应确定

原理说明

FFT 的计算效率在点数为 2 的幂时最高(基 2-FFT 算法),需自动选择「≥信号长度且≥1024」的最小 2 的幂,兼顾计算效率和频谱分辨率。

代码对应逻辑


if nfft is None:
    # 计算≥max(n,1024)的最小2的幂
    nfft = 1 << int(np.ceil(np.log2(max(n, 1024))))

原理补充

  • np.log2(max(n,1024)):计算目标点数的对数;

  • np.ceil():向上取整(保证点数≥目标值);

  • 1 << 整数:等价于2^整数,快速得到 2 的幂。


步骤 6:信号加窗处理

原理说明

将 IQ 复信号与窗函数逐点相乘,使信号两端平滑衰减,降低频谱泄露,加窗后信号的能量会被窗函数加权,后续幅值归一化需考虑窗函数的能量。

代码对应逻辑


# 生成窗函数
w = make_window(window, n).astype(np.float64)  
# 复信号逐点乘窗函数(I/Q同时加权)
xw = (x * w).astype(np.complex64)  

工程考量

  • 窗函数转float64:保证加权运算的精度;

  • 结果转complex64:维持数据类型一致性。


步骤 7:FFT 计算与频谱移位

原理说明

  • FFT 默认输出的频谱是「0 频→正频→负频」排列,需用fftshift将其移位为「负频→0 频→正频」,符合人对频率轴的直观认知;

  • 复信号 FFT 的结果是复数,其模(绝对值)代表频率分量的幅值。

代码对应逻辑


# FFT+移位(中心为0频)
X = np.fft.fftshift(np.fft.fft(xw, n=nfft))  

原理补充

  • np.fft.fft(xw, n=nfft):对加窗后的信号做 nfft 点 FFT(信号长度 <nfft 时自动补零,>nfft 时截断);

  • fftshift:将 FFT 结果的左右半部分交换,使 0 频位于频谱中心。


步骤 8:幅值归一化与 dB 转换

原理说明

  • 幅值归一化:将幅值缩放到 [0,1] 范围,方便不同信号的频谱对比;

  • dB 转换:将线性幅值转为对数刻度(dB),更符合人耳 / 仪器对信号强度的感知,公式:20×log10(A)(A 为幅值)。

代码对应逻辑


# 归一化到[0,1]
mag = np.abs(X) / (np.max(np.abs(X)) + 1e-12)  
# 转为dB值
mag_db = 20.0 * np.log10(mag + 1e-12)  

工程考量

  • 加1e-12:避免除以 0(幅值全为 0 时)或对数计算中出现log10(0)(会得到 - inf);

  • 归一化到最大值:消除信号绝对幅值的影响,聚焦频谱形状。


步骤 9:频率轴生成与结果格式化

原理说明

  • 频率轴需与 FFT 结果一一对应,fftfreq根据采样率和 FFT 点数生成频率刻度,再用fftshift移位,保证与频谱中心对齐;

  • 结果转为 JSON 字符串:方便跨平台 / 跨语言传输(如前端绘图、网络接口返回)。

代码对应逻辑


import json

# 生成频率轴:范围[-fs/2, fs/2),间隔fs/nfft
f = np.fft.fftshift(np.fft.fftfreq(nfft, d=1.0 / fs_hz))

# 格式化为JSON字符串
result = json.dumps({
    "frequency_hz": f.tolist(),  # numpy数组转列表(JSON不支持数组)
    "magnitude_db": mag_db.tolist()
})

原理补充

  • fftfreq(nfft, d=1/fs_hz):生成原始频率轴,范围 [0, fs),间隔fs/nfft;

  • fftshift后:频率轴变为 [-fs/2, fs/2),对应负频→0 频→正频的频谱排列。


总结

  1. 核心流程:文件读取→I/Q 拆分→预处理(去直流)→加窗→FFT 计算→频谱移位→幅值归一化(dB)→频率轴生成→结果格式化;

  2. 关键优化:自动选择 2 的幂作为 FFT 点数(提升效率)、加窗抑制频谱泄露、容错处理(数据长度校验、防除零 / 对数错误);

  3. 工程设计:统一数据类型(complex64)、兼容大小写窗函数输入、JSON 格式化结果(适配跨平台使用)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值