Java实现DFT时振幅值异常问题求助
问题:DFT计算振幅异常,高频段振幅升高
我正在开发一个通过DFT(离散傅里叶变换)结合周转圆绘制指定图形的项目,但计算出的振幅值不符合预期——无论使用何种样本点,高频段(索引i较大时)的振幅都会升高。
我的DFT函数接收存储样本点x、y坐标的double[][]数组作为输入,Points.n代表样本点总数。以下是具体实现代码:
Dft类代码
public class Dft { public static double[][] dft(double[][] psamples){ double[][] result = new double[Points.n][2]; for (int i = 0; i < Points.n; i++){ Complex x_i = new Complex(0, 0); for (int j = 0; j < Points.n; j++){ Complex sample = new Complex(psamples[j][0], psamples[j][1]); double root = Math.PI*2*i*j/Points.n; Complex unity = new Complex(Math.cos(root), -Math.sin(root)); x_i = Complex.add(x_i, Complex.multiply(sample, unity)); } result[i][0] = x_i.amp()/Points.n; //amplitude result[i][1] = x_i.angle(); //phase change //frequency is equal to the index number i System.out.println(i + " amp: " + result[i][0] + " phase change: " + result[i][1]); } return result; } }
Complex类代码
public class Complex { double[] num = {0,0}; public Complex(double a, double b){ num[0] = a; num[1] = b; } public void setReal(double a){ num[0] = a; } public void setImaginary(double b){ num[1] = b; } public double getReal(){ return num[0]; } public double getImaginary(){ return num[1]; } public static Complex add(Complex a, Complex b){ Complex result = new Complex(a.getReal()+b.getReal(), a.getImaginary() + b.getImaginary()); return result; } public static Complex euler(double r, double theta){ Complex result = new Complex(r*Math.cos(theta), r*Math.sin(theta)); return result; } public static Complex multiply(Complex a, Complex b){ Complex result = new Complex(a.getReal()*b.getReal() - a.getImaginary()*b.getImaginary(), a.getReal()*b.getImaginary() + a.getImaginary()*b.getReal()); return result; } public double amp(){ double result = Math.sqrt(num[0]*num[0] + num[1]*num[1]); return result; } public double angle(){ if (num[0] == 0){ if (num[1]>0) return Math.PI/2; else if (num[1]<0) return -Math.PI/2; else return 0; } else { double result = Math.atan2(num[1],num[0]); return result; } } }
问题分析与解决方案
核心问题
问题出在DFT频率分量的振幅归一化逻辑上:
对于N点DFT,索引i对应的频率分为两种情况:
- 当
i < N/2时,是正频率分量; - 当
i >= N/2时,是负频率分量,其振幅与对应正频率分量(索引N-i)完全相等,仅旋转方向相反。
你当前对所有索引的振幅统一除以N,但未区分正/负频率分量的能量对应关系,导致负频率分量的振幅被单独计算,看起来像是高频段振幅异常升高。
修正后的振幅计算逻辑
针对周转圆绘制场景,正确的振幅归一化规则为:
- 直流分量(
i=0):振幅为x_i.amp()/N; - 正频率分量(
1 <= i < N/2):振幅为x_i.amp()*2/N(合并对应负频率分量的能量); - 奈奎斯特频率分量(N为偶数时
i=N/2):振幅为x_i.amp()/N(无对应负频率分量); - 负频率分量(
i > N/2):可直接复用对应正频率分量的振幅,或忽略(绘制周转圆仅需正频率分量)。
修改后的代码片段:
for (int i = 0; i < Points.n; i++){ // 原有DFT计算逻辑保持不变 if (i == 0 || (Points.n % 2 == 0 && i == Points.n/2)) { result[i][0] = x_i.amp() / Points.n; } else if (i < Points.n/2) { result[i][0] = x_i.amp() * 2 / Points.n; } else { // 负频率分量复用正频率振幅,或直接跳过处理 result[i][0] = result[Points.n - i][0]; } result[i][1] = x_i.angle(); }
额外优化
绘制周转圆时,仅需保留前N/2 + 1个分量(直流+正频率+奈奎斯特频率)即可,负频率分量无需参与绘制,这样能避免高频段振幅异常的视觉干扰,同时减少计算量。
内容的提问来源于stack exchange,提问作者Momin Ahmed
相关产品推荐
相关产品推荐

