IFFT on symmetric spectral data giving complex result?

I have a single sided frequency spectrum which I am attempting to convert into a real time domain signal using the matlab IFFT function. I understand that I need to ensure the spectrum is complex conjugate symmetric in order for the output of the IFFT function to be purely real, however that doesn't seem to have worked and I can't see what I'm doing wrong. The relevant code I'm using is as follows:
twoSidedSpectrum = [singleSpectrum(1:end); flipud(conj(singleSpectrum(2:end)));
timeSignal = ifft(twoSidedSpectrum);
Note that singleSpectrum is odd in length, therefore twoSidedSpectrum is odd in length also. I would have though this would produce a purely real ifft output?

 Accepted Answer

assert(isreal(singleSpectrum(1)), 'first element must be real');
twoSidedSpectrum = [singleSpectrum(1:end); flipud(conj(singleSpectrum(2:end)));
timeSignal = ifft(twoSidedSpectrum);

6 Comments

This worked like a treat, thank you!
So the issue was that the first element of singleSpectrum wasn't real?
Once that's fixed, just want to point out that you can fill the second half of the array with zeros and specify the 'symmetric' flag to get the same result
rng(100);
X = [rand; rand(500,1)+1j*rand(500,1)];
XX = [X;flipud(conj(X(2:end)))];
isequal(ifft(XX),ifft([X;zeros(500,1)],'symmetric'))
ans = logical
1
Also, based on this discussion I believe the documentation of ifft should be clarified. That doc page states:
"The ifft function tests whether the vectors in Y are conjugate symmetric. If the vectors in Y are conjugate symmetric, then the inverse transform computation is faster and the output is real.
A function g(a) is conjugate symmetric if g(a)=g(a). However, the fast Fourier transform of a time-domain signal has one half of its spectrum in positive frequencies and the other half in negative frequencies, with the first element reserved for the zero frequency. For this reason, a vector v is conjugate symmetric when v(2:end) is equal to conj(v(end:-1:2))."
One could reasonably interpret that last sentence as a sufficient condition.
Let's make the first element in XX complex:
XX2 = XX;
XX2(1) = 1000 + 1000j;
By the definition in the very last sentence of the quoted text, XX would still be "conjugate symmetric." Of course it isn't and the output of ifft is complex
isreal(ifft(XX2))
ans = logical
0
figure,plot(imag(ifft(XX2)))
So I guess that last sentence would be better to say: "For this reason, a vector v is conjugate symmetric when v(2:end) is equal to conj(v(end:-1:2)) and v(1) is real."
What happens if we specify the 'symmetric' flag when v(1) is complex (and the rest of v satisfies the conjugate symmetry property? ifft doesn't throw an error or warning, it just ignores the imaginary part of v(1)
isequal((ifft([real(XX2(1));XX2(2:end)])) , ifft(XX2,'symmetric'))
ans = logical
1
@Paul indeed it was my 0 frequency bin which was complex (as a side note, it shouldn't have been in this case, which helped me find another error in my code).
Thank you for your additional comment, very thorough and you're right I think the ifft documentation should be updated. I could easily see others interpretting the documentation as I have.
One can also call IFFT like this for odd length signal
twoSidedSpectrum = ifft(singleSpectrum(1:end), 2*numel(singleSpectrum)-1, 'symmetric')
If you call for even length signal
twoSidedSpectrum = ifft(singleSpectrum(1:end), 2*numel(singleSpectrum)-2, 'symmetric')
The imaginary part of singleSpectrum(end) is ignored as well.
Bruno's comment with implicit zero padding seems to be faster than my comment with explicit zero padding.
I wonder if that's because ifft is smart enough to realize that it does not need to fully construct the full vector in the implicit case for the particular X and NFFT input.
rng(100);
N = 1e7;
X = [rand; rand(N,1)+1j*rand(N,1)]; % odd case
f1 = @() ifft([X;zeros(N,1)],'symmetric'); % explicit
f2 = @() ifft(X,2*numel(X)-1,'symmetric'); % implicit
isequal(f1(),f2())
ans = logical
1
timeit(f1)
ans = 1.1295
timeit(f2)
ans = 0.8026
I wonder if that's because ifft is smart enough to realize that it does not need to fully construct the full vector in the implicit case for the particular X and NFFT input
It must be the case. Whenn I interface FFTW they have all such options and more. Matlab uses tthe same library.

Sign in to comment.

More Answers (0)

Products

Release

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!