使用fft查找每个谐波的相位

时间:2015-11-27 17:47:15

标签: matlab fft phase

我使用Matlab。

我有一个正弦信号:

X(放大器:220 /频率:50)

我添加3次谐波:

x1 => (h2)amp:30 / Freq:100 / phase:30°

x2 => (h4)amp:10 / Freq:200 / phase:50°

x3 => (h6)amp:05 / Freq:300 /相位:90°

我将所有信号加在一起(如X包含3个谐波),结果信号称为: Xt

以下是代码:

%% Original signal
X = 220.*sin(2 .* pi .* 50 .* t);

%% Harmonics
x1 = 30.*sin(2 .* pi .* 100 .* t + 30);
x2 = 10.*sin(2 .* pi .* 200 .* t + 50);
x3 = 05.*sin(2 .* pi .* 300 .* t + 90);

%% adding the harmonics
Xt = X + x1 + x2 + x3;

我想要做的是:找到3个谐波信号(它们的幅度,频率和相位),从总和信号 Xt 开始,并知道基本信号 X (幅度和频率)!

到目前为止,我能够使用fft来检索谐波的频率和振幅,现在的问题是找到谐波的相位(在我们的例子中:30 °,50°和90°)。

2 个答案:

答案 0 :(得分:6)

FFT返回一个由复数组成的数组。要定义频率分量的相位,需要对复数使用angle()函数。不要忘记:你的谐波相位必须用弧度表示。

以下是代码:

Fs = 1000; % Sampling frequency                     

t=0 : 1/Fs : 1-1/Fs; %time

X = 220*sin(2 * pi * 50 * t);

x1 = 30*sin(2*pi*100*t + 30*(pi/180));
x2 = 10*sin(2*pi*200*t + 50*(pi/180));
x3 = 05*sin(2*pi*300*t + 90*(pi/180));

%% adding the harmonics
Xt = X + x1 + x2 + x3;

%Transformation
Y=fft(Xt); %FFT

df=Fs/length(Y); %frequency resolution

f=(0:1:length(Y)/2)*df; %frequency axis


subplot(2,1,1);
M=abs(Y)/length(Xt)*2; %amplitude spectrum
stem(f, M(1:length(f)), 'LineWidth', 0.5);
xlim([0 350]);
grid on;  

xlabel('Frequency (Hz)')
ylabel('Magnitude');

subplot(2,1,2);
P=angle(Y)*180/pi; %phase spectrum (in deg.)
stem(f, P(1:length(f)), 'LineWidth', 0.5);
xlim([0 350]);
grid on;

xlabel('Frequency (Hz)');
ylabel('Phase (degree)');

这将导致如此混乱(但你可以很好地看到你的振幅):

enter image description here

你可以在第二个图上看到很多相位分量。但如果你消除了与零振幅相对应的所有频率,你就会看到你的阶段。

我们在这里:

Y=fft(Xt); %FFT

df=Fs/length(Y); %frequency resolution

f=(0:1:length(Y)/2)*df; %frequency axis

subplot(2,1,1);
M=abs(Y)/length(Xt)*2; %amplitude spectrum

M_rounded = int16(M(1:size(f, 2))); %Limit the frequency range
ind = find(M_rounded ~= 0);

stem(f(ind), M(ind), 'LineWidth', 0.5);
xlim([0 350]);
grid on;  

xlabel('Frequency (Hz)')
ylabel('Magnitude');

subplot(2,1,2);
P=angle(Y)*180/pi; %phase spectrum (in deg.)
stem(f(ind), P(ind), 'LineWidth', 0.5);
xlim([0 350]);
ylim([-100 100]);
grid on;

xlabel('Frequency (Hz)');
ylabel('Phase (degree)');

enter image description here

现在你可以看到相位,但所有相位都转移到了90度。为什么?因为FFT使用cos()而不是sin(),所以:

X = 220*sin(2*pi*50*t + 0*(pi/180)) = 220*cos(2*pi*50*t - 90*(pi/180));

<强>更新

如果某些信号分量的参数不是整数怎么办?

让我们添加一个新组件x4

x4 = 62.75*cos(2*pi*77.77*t + 57.62*(pi/180));

使用提供的代码,您将得到以下图表:

fft of a signal with real number parameters

这不是我们期望得到的,不是吗?问题在于频率样本的分辨率。该代码用谐波近似信号,频率以1 Hz采样。使用77.77 Hz等频率显然是不够的。

频率分辨率等于信号时间的反转值。在我们之前的示例中,信号的长度为1秒,这就是频率采样为1/1s=1Hz的原因。因此,为了提高分辨率,您需要扩展处理信号的时间窗口。为此,只需更正可变t

的定义
frq_res = 0.01; %desired frequency resolution

t=0 : 1/Fs : 1/frq_res-1/Fs; %time

将产生以下光谱:

spectra for the signals with non-integer parameters

更新2

无关紧要,必须分析哪个频率范围。信号分量可以来自非常高的范围,如下一个例子所示。假设信号如下所示:

f=20e4; % 200 KHz
Xt = sin(2*pi*(f-55)*t + pi/7) + sin(2*pi*(f-200)*t-pi/7);

以下是结果图:

enter image description here

相位转移到-90度,前面已解释过。

以下是代码:

Fs = 300e4; % Sampling frequency                     

frq_res = 0.1; %desired frequency resolution

t=0 : 1/Fs : 1/frq_res-1/Fs; %time

f=20e4;
Xt = sin(2*pi*(f-55)*t + pi/7) + sin(2*pi*(f-200)*t-pi/7);

