Search code examples
matlabsignal-processingfftdeconvolution

MATLAB: How to apply ifft correctly to bring a "filtered" signal back to the time doamin?


I am trying to get the output of a Gaussian pulse going through a coax cable. I made a vector that represents a coax cable; I got attenuation and phase delay information online and used Euler's equation to create a complex array.

I FFTed my Gaussian vector and convoluted it with my cable. The issue is, I can't figure out how to properly iFFT the convolution. I read about iFFt in MathWorks and looked at other people's questions. Someone had a similar problem and in the answers, someone suggested to remove n = 2^nextpow2(L) and FFT over length(t) instead. I was able to get more reasonable plot from that and it made sense to why that is the case. I am confused about whether or not I should be using the symmetry option in iFFt. It is making a big difference in my plots. The main reason I added the symmetry it is because I was getting complex numbers in the iFFTed convolution (timeHF). I would truly appreciate some help, thanks!

clc, clear
Fs = 14E12;          %1 sample per pico seconds
tlim = 4000E-12;
t = -tlim:1/Fs:tlim; %in pico seconds
ag = 0.5;            %peak of guassian 
bg = 0;              %peak location
wg = 50E-12;         %FWHM

x = ag.*exp(-4 .* log(2) .* (t-bg).^2 / (wg).^2); %Gauss. in terms of FWHM
Ly = x;

L = length(t);
%n = 2^nextpow2(L);  %test output in time domain with and without as suggested online
fNum = fft(Ly,L);

frange = Fs/L*(0:(L/2)); %half of the spectrum
fNumMag = abs(fNum/L);   %divide by n to normalize


% COAX modulation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

%phase data
mu = 4*pi*1E-7;
sigma_a = 2.9*1E7;
sigma_b = 5.8*1E6;
a = 0.42E-3;
b = 1.75E-3;
er = 1.508;
vf = 0.66;
c = 3E8;
l = 1;
Lso = sqrt(mu) /(4*pi^3/2) * (1/(sqrt(sigma_a)*a) + 1/(b*sqrt(sigma_b)));
Lo = mu/(2*pi) * log(b/a);
%to = l/(vf*c);
to = 12E-9; %measured
phase = -pi*to*(frange + 1/2 * Lso/Lo * sqrt(frange));

%attenuation Data
k1 = 0.34190;
k2 = 0.00377;
len = 1;
mldb = (k1 .* sqrt(frange) + k2 .* frange) ./ 100 .* len ./1E6;
mldb1 = mldb ./ 0.3048; %original eqaution is in inch
tfMag = 10.^(mldb1./-10);
  
% combine to make in complex form
 tfC = [];
     for ii = 1: L/2 + 1
        tfC(ii) = tfMag(ii) * (cosd(phase(ii)) + 1j*sind(phase(ii)));
     end
     
%END ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

%convolute both h and signal
fNum = fNum(1:L/2+1);
convHF = tfC.*fNum;
convHFMag = abs(convHF/L);
timeHF = ifft(convHF, length(t), 'symmetric');  %this is the part im confused about

% Ignore, 
% tfC(numel(fNum)) = 0;
% convHF = tfC.*fNum;
% convHFMag = abs(convHF/n);
% timeHF = ifft(convHF);

%% plotting

% subplot(2, 2, 1);
% plot(t, Ly)
% title('Gaussian input');
% xlabel('time in seconds')
% ylabel('V')
% grid

subplot(2, 2, 1)
plot(frange, abs(tfC(1: L/2 + 1)));
set(gca, 'Xscale', 'log')
title('coax cable model')
xlabel('Hz')
ylabel('|H(s)|V/V')
grid
ylim([0 1.1])

subplot(2, 2, 2);
plot(frange, convHFMag(1:L/2+1), '.-', frange, fNumMag(1:L/2+1)) %make both range and function the same lenght
title('The input signal Vs its convolution with coax');
xlabel('Hz')
ylabel('V')
legend('Convolution','Lorentzian in frequecuency domain');
xlim([0, 5E10])
grid

subplot(2, 2, [3, 4]);
plot(t, Ly, t, timeHF)
% plot(t, real(timeHF(1:length(t)))) %make both range and function the same lenght
legend('Input', 'Output')
title('Signal at the output')
xlabel('time in seconds')
ylabel('V')
grid



Solution

  • It's important to understand deeply the principles of the FFT to use it correctly.

    When you apply Fourier transform to a real signal, the coefficients at negative frequencies are the conjugate of the ones at positive frequencies. When you apply FFT to a real numerical signal, you can show mathematically that the conjugates of the coefficients that should be at negative frequencies (-f) will now appear at (Fsampling-f) where Fsampling=1/dt is the sampling frequency and dt the sampling period. This behavior is called aliasing and is present when you apply fft to a discrete time signal and the sampling period should be chosen small enaough for those two spectra not to overlap Shannon criteria.

    When you want to apply a frequency filter to a signal, we say that we keep the first half of the spectrum because the high frequencies (>Fsampling/2) are due to aliasing and are not characteristics of the original signal. To do so, we put zeros on the second half of the spectra before multiplying by the filter. However, by doing so you also lose half of the amplitude of the original signal that you will not recover with ifft. The option 'symmetric' enable to recover it by adding in high frequencis (>Fsampling/2) the conjugate of the coefficients at lower ones (<Fsampling/2).

    I simplified the code to explain briefly what's happening and implemented for you at line 20 a hand-made symmetrisation. Note that I reduced the sampling period from one to 100 picoseconds for the spectrum to display correctly:

    close all
    clc, clear
    Fs = 14E10;          %1 sample per pico seconds % CHANGED to 100ps
    tlim = 4000E-12;
    t = -tlim:1/Fs:tlim; %in pico seconds
    ag = 0.5;            %peak of guassian 
    bg = 0;              %peak location
    wg = 50E-12;         %FWHM
    NT = length(t);
    
    x_i = ag.*exp(-4 .* log(2) .* (t-bg).^2 / (wg).^2); %Gauss. in terms of FWHM
    fftx_i = fft(x_i);
    f = 1/(2*tlim)*(0:NT-1);
    
    fftx_r = fftx_i;
    fftx_r(floor(NT/2):end) = 0; % The removal of high frequencies due to aliasing leads to losing half the amplitude
    % HER YOU APPLY FILTER
    x_r1 = ifft(fftx_r); % without symmetrisation (half the amplitude lost)
    x_r2 = ifft(fftx_r, 'symmetric'); % with symmetrisation
    x_r3 = ifft(fftx_r+[0, conj(fftx_r(end:-1:2))]); % hand-made symmetrisation
    
    figure();
    subplot(211)
    hold on
    plot(t, x_i, 'r')
    plot(t, x_r2, 'r-+')
    plot(t, x_r3, 'r-o')
    plot(t, x_r1, 'k--')
    hold off
    legend('Initial', 'Matlab sym', 'Hand made sym', 'No sym')
    title('Time signals')
    xlabel('time in seconds')
    ylabel('V')
    grid
    subplot(212)
    hold on
    plot(f, abs(fft(x_i)), 'r')
    plot(f, abs(fft(x_r2)), 'r-+')
    plot(f, abs(fft(x_r3)), 'r-o')
    plot(f, abs(fft(x_r1)), 'k--')
    hold off
    legend('Initial', 'Matlab sym', 'Hand made sym', 'No sym')
    title('Power spectra')
    xlabel('frequency in hertz')
    ylabel('V')
    grid
    

    Plots the result:

    enter image description here

    Do not hesitate if you have further questions. Good luck!

    ---------- EDIT ----------

    The amplitude of discrete Fourier transform is not the same as the continuous one. If you are interested in showing signal in frequency domain, you will need to apply a normalization based on the convention you have chosen. In general, you use the convention that the amplitude of the Fourier transform of a Dirac delta function has amplitude one everywhere.

    A numerical Dirac delta function has an amplitude of one at an index and zeros elsewhere and leads to a power spectrum equal to one everywhere. However in your case, the time axis has sample period dt, the integral over time of a numerical Dirac in that case is not 1 but dt. You must normalize your frequency domain signal by multiplying it by a factor dt (=1picoseceond in your case) to respect the convention. You can also note that this makes the frequency domain signal homogeneous to [unit of the original multiplied by a time] which is the correct unit of a Fourier transform.