基于FFT的傅里叶分析:能否提取信号分量的幅值与相位信息?
Absolutely! FFT isn't limited to just identifying frequencies of signal components—you absolutely can extract both amplitude and phase shift information from the FFT output, which is all you need to fully reconstruct the original signal (or tweak individual components and build a modified version). Let’s walk through this using your existing code as a foundation.
How FFT Encodes Amplitude and Phase
The FFT returns a complex array where each element corresponds to a frequency component:
- The magnitude of the complex value gives you the amplitude of that frequency component (after applying the right scaling factor).
- The phase angle (argument) of the complex value gives you the phase offset of that component relative to a reference sine wave.
Modified Code to Extract Amplitude, Phase, and Reconstruct the Signal
Let’s adjust your code to calculate these values and rebuild the original signal:
%matplotlib inline import numpy as np import matplotlib.pyplot as plt import scipy.fftpack # Number of samplepoints N = 600 # Sample spacing T = 1.0 / 800.0 x = np.linspace(0.0, N*T, N) # Original signal: 50Hz sine (amplitude 1) + 80Hz sine (amplitude 0.5) y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x) # Compute FFT yf = scipy.fftpack.fft(y) xf = np.linspace(0.0, 1.0/(2.0*T), N//2) # Extract amplitude and phase # Amplitude: scale by 2/N for non-DC components (DC only needs 1/N scaling) amplitude = 2.0/N * np.abs(yf[:N//2]) # Phase: use np.unwrap to fix sudden phase jumps of ±π phase = np.unwrap(np.angle(yf[:N//2])) # Reconstruct the signal from FFT components reconstructed_y = np.zeros_like(x) for i in range(N//2): freq = xf[i] # Skip DC component (our original signal has no DC offset) if freq == 0: continue # Build each component: amplitude * cos(2πft + phase) component = amplitude[i] * np.cos(2.0 * np.pi * freq * x + phase[i]) reconstructed_y += component # Plot original vs reconstructed signal fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(10, 12)) # Original signal ax1.plot(x, y) ax1.set_title('Original Signal') ax1.set_xlabel('Time (s)') ax1.set_ylabel('Amplitude') # Amplitude spectrum ax2.plot(xf, amplitude) ax2.set_title('Amplitude Spectrum') ax2.set_xlabel('Frequency (Hz)') ax2.set_ylabel('Amplitude') # Reconstructed vs original signal ax3.plot(x, y, label='Original') ax3.plot(x, reconstructed_y, label='Reconstructed', linestyle='--') ax3.set_title('Original vs Reconstructed Signal') ax3.set_xlabel('Time (s)') ax3.set_ylabel('Amplitude') ax3.legend() plt.tight_layout() plt.show()
Key Details to Keep in Mind
- Amplitude Scaling: We multiply by
2/Nfor non-DC components because FFT splits the signal's energy between positive and negative frequencies. The DC component (frequency 0) only needs1/Nscaling since it has no mirrored counterpart. - Phase Unwrapping:
np.unwrap()fixes artificial phase discontinuities (jumps of ±π) that come from how FFT calculates phase angles, ensuring we get a smooth, accurate phase curve. - Reconstruction Logic: Each frequency component is rebuilt using a cosine term with the extracted amplitude and phase—this works because FFT decomposes real-valued signals into complex exponentials, which map directly to cosine waves with phase offsets.
- Nyquist Limit: We only use the first half of the FFT output (
N//2) because frequencies above the Nyquist frequency (1/(2T)) are just mirrored duplicates of lower frequencies for real signals.
When you run this code, you’ll see the reconstructed signal overlaps nearly perfectly with the original—proof that we’ve captured all the necessary information from the FFT to fully rebuild the input.
内容的提问来源于stack exchange,提问作者Ayan Mitra