Y=fft(Xt); %FFT

df=Fs/length(Y); %frequency resolution

f=(0:1:length(Y)/2)*df; %frequency axis

subplot(2,1,1);
M=abs(Y)/length(Xt)*2; %amplitude spectrum

M_rounded = int16(M(1:size(f, 2))); %Limit the frequency range
ind = find(M_rounded ~= 0);

stem(f(ind), M(ind), 'LineWidth', 0.5);
xlim([20e4-300 20e4]);
grid on;  

xlabel('Frequency (Hz)')
ylabel('Magnitude');

subplot(2,1,2);
P=angle(Y)*180/pi; %phase spectrum (in deg.)
stem(f(ind), P(ind), 'LineWidth', 0.5);
xlim([20e4-300 20e4]);
ylim([-180 180]);
grid on;

xlabel('Frequency (Hz)');
ylabel('Phase (degree)');

答案 1 :(得分:1)

首先我们应该注意(正如你在评论中正确发现的那样)Matlab使用弧度来表示角度,所以谐波应该是:

%% Harmonics
x1 = 30.*sin(2 .* pi .* 100 .* t + 30*pi/180);
x2 = 10.*sin(2 .* pi .* 200 .* t + 50*pi/180);
x3 = 05.*sin(2 .* pi .* 300 .* t + 90*pi/180);

简单案例

估计频率分量的幅度,频率和相位的过程通常从快速傅立叶变换(FFT)开始,并选择最强的频率分量:

% Compute the frequency spectrum
N  = length(Xt);
Xf = fft(Xt);
Nmax = N/2 + 1;
Xf = Xf(1:Nmax);

% Locate the peaks
largest_peak = max(20*log10(abs(Xf)));
peak_floor   = largest_peak - 100;     % to reject peaks from spectral leakage and noise
[pks,idx] = findpeaks((max(peak_floor, 20*log10(abs(Xf))) - peak_floor)')

现在,如果谐波的基频和频率恰好是fs/N的精确倍数,其中fs是采样率,N是样本数(在这种情况下) length(Xt))然后音调将完全落在一个音箱上,每个组件的频率,幅度和相位可以很容易地用以下方法估算:

Amp   = 2*abs(Xf(idx))/N;
freq  = (idx-1)*fs/N;
phase = angle(Xf(idx));
phase = phase - phase(1); % set phase reference to that of the fundamental

通常和更复杂的现实

另一方面,如果频率成分不是fs/N的精确倍数,(或至少不知道是fs/N的精确倍数,那么你毕竟是在试图估算频率事情变得更加复杂。请注意,这会对相位估计产生特别显着的影响。

我们首先回顾一下有限长度exp(2*pi*j*n*f/fs)的纯复杂音调(N)具有离散傅里叶变换(DFT),由下式给出:

enter image description here

一种估算方法可以从估算频率开始。通过观察峰值周围Xf的两个连续区间的大小的比率,可以将振幅和相位考虑在内,主要是在指数idx(i)idx(i)+1处。在假设这两个箱受到很小干扰的情况下,该比率可以表示为:

ratio = abs(Xf(idx(i)+1)/Xf(idx)) 
      = abs(sin(pi*frac/N)/sin(pi*(frac-1)/N))

估算的频率为f = (idx(i)-1 + frac)*fs/N。然后可以使用Newton-Raphson方法获得参数frac

% Solve for "f" for which ratio = sin(pi*frac/N)/sin(pi*(frac-1)/N)
function f = fractional_frequency(ratio, N)

  niter = 20;
  K = (pi/N) * sin(pi/N);
  f = 0;
  for i=1:niter
    a  = sin(pi*f/N);
    b  = sin(pi*(f-1)/N);

    y  = ratio - a/b;
    yp = K / (b^2);
    f = max(-0.5, min(f - y/yp, 0.5));
  end
end

我们用它来估算频率:

freq  = zeros(1,length(idx));
for i=1:length(idx)
  ratio = abs(Xf(idx(i)+1))/abs(Xf(idx(i)));
  if (abs(Xf(idx(i)+1)) > abs(Xf(idx(i)-1)))
    ratio = -ratio;
  end

  frac = fractional_frequency(ratio, N)
  freq(i)  = (idx(i)-1+frac)*fs/N;
end

现在我们有了音调频率,我们可以通过拟合上面给出的DFT方程来获得幅度和相位(其中我们也因为我们处理真实音调而将幅度加上2):

  Amp(i)   = 2 * abs(Xf(idx(i))) * abs(sin(pi*frac/N)/sin(pi*frac));
  phase(i) = angle( Xf(idx(i)) .* (1-exp(2*pi*frac*j/N)) ./ (1-exp(2*pi*frac*j)) );

并将它们放在一起:

Amp   = zeros(1,length(idx));
freq  = zeros(1,length(idx));
phase = zeros(1,length(idx));
for i=1:length(idx)
  ratio = abs(Xf(idx(i)+1))/abs(Xf(idx(i)));
  if (abs(Xf(idx(i)+1)) > abs(Xf(idx(i)-1)))
    ratio = -ratio;
  end

  frac = fractional_frequency(ratio, N)
  freq(i)  = (idx(i)-1+frac)*fs/N;
  Amp(i)   = 2 * abs(Xf(idx(i))) * abs(sin(pi*frac/N)/sin(pi*frac));
  phase(i) = angle( Xf(idx(i)) .* (1-exp(2*pi*frac*j/N)) ./ (1-exp(2*pi*frac*j)) );
end
phase = phase - phase(1); % set phase reference to that of the fundamental