2013-08-19 142 views
3

我最近試圖在matlab上實現一個簡單的插值方法的例子,在傅立葉域中使用zéro填充。 但是我無法正確地完成這項工作,我總是有一個小的頻率偏移,在國際空間中幾乎看不到,但是它在時間空間中產生了一個巨大的錯誤。通過fourier空間填充插值

如傅立葉空間零填充似乎是一個常見(快速)插值方法,我認爲有我丟失的東西:

這裏是MATLAB代碼:

clc; 
clear all; 
close all; 


Fe = 3250; 
Te = 1/Fe; 
Nech = 100; 

F1 = 500; 
F2 = 1000; 
FMax = 1500; 

time = [0:Te:(Nech-1)*Te]; 
timeDiscrete = [1:1:Nech]; 
frequency = (timeDiscrete/Nech)*Fe; 

signal = cos(2*pi*F1*(time))+cos(2*pi*F2*(time))+cos(2*pi*FMax*(time)); 

%Compute the FFT 
spectrum=zeros(1,Nech); 
for k = timeDiscrete 
    for l = timeDiscrete 
     spectrum(k) = spectrum(k) + signal(l)*exp(-2*pi*j*l*k/Nech); 
    end 
end 

%Compute de inverse FFT 
reconstruction=zeros(1,Nech); 
for k = timeDiscrete 
    for l = timeDiscrete 
     reconstruction(k) = reconstruction(k) + spectrum(l)*exp(2*pi*j*l*k/Nech); 
    end 
end 
reconstruction=reconstruction/Nech; 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
%%%%%%%%%%%%%%%%%% Now interpolation will take place %%%%%%%%%%%%%%%%%% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

Finterp = 6*Fe; 
Tinterp = 1/Finterp; 
TimeInterp = [0:Tinterp:(Nech-1)*Te]; 
[m,n] = size(TimeInterp); 
NechInterp = n; 
TimeInterpDiscrete = [1:1:NechInterp]; 

%Compute original signal value without any interpolation 
signalResampled = cos(2*pi*F1*(TimeInterp))+cos(2*pi*F2*(TimeInterp))+cos(2*pi*FMax*(TimeInterp)); 

%Compute original signal interpolation by padding the fft and performing 
%inverse fft on the result 
semipaddedsize=floor(NechInterp/2); 
padded_spectrum0 = zeros(1,semipaddedsize); 
padded_spectrum0 = padarray(spectrum(1:Nech/2),[0 semipaddedsize-(Nech/2)],0,'post'); 
padded_spectrum = zeros(1,NechInterp); 
padded_spectrum(1:semipaddedsize) = padded_spectrum0; 
padded_spectrum(semipaddedsize+1:NechInterp-1) = conj(fliplr(padded_spectrum0)); 
% padded_spectrum = padarray(spectrum,[0 NechInterp-Nech],0,'post'); 
padded_timeDiscrete = [1:1:NechInterp]; 
padded_reconstruction = zeros(1,NechInterp); 


for k = padded_timeDiscrete 
    for l = padded_timeDiscrete 
     padded_reconstruction(k) = padded_reconstruction(k) + padded_spectrum(l)*exp(2*pi*j*l*k/NechInterp); 
    end 
end 
padded_reconstruction=padded_reconstruction/(1*Nech); 


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
%%%%%%%%%%%%%%%%%%  Let's print out the result  %%%%%%%%%%%%%%%%%% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

spectrumresampled=zeros(1,NechInterp); 
for k = TimeInterpDiscrete 
    for l = TimeInterpDiscrete 
     spectrumresampled(k) = spectrumresampled(k) + signalResampled(l)*exp(-2*pi*j*l*k/NechInterp); 
    end 
end 

figure(2); 
plot(abs(spectrumresampled)/6,'g'); 
hold on; 
plot(abs(padded_spectrum),'b'); 

figure(3); 

% Ground truth : deterministic signal is recomputed 
plot(TimeInterp,signalResampled,'g'); 
hold on; 
% linear interpolation between subsampled points (matlab tracing tool) 
plot(time,(reconstruction),'c'); 
hold on; 
% Padding the spectrum and reconstructing it 
plot(TimeInterp,real(padded_reconstruction),'m'); 
hold on; 

xlabel('Time in s','FontSize',16) 
ylabel('Signal value (no unit)','FontSize',16) 
title('\it{ Various signal reconstruction from fourier transform }','FontSize',16) 
legend('True signal', 'Reconstruction with linear interpolation', 'Reconstruction with padded spectrum'); 

由於我的聲望,我無法發佈結果圖像,但通過matlab,圖形很容易生成。 我真的很感激對這個代碼或零填充fft一般插值的評論。

預先感謝您

+0

你知道嗎?唯一的'fft'不能代表你信號的功率譜? – fpe

+0

其實我這裏不使用FFT,我用手寫的DFT。我知道我可以通過計算得到的dft完美地重建我的原始信號,當我修改頻譜以獲得更好的時間空間分辨率時,會出現問題。據我所知,許多應用程序正在使用fft和ifft來執行快速和準確的插值,並且我從來沒有聽說過會導致問題的傅立葉變換或其實現的理論侷限性?你指的是什麼? – Tobbey

+0

Tobbey,我認爲你的DFT有些問題。只運行第一塊代碼,然後執行:繪製信號;等一下;情節(ABS(重建), 'G');顯示我他們不排隊,並且一個被翻轉和不同的幅度... – Frederick

回答

1

你在時域觀察結果振鈴由於與原來的數據的正弦函數的卷積。這與頻域中矩形窗口乘法的時域等價,這實際上是您在零填充時所做的。別忘了apodize

我在摺疊循環(重大加速計算)後重新發布代碼,重新定義時間和頻率變量的範圍(請參閱DFT的定義以瞭解原因),並刪除您執行的其中一項填充操作我坦率地不理解這一點。

clc; 
clear all; 
close all; 

Fe = 3250; 
Te = 1/Fe; 
Nech = 100; 
mlt = 10; 
F1 = 50; 
F2 = 100; 
FMax = 150; 

time = [0:Te:(Nech-1)*Te]; 
%timeDiscrete = [1:1:Nech]; 
timeDiscrete = [0:1:Nech-1]; 
frequency = (timeDiscrete/Nech)*Fe; 

signal = cos(2*pi*F1*(time))+cos(2*pi*F2*(time))+cos(2*pi*FMax*(time)); 
spectrum = signal*exp(-2*pi*j*timeDiscrete'*timeDiscrete/Nech); 
fspec = [0:Nech-1]*Fe/Nech; 
reconstruction = spectrum*exp(2*pi*j*timeDiscrete'*timeDiscrete/Nech)/Nech; 

figure 
plot(time,signal) 
hold on 
plot(time,reconstruction,'g:') 

% **** interpolation **** 

Finterp = 6*Fe; 
Tinterp = 1/Finterp; 
TimeInterp = [0:Tinterp:(Nech-1)*Te]; 
NechInterp = length(TimeInterp); 
%TimeInterpDiscrete = [1:NechInterp]; 
TimeInterpDiscrete = [0:NechInterp-1]; 

%Compute original signal value without any interpolation 
signalResampled = cos(2*pi*F1*(TimeInterp))+cos(2*pi*F2*(TimeInterp))+cos(2*pi*FMax*(TimeInterp)); 

%Compute original signal interpolation by padding the fft and performing 
%inverse fft on the result 
padded_spectrum0 = spectrum; 
padded_spectrum0(NechInterp) = 0; 
fspecPadded = [0:NechInterp-1]*Finterp/NechInterp; 

padded_reconstruction = padded_spectrum0*exp(2*pi*j*TimeInterpDiscrete'*TimeInterpDiscrete/NechInterp)/(1*Nech); 
spectrumresampled = signalResampled*exp(-2*pi*j*TimeInterpDiscrete'*TimeInterpDiscrete/NechInterp); 
fresampled = [0:NechInterp-1]*Fe/NechInterp; 

% **** print out **** 

figure(2); 
hold on; 
plot(fspec,abs(spectrum),'c'); 
plot(fresampled,abs(spectrumresampled)/6,'g--'); 
plot(fspecPadded,abs(padded_spectrum0),'m:'); 
xlabel('Frequency in Hz','FontSize',16) 
ylabel('Signal value (no unit)','FontSize',16) 
legend('True signal', 'Reconstruction with resampled spectrum', 'Padded spectrum'); 

figure(3); 
% Ground truth : deterministic signal is recomputed 
plot(TimeInterp,signalResampled,'g'); 
hold on; 
% Padding the spectrum and reconstructing it 
plot(TimeInterp,real(padded_reconstruction),'m:'); 
xlabel('Time in s','FontSize',16) 
ylabel('Signal value (no unit)','FontSize',16) 
title('\it{ Various signal reconstruction from fourier transform }','FontSize',16) 
legend('True signal', 'Reconstruction with padded spectrum'); 

而這裏的一個可怕的失真信號的圖像由於在頻域中填充:

enter image description here

一些改進,可以通過首先施加fftshift到中心上交替側頻譜和填充然後反相fftshift操作:

Nz = NechInterp-Nech; 
padded_spectrum0 = ifftshift([ zeros(1,floor(Nz/2)) fftshift(spectrum) zeros(1,floor(Nz/2)+rem(Nz,2)) ]); % replaces (NechInterp) = 0; 
fspecPadded = [0:NechInterp-1]*Finterp/NechInterp; 

然後就到達此好得多插的時間域信號,因爲填充操作不會導致在光譜這種突然下降取捨(一些改進仍是可能然而進一步的修補):

enter image description here

1

好。其中一個問題就是你在做padded_reconstruction的IDFT的方式。您定義TimeInterp和NechInterp的方式使復指數的元素不正確。這解釋了不正確的頻率。

然後,在傅里葉域(pt 50)中包含中點兩次出現了問題。它接近於零,所以它不是一個非常明顯的問題,但應該只包括一次。我重寫了這一部分,因爲我很難完全按照你的方式進行工作。儘管我保持非常接近。如果我這樣做,我會使用fftshift,然後padarray(...,'both'),這將節省不得不將零置於中間的工作。如果你這樣做是爲了獲得學習體驗,並試圖不使用matlab工具(例如fftshift),那麼不要介意。

我也重複了你定義時間的方式,但要公平,我認爲它可以按你的方式工作。

與%我已經指示的改變< < < < < < < < < <

Fe = 3250; 
Te = 1/Fe; 
Nech = 100; 

F1 = 500; 
F2 = 1000; 
FMax = 1500; 

time = [Te:Te:(Nech)*Te]; %<<<<<<<<<< 
timeDiscrete = [1:1:Nech]; 
frequency = (timeDiscrete/Nech)*Fe; 

signal = cos(2*pi*F1*(time))+cos(2*pi*F2*(time))+cos(2*pi*FMax*(time)); 

%Compute the FFT 
spectrum=zeros(1,Nech); 
for k = timeDiscrete 
    for l = timeDiscrete 
     spectrum(k) = spectrum(k) + signal(l)*exp(-2*pi*j*l*k/Nech); 
    end 
end 

%Compute de inverse FFT 
reconstruction=zeros(1,Nech); 
for k = timeDiscrete 
    for l = timeDiscrete 
     reconstruction(k) = reconstruction(k) + spectrum(l)*exp(2*pi*j*l*k/Nech); 
    end 
end 
reconstruction=reconstruction/Nech; 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
%%%%%%%%%%%%%%%%%% Now interpolation will take place %%%%%%%%%%%%%%%%%% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

Finterp = 6*Fe; 
Tinterp = 1/Finterp; 
TimeInterp = [Tinterp:Tinterp:(Nech*6)*Tinterp]; %<<<<<<<<<< 
[m,n] = size(TimeInterp); 
NechInterp = n; 
TimeInterpDiscrete = [1:1:NechInterp]; 

%Compute original signal value without any interpolation 
signalResampled = cos(2*pi*F1*(TimeInterp))+cos(2*pi*F2*(TimeInterp))+cos(2*pi*FMax*(TimeInterp)); 

%Compute original signal interpolation by padding the fft and performing 
%inverse fft on the result 
padded_spectrum = zeros(1,NechInterp); %<<<<<<<<<< 
padded_spectrum(1:floor(Nech/2-1)) = spectrum(1:floor(Nech/2-1)); %<<<<<<<<<< 
padded_spectrum(end-floor(Nech/2)+1:end) = spectrum(floor(Nech/2)+1:end); %<<<<<<<<<< 

padded_reconstruction = zeros(1,NechInterp); 
for k = TimeInterpDiscrete %<<<<<<<<<<(no reason for new variable) 
    for l = TimeInterpDiscrete %<<<<<<<<<<(no reason for new variable) 
     padded_reconstruction(k) = padded_reconstruction(k) + padded_spectrum(l)*exp(2*pi*j*l*k/NechInterp); 
    end 
end 
padded_reconstruction=padded_reconstruction/(1*Nech); 
+0

請注意,您定義timeDiscrete的方式與DFT的定義不一致(如原始帖子中所示) –

+0

我會投票贊成您的回答,以及它對我的幫助,但我的名聲不夠高。使用padarray'both'和ffthift和ifftshift是一個好主意。 – Tobbey

+0

@TryHard timeDiscrete是一個迭代器。它不能從0開始,因爲matlab變量從1開始。但是,它可能應該是指數中的(l-1)*(k-1)。 – Frederick

2

非常感謝你們倆的那些建議,我決定迴應我自己的問題,因爲是沒有足夠的空間可用在coment框中:

@很難我確實定義了一個錯誤的離散時間向量,正如@Frederick也指出的,我有一個問題在填充我的矢量的過程中,感謝你給我正確的「matlab方式」來做到這一點,我不應該那麼害怕ffthift/iffthift,另外,使用padarray和'both'也會完成這項工作,正如@Frederick所提到的那樣。

摺疊for循環對於正確的matlab實現來說也是一個必不可少的步驟,我並沒有將它用於訓練目的來減輕我的理解和限制檢查。

另一個非常有趣的點@Try在第一句話中強調,而且我並沒有意識到,事實上,零填充就等於在時間域中通過sinc對數據進行卷積運算功能。

其實我覺得這是literraly相當於卷積與混迭正弦函數,也稱爲狄利克雷核,這就限制,採樣到無窮頻率增加時,是經典的正弦函數(見http://www.dsprelated.com/dspbooks/sasp/Rectangular_Window_I.html#sec:rectwinintro

我沒有在這裏發佈整個代碼,但我原來的程序的目的是比較dirichlet內核卷積公式,這是我在不同的框架(使用傅里葉級數離散表達式的理論演示),sinc卷積Whittaker–Shannon interpolation formula和零填充展示的,所以我應該給與一個非常相似的結果。

對於變跡問題,我認爲真正的答案是,如果您的信號是帶限的,則不需要其他切趾函數而不是矩形窗口。

如果你的信號沒有帶寬限制,或者有關採樣率的別名,你需要降低頻譜混疊部分的貢獻,這是通過頻率濾波器=頻域變跡窗口濾除它們,這在時域中變成了特定的內插內核。

+0

關於變跡問題的好處,我有很多要了解這一點。 –