簡體   English   中英

使用fft查找每個諧波的相位

[英]Finding the phase of each harmonics using fft

我用Matlab。

我有一個正弦信號:

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

我添加了3個諧波:

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

x2 =>(h4)amp:10 / Freq:200 /相位: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°)。

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)');

它會導致如此混亂(但你可以很好地看到你的振幅):

在此輸入圖像描述

你可以在第二個圖上看到很多相位分量。 但如果你消除了與零振幅相對應的所有頻率,你就會看到你的階段。

我們到了:

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)');

在此輸入圖像描述

現在您可以看到相位,但所有相位都轉移到90度。 為什么? 因為FFT使用cos()而不是sin(),所以:

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

UPDATE

如果某些信號分量的參數不是整數怎么辦?

讓我們添加一個新的組件x4

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

使用提供的代碼,您將獲得以下圖表:

具有實數參數的信號的fft

這不是我們期望得到的,不是嗎? 問題在於頻率樣本的分辨率。 該代碼用諧波近似信號,頻率以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

它將產生以下光譜:

具有非整數參數的信號的頻譜

更新2

無關緊要,必須分析哪個頻率范圍。 信號分量可以來自非常高的范圍,如下一個例子所示。 假設信號看起來像這樣:

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

這是結果圖:

在此輸入圖像描述

正如前面所解釋的那樣,相位轉移到-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)');

首先,我們應該注意(正如你在評論中正確地發現的那樣)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) ),那么音調將完全落在a bin,以及每個組件的頻率,幅度和相位可以相當容易地估算:

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精確倍數,你畢竟是在試圖估計這些分量的頻率)那么事情會變得更多復雜。 請注意,這會對相位估計產生特別顯着的影響。

我們首先回顧一下有限長度N的純復合音調( exp(2*pi*j*n*f/fs) )具有離散傅里葉變換(DFT),由下式給出:

在此輸入圖像描述

一種估計方法可以從估計頻率開始。 通過觀察峰值周圍的兩個連續的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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM