# IFFT gives complex values in Matlab

I have frequency data from a VNA. I am trying to convert to time domain, and I can't figure out why I am getting complex valued time domain data. This is for ISAR measurements, and I can't get passed this simple step.

ifft_points = length(frequency)*1;
% S11 time domain
for i = 1:1:s_param_number
temp_data = data(:,i);
data_flip = conj(flipud(temp_data(2:end)));  % complex conjugate
data_total = [data_flip; data(:,i)];
data_ifft = ifft(temp_data, ifft_points);
S_param_time(:,i) = (ifftshift(abs(data_ifft)));
end

% Create the Time Vector
BW = frequency(end) - frequency(1);         % Bandwidth of the frequency data
dt = 1/BW;                                  % Time step
start_time = -length(S_param_time(:,1))/2*dt;  % Start time of the Time Domain Vector
end_time = length(S_param_time(:,1))/2*dt-dt;  % End time of the Time Domain Vector
time_vector = start_time: dt: end_time;            % Time Domain Vector


In the above code, the variable data is a complex valued S-Parameter measurement. The variable data_ifft is always complex. My thoughts on this:

1. I take my data and flip it and conjugate it
2. I append the flipped data to the beginning of the original data
3. Take the IFFT and specify the points to be the original size
4. Do the IFFT shift.

I don't think the the symmetric tag is the way to go because that is meant for data that is already very near to being complex symmetric.

EDIT/UPDATE

Ok, so I updated a few things. I am taking measurements on a VNA from 500MHz to 8GHz with 48001 points, this gives a delta_f of 156250Hz

1. I take my raw S21 data (real/imaginary) and zero pad from DC to 3200 points
2. Make a copy of raw S21 data from 2:end and flip and conjugate
3. I append the flipped data to the beginning of the original data. This should give a full FFT to then take the IFFT and IFFT shift.
points = length(freq_data);           % Number of points in raw data
df = (freq_data(end) - freq_data(1))/(points-1);  % Frequency step
fs = 2^17*df;                         % Sampling frequency
lower_points = floor(freq_data(1)/df); % Number of lower points to zeropad
upper_points = (fs)/df - points - lower_points; %Number of upper points to zero pad
for i = 1:1:(2^17)
freq_total_FFT(i) = (i-1)*df;  % Create the total frequency vector
end
freq_total_FFT = freq_total_FFT';

S21_copy= [zeros(lower_points,1); S21_raw; zeros(upper_points,1)];
S21_flip = conj(flipud(S21_copy(2:end)));
S21_full_FFT = [S21_copy; S21_flip ];
S21_time = ifftshift(ifft(S21_full_FFT));

% Create the Time Vector
BW = freq_total_FFT(end) - freq_total_FFT(1);         % Bandwidth of the frequency data
dt = 1/BW;                                  % Time step
start_time = -ceil(length(S21_time (:,1))/2)/2*dt;  % Start time of the Time Domain Vector
end_time = ceil(length(S21_time (:,1))/2)/2*dt-dt;  % End time of the Time Domain Vector
time_vector = start_time: dt/2: end_time;            % Time Domain Vector

1. After taking the IFFT, I use a kaiser window and filter
filter_order = 10; beta = 6;
Fsample = freq_total_FFT(end)*1e-9; Fc1 = .8; Fc2 = 5.2;

flag = 'scale';
win = kaiser(filter_order +1, beta);      % calculate the kaiser window
passband = [Fc1 Fc2]/(Fsample/2);    % bandpass passband
b = fir1(order, passband, 'bandpass', win, flag);
hd = dsp.FIRFilter('Numerator', b);

filtered_data = filtfilt(hd.Numerator, 1, S21_time);



The plot shows time data pulled directly from VNA (BLACK), IFFT unfiltered (BLUE), and IFFT filtered (RED). The green is the area of interest which I will time gate, but I am still having issues getting my time results to look similar to the VNA • Step 1 is done wrong if the data length is even. Step 3 is wrong all together. Mar 1 at 23:14

Don’t use the original size for the IFFT but instead use the size of your properly extended and complex conjugated spectrum. In order for the time domain data to be real, the frequency spectrum must be complex conjugate symmetric, and all of those points must be included in the IFFT. This is most easily done when the resulting FFT samples are of odd length (since Nyquist is at a half sample offset in that case). An odd length FFT will result naturally when following the prescribed processing described here so we needn't go into detail on how to handle an even length FFT case.

As a simple experiment to prove this to yourself, create the FFT data from a real waveform and observe the full FFT which will be complex conjugate symmetric. Take the IFFT of that and you will of course get your real waveform back. If you only include the first half of that FFT result, you will get a complex, and incorrect, result.

Additionally it is important to have the frequency domain sufficiently sampled to avoid time domain aliasing effects. If time domain aliasing occurs in the inverse FFT, then inaccuracies will result in the derived time domain response.

The deeper details are the IFFT result includes time domain aliasing, so may not be accurately representative of the frequency response as captured with a VNA if not processed properly. Below I demonstrate the recommended procedure to recreate the time vector from the frequency data, and what occurs if not done properly.

Below I show a test waveform that is well constrained in both time and frequency. I show the known "true" time response, and it's frequency response as given by the Discrete Time Fourier Transform (DTFT). We note here that the frequency response is well below 100 dB at Nyquist, and thus any frequency domain aliasing which does occur in the DTFT has been minimized below the errors we will later demonstrate due to time domain aliasing from improper processing. The above frequency response contains 20,000 samples, which results in a very good match to the true time domain response when the time domain result is predicted from the frequency domain using the process depicted in the graphic below with steps as follows:

• Assign the measured complex frequency values to the first half of the frequency vector
• Flip and conjugate these values omitting the first (DC bin) value and append as the second half of the frequency vector
• The result will always be odd length. Inverse FFT this result to get the time domain waveform.
• Observe the time domain response on a dB scale, if this hasn't decayed to the noise floor at the upper range of the time axis, then the result is likely degraded by time domain aliasing. In this case the frequency vector must be first interpolated to a higher number of samples (on the VNA, this should be done with a tighter resolution bandwidth resulting in a longer time capture duration).
• If there are no such signs of time domain aliasing, then the resulting time waveform can be truncated to any desired length of observation. The resulting time domain waveform recovered from the complex frequency response alone using the above process is confirmed to be an excellent match with little error from the "true" time response as shown in the plot below. The upper plot shows the two waveforms superimposed (where we cannot discern any difference) and the lower plot shows the normalized error between the two as (recovered-actual)/actual in dB. (Note that the maximum imaginary value for the time domain result was $$1.78e-18$$) The above was done with 20,000 samples over the frequency range from DC to Nyquist, even though the original time domain waveform only contained 200 samples, and as demonstrated resulted in minimum time domain aliasing. Below I will show what would have occurred if we only used 200 samples in frequency (199 actual samples as an odd vector)... And again if we had even less samples in the frequency response from DC to Nyquist (Note this hasn't changed the sampling rate so we have not introduced frequency domain aliasing, but the less samples means less samples in time, meaning less of a duration in time, resulting in time domain aliasing): • Hello, thank you so much for your response. I tried this and it still has complex values. The values are on the order of 1e-5. I don't think that is small enough to be rounding errors. Also, I was keeping the points the same just so that it didn't ruin my time vector. With the number of point doubled, my time vector is stretched Mar 1 at 19:34
• Agree doesn’t sound like rounding errors. Also be sure you use the DC and then only mirror the positive frequencies such that you will have an odd number of bins. Time vector is stretched but you can truncate that result back to the original length (note that the FFT and IFFT has time domain aliasing so if you don’t have enough frequency sample resolution from your VNA you will also have that affecting you) Mar 1 at 20:52
• @Frank see my update and hopefully it is clearer what I meant about time domain aliasing and how to properly process the resulting samples in time for the time length you want. Mar 2 at 15:53
– Jdip
Mar 2 at 16:46
• Thank you so much. I really appreciate the effort into helping my understanding. I have more data to process, but I think I know what I was doing wrong. I was using bandlimited data, and I was zero padding to DC and to Fs. This is now obvious, but I guess I have to struggle to learn this stuff. Mar 2 at 21:07

This is an example how to arrange the data to get real-valued IFFT

N=1024;
data=randn(N,1)+1j*randn(N,1);

data_herm_sym = [real(data(1)); data(2:end); ...
imag(data(1)); conj(flipud(data(2:end)))];

S_param_time = ifft(data_herm_sym, 2*N);


data_herm_sym contains the data arranged in Hermittian symmetry. The IFFT should be 2 times your original data length.

I have used complex-valued random data for the S parameters in frequency domain for obvious reasons.