web-dev-qa-db-ja.com

fftを使用したMatlabローパスフィルター

前方および後方fftを使用して、matlabに単純なローパスフィルターを実装しました。原理的には動作しますが、最小値と最大値が元の値と異なります。

signal = data;
%% fourier spectrum
% number of elements in fft
NFFT = 1024;
% fft of data
Y = fft(signal,NFFT)/L;
% plot(freq_spectrum)

%% apply filter
fullw = zeros(1, numel(Y));
fullw( 1 : 20 ) = 1;
filteredData = Y.*fullw;

%% invers fft
iY = ifft(filteredData,NFFT);
% amplitude is in abs part
fY = abs(iY);
% use only the length of the original data
fY = fY(1:numel(signal));
filteredSignal = fY * NFFT; % correct maximum

clf; hold on;
plot(signal, 'g-')
plot(filteredSignal ,'b-')
hold off;

結果の画像は次のようになります

enter image description here

私は何が間違っているのですか?両方のデータを正規化すると、フィルタリングされた信号は正しく見えます。

8

MATLABがY = fft(y,N)の周波数コンテンツをどのように格納するかを思い出してください。

  • Y(1)は定数オフセットです
  • Y(2:N/2 + 1)は正の周波数のセットです
  • Y(N/2 + 2:end)は負の周波数のセットです...(通常、垂直軸のこれをプロットします)

真のローパスフィルターを作成するには、低い正の周波数の低い負の周波数周波数。

これを行ったように、周波数領域で乗法長方形フィルターを使用してこれを行う例を次に示します。

% make our noisy function
t = linspace(1,10,1024);
x = -(t-5).^2  + 2;
y = awgn(x,0.5); 
Y = fft(y,1024);

r = 20; % range of frequencies we want to preserve

rectangle = zeros(size(Y));
rectangle(1:r+1) = 1;               % preserve low +ve frequencies
y_half = ifft(Y.*rectangle,1024);   % +ve low-pass filtered signal
rectangle(end-r+1:end) = 1;         % preserve low -ve frequencies
y_rect = ifft(Y.*rectangle,1024);   % full low-pass filtered signal

hold on;
plot(t,y,'g--'); plot(t,x,'k','LineWidth',2); plot(t,y_half,'b','LineWidth',2); plot(t,y_rect,'r','LineWidth',2);
legend('noisy signal','true signal','+ve low-pass','full low-pass','Location','southwest')

enter image description here

フルローパスフィトラーの方が優れていますが、再構成が少し「波打っている」ことに気付くでしょう。これは、周波数領域での矩形関数を使用した乗算が 時間領域でのsinc関数を使用した畳み込み と同じであるためです。 sinc関数を使用した畳み込みは、すべてのポイントを隣接するポイントの非常に不均一な加重平均に置き換えます。したがって、「波」効果が発生します。

ガウスのフーリエ変換はガウスです であるため、ガウスフィルターのローパスフィルターのプロパティはより優れています。ガウス分布はゼロにうまく減衰するため、畳み込み中の加重平均に遠方の近傍は含まれません。正と負の周波数を保持するガウスフィルターの例を次に示します。

gauss = zeros(size(Y));
sigma = 8;                           % just a guess for a range of ~20
gauss(1:r+1) = exp(-(1:r+1).^ 2 / (2 * sigma ^ 2));  % +ve frequencies
gauss(end-r+1:end) = fliplr(gauss(2:r+1));           % -ve frequencies
y_gauss = ifft(Y.*gauss,1024);

hold on;
plot(t,x,'k','LineWidth',2); plot(t,y_rect,'r','LineWidth',2); plot(t,y_gauss,'c','LineWidth',2);
legend('true signal','full low-pass','gaussian','Location','southwest')

enter image description here

ご覧のとおり、この方法では再構築がはるかに優れています。

18
eigenchris