fft and ifft of signal seem to cause time reversal
88 次查看(过去 30 天)
显示 更早的评论
Hello!
I'm working with a signal that is periodic but also has a distinct behaviour that identifies the passage of time in a specific direction. As an analogy, consider if I'm making a video where a car drives from left to right across a figure window and then reappears on the left side, as though the boundaries themselves were periodic. The car's location is periodic, but the car must be moving from left to right if time is progressing. If time is going backward, then the car will appear to move backward, from right to left and reappearing on the right side.
The issue I am having is that somewhere during the following process:
- Fourier transforming the signal
- Turning that result into a single-sided spectrum
- Turning that single-sided spectrum back into the double-sided spectrum
- Inverse-Fourier transforming that double-sided spectrum back into [what should be] the original signal
I end up "reversing" the passage of time; if I start with my car going from left to right, I end up with my car going from right to left.
Now, I've seen from experimentation that I can seemingly solve this problem by introducing an additional complex conjugate operation between Steps 3 and 4; however, I don't understand why this works and why I'm having the issue in the first place. As far as I can tell, I am using the standard MATLAB procedures for working with time signals and single-sided spectra, as described here and here, among other places.
Here are the functions I'm using:
function [freqs, spectra] = getSingleSidedSpectra(signal,time)
Fs = 1/mean(diff(time));
L = length(signal);
freqs = Fs*(0:(L/2))/L;
rawfft = fft(signal);
P2 = rawfft/L;
P1 = P2(1:L/2+1);
P1(2:end-1) = 2*P1(2:end-1);
spectra = P1;
function [time,signal] = getSingleSidedTimeSeries(spectra,freqs)
T = 1/mean(diff(freqs));
testsize1 = size(spectra);
if testsize1(2) == 1
spectra = spectra';
end
spec_bothsides = [spectra(1) spectra(2:end-1)/2 spectra(end) fliplr(conj(spectra(2:end-1)))/2];
% spec_bothsides = conj(spec_bothsides); <--this line fixes the problem
signal = ifft(spec_bothsides * length(spec_bothsides));
time = (0:length(signal)-1)*T;
Essentially, my process is as follows:
[freqs,spectrum] = getSingleSidedSpectra(original_signal,original_signal_times)
[~,output_signal] = getSingleSidedTimeSeries(spectrum,freqs);
I would expect the original and output signals to be the same, but no; some kind of time reversal has occured. In the analogy, the orginal car movement from left to right has somehow become backward travel from right to left.
"original_signal" and "original_signal_times" are both 1D arrays.
The "time" output from the second function doesn't actually have any utility in this context; I just kept it for completeness.
As mentioned before, if I uncomment the line in the second function where I take an additional complex conjugate, the problem seems to be fixed. However, I don't understand why that would be the case and I'm unwilling to just accept that line without understanding its physical necessity.
I will note that I've tried to take care in keeping the spectra values associated with f = 0 and f = Nyquist frequency (= Fs/2) are included in the single-sided spectra. I've seen different people keep or remove those components in their definitions. There is actually a discrepancy between the two MATLAB examples that I added links to above - in the fft page, the single-sided spectrum includes the Nyquist frequency, but the single-sided spectrum in the ifft page does not.
I will also note that I've tried removing the transpose in the second function (within the if testsize1(2) == 1 statement) and changing the bracket-based horizontal concatenation to the vertcat function. The result of this is now my final value for "output_signal" remains a complex array, as opposed to having the complexity removed from the ifft() function. I've tried specifying the dimension over which the ifft should be calculated, but the result is unchanged. Given this is the only part of the code that I can clearly identify as being the different from the specified MATLAB procedure and the fact that horizcat vs vertcat seems to have an effect on the complexity of the ifft result regardless of whether or not I specify the ifft dimensionality, this is my best guess for the source of the problem. However, even if it is I don't understand why this would be an issue.
Any help would be appreciated. Please let me know if you need any further information from me. If necessary, I can try directly linking to a movie of the data I'm attempting to plot if the time dependency I'm trying to convey isn't clear.
Edit: typo
0 个评论
采纳的回答
David Goodmanson
2024-10-23,18:38
编辑:David Goodmanson
2024-10-24,0:23
Hi sgreess,
I'm guessing your input signal is a column vector. In that case the command
spectra = spectra'
by Matlab convention produces a complex conjugate transpose, giving an unwanted conjugate operation. Using
spectra = spectra.'
takes the non-conjugate transpose and fixes things.
Soapbox: I have never understood the general feeling that going to the one-sided spectrum is some kind of necessity or even a good idea. It's all right to take away a one-sided spectrum for plotting and leave it in exile there. But once someone goes to transforming back, if all they have left is the one-sided spectrum, too many mistakes get made trying to remake the actual spectrum. You were careful with your remake, but even there you won't like what happens for an odd number of points.
Whatever goes on with plotting, it's much better and easier to save the actual two-sided spectrum, and then using ifft is a breeze.
7 个评论
David Goodmanson
2024-10-24,19:04
编辑:David Goodmanson
2024-10-24,19:19
Hi William et. al.
Yes, zeropadding with nextpow2 is faster, except when it isn't. Sometimes it's slower, and it can be slower by a lot. For example,
n = 1e6;
y = rand(1,n);
m = 1000;
tic
for k = 1:m
z1 = fft(y);
end
t1 = toc
n2 = nextpow2(n); % new improved method
tic
for k = 1:m
z2 = fft(y,2^n2);
end
t2 = toc
t1 = 5.6366
t2 = 14.0273
nextpow2 is faster for 1024 points vs.1000 (it's so fast anyway that that hardly matters, per William's comment) but for 10^d points, using nextpow2 is slower for every d from 4 on up. For 10^8 points (and 10 repetitions)
t1 = 8.6337
t2 = 23.8874
That's an impressive time penalty to pay for a supposed speed improvement. In cases like this, speedup is a myth.
I imagine microprocessor cache properties could be involved and the results will be machine dependent, but my PC has an Intel i5-9400 six cores which I think is fairly typical.
Certainly something like nextpow2 makes sense for an fft on n points if n is a moderately large prime number. Far more often, zeropadding with nextpow2 is done for tribal knowledge reasons. I don't believe there is enough regard for consequences to the resulting spectrum, which can be detrimental.
Does anyone have thoughts about how the mindless use of nextpow2 came to be so entrenched? Use of 2^n points was the deal in the 50's and 60's, but that was a long time ago.
Paul
2024-10-25,21:37
编辑:Paul
2024-10-26,11:22
Hi David,
Suppose n is moderately large prime number, e.g., n = 999983.
In light of your results, it would make sense to zero pad to 1e6 rather than to nextpow2(n). But for a given value of n I guess it's not really clear what the ideal amount of padding should be to get the fastest result, or at least something close to the fastest result (assuming any zero padding at all is acceptable for the problem at hand).
Don't know how it came to be so entrenched. I know that there are lots of answers on this forum that use nextpow2, so anyone searching for how do use fft in Matlab will probably get lots of links to those answers and get the impression it's the "right approach."
Also, the doc page for nextpow2 has an example that says "Use the nextpow2 function to increase the performance of fft when the length of a signal is not a power of 2." but doesn't actually show what the performance increase actually is or when it might not be obtained.
更多回答(0 个)
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Spectral Measurements 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!