Recap
The formula of Fourier transform:
F ^ ( f ) = ∫ f ( t ) e − i 2 π ftdt \hat{F}(f) = \int f(t) e^{-i2 \pi ft} dtF^(f)=∫f(t)e− i 2 π f t dt
The formula of inverse Fourier transform:
f ( t ) = ∫ F ^ ( f ) ei 2 π ftdff(t) = \int \hat{F}(f) e^{i2 \ pi ft} dff(t)=∫F^(f)ei2πftdf
The problem we encountered before is that the amplitude of the reconstructed signal obtained directly by the formula of inverse Fourier transform is much larger than the original signal.
- rebuild signal
- original signal
Now I can tell you the reason: the Fourier transform done by a computer is essentially a discrete Fourier transform, so to reconstruct the signal, the inverse discrete Fourier transform should also be used.
Discrete Fourier Transform
The formula of Fourier transform F ^ ( f ) = ∫ f ( t ) e − i 2 π ftdt \hat{F}(f) = \int f(t) e^{-i2 \pi ft} dtF^(f)=∫f(t)e− f ( t ) f(t)in i 2 π f t dtf ( t ) represents a continuous time series signal, which will be discretized in the computer, namely: sampling -> quantization -> encoding. T in the figure below is the sampling period, which is the interval time of each sampling point in the computer. After digitization,f ( t ) f(t)f ( t ) becomesx ( n ) x(n)x(n), x ( n ) = f ( n T ) x(n)=f(nT) x(n)=f ( n T ) .
Next, step by step, the formula of Fourier transform is also discretized:
- The sign of the signal in the formula should be changed to a discrete form, and the integral sign should be changed to a summation sign
X ^ ( f ) = ∑ nx ( n ) e − i 2 π fn \hat{X} (f) = \sum_ {n} x(n) e^{-i2 \pi fn}X^(f)=n∑x(n)e− i 2 π f nSo
, the original signal ande − i 2 π fne^{-i2 \pi fn}e− i 2 π f n signals have become discrete and become an array that can be accessed with the following n. - There are two more questions:
- The original signal is infinite in time series, how to represent the original signal in the computer?
- Need to choose e − i 2 π fne^{-i2 \pi fn} of different frequenciese− i 2 π f n signal, find out the corresponding optimal amplitude and initial phase, and these possible frequencies are infinitely many, how to gete − i 2 π fne^{-i2 \ pi fn}eWhat about the − i 2 π f n signal?
- There are still ways:
- Assume that the frequency of the original signal to be decomposed is non-zero within a finite time series interval. This is easy to understand, a 3-minute song should already have enough information for frequency decomposition.
X ^ ( f ) = ∑ n = 0 N − 1 x ( n ) e − i 2 π fn \hat{X} (f) = \sum_{n=0}^{N-1} x(n) e ^{-i2 \pi fn}X^(f)=n=0∑N−1x(n)e−i2πfn - Only select a limited number of frequencies to get a limited number of e − i 2 π fne^{-i2 \pi fn}e− i 2 π f n signals, for these finite signals, find the best amplitude and initial phase.
- The number of selected finite frequencies is preferably the same as the number of sampling points of the original signal within a finite time sequence interval. This is mainly for better inverse Fourier transform.
X ^ ( k N ) = ∑ n = 0 N − 1 x ( n ) e − i 2 π k N n , k = 0 , 1 , 2 , . . . , N − 1 \hat{X} (\frac {k}{N}) = \sum_{n=0}^{N-1} x(n) e^{-i2 \pi \frac{k}{N}n},k=0,1,2 ,...,N-1X^(Nk)=n=0∑N−1x(n)e−i2πNkn,k=0,1,2,...,N−1 - What is the actual meaning of k? Why k N \frac{k}{N}NkCan it replace the position of frequency f? In fact, there is a mapping relationship between k and f, and the function is expressed as:
f = g ( k ) = k NT = k ⋅ sr N f = g(k) = \frac{k}{NT} =\frac{k \ cdot s_r}{N}f=g(k)=NTk=Nk⋅sr
Where sr is the sampling frequency of the original signal. That is to say, the selected frequency range is [0, sr), within this range, the selected frequency is equally divided by the number of sampling points.
- Assume that the frequency of the original signal to be decomposed is non-zero within a finite time series interval. This is easy to understand, a 3-minute song should already have enough information for frequency decomposition.
Inverse Discrete Fourier Transform
The formula of inverse discrete Fourier transform can be given directly:
x ( n ) = 1 N ∑ k = 0 N − 1 X ^ ( k N ) ei 2 π k N nx(n) = \frac{1}{N } \sum_{k=0}^{N-1} \hat{X} (\frac{k}{N}) e^{i2 \pi \frac{k}{N}n}x(n)=N1k=0∑N−1X^(Nk)ei2πNkn
import matplotlib.pyplot as plt
import numpy as np
def create_signal(frequency, time: np.ndarray):
sin0 = np.sin(2 * np.pi * (frequency * time))
sin1 = np.sin(2 * np.pi * (2 * frequency * time))
sin2 = np.sin(2 * np.pi * (3 * frequency * time))
return sin0 + sin1 + sin2
def create_pure_tone(frequency, time: np.ndarray):
angle = 2 * np.pi * frequency * time
return np.cos(angle) - complex(0, 1) * np.sin(angle)
def calculate_mean(multi_signal):
x_mean = np.mean([x.real for x in multi_signal])
y_mean = np.mean([x.imag for x in multi_signal])
return x_mean, y_mean
def calculate_sum(multi_signal):
x_sum = np.sum([x.real for x in multi_signal])
y_sum = np.sum([x.imag for x in multi_signal])
return x_sum, y_sum
def plot_fourier_transform(signal,
pure_tone,
plot_mean=False,
plot_sum=False,
plot=True):
multi_signal = signal * pure_tone
x_series = np.array([x.real for x in multi_signal])
y_series = np.array([x.imag for x in multi_signal])
mean = calculate_mean(multi_signal)
sum = calculate_sum(multi_signal)
# print(f"mean:{mean}\nsum:{sum}")
if plot:
plt.plot(x_series, y_series)
if plot_mean:
plt.plot([mean[0]], [mean[1]],
marker='o',
markersize=10,
color="red")
if plot_sum:
plt.plot([sum[0]], [sum[1]],
marker='o',
markersize=10,
color="green")
plt.show()
return complex(mean[0], mean[1]), complex(sum[0], sum[1])
def plot_inverse_fourier_transform(cfs, pure_tones, time, plot=True):
assert len(cfs) == len(pure_tones)
N = len(cfs)
signal = 0
for i in range(N):
signal += cfs[i] * np.conj(pure_tones[i])
signal /= N
if plot:
plt.plot(time, signal)
plt.show()
return signal
if "__main__" == __name__:
time = np.linspace(0, 10, 1000)
N = time.shape[0]
sr = 1000 // (10 - 0)
signal = create_signal(frequency=1, time=time)
pure_tones = []
for k in np.linspace(0, N, N, endpoint=False):
pure_tone = create_pure_tone(frequency=k * sr / N, time=time)
pure_tones.append(pure_tone)
cfs = []
for pure_tone in pure_tones:
mean, sum = plot_fourier_transform(signal,
pure_tone,
plot_mean=True,
plot_sum=True,
plot=False)
cfs.append(sum)
rebuild = plot_inverse_fourier_transform(cfs, pure_tones, time, plot=False)
plt.plot(time, signal, label="signal")
plt.plot(time, rebuild, label="rebuild")
plt.fill_between(time, signal * rebuild, alpha=0.25)
plt.legend()
plt.show()
# np.testing.assert_array_almost_equal(signal, rebuild)
The original signal and the reconstructed signal almost coincide, and the products are all positive!
You can use numpy's unit test to calculate the error point by point:
np.testing.assert_array_almost_equal(signal, rebuild)
Arrays are not almost equal to 6 decimals
Mismatched elements: 996 / 1000 (99.6%)
Max absolute difference: 0.00249961
Max relative difference: 1.05935375
x: array([ 0.000000e+00, 3.758780e-01, 7.428670e-01, 1.092347e+00,
1.416225e+00, 1.707181e+00, 1.958881e+00, 2.166163e+00,
2.325182e+00, 2.433514e+00, 2.490210e+00, 2.495807e+00,...
y: array([ 8.928912e-14-8.203696e-14j, 3.755021e-01-1.757345e-13j,
7.421241e-01-8.970006e-14j, 1.091254e+00-9.888207e-14j,
1.414809e+00-5.689618e-15j, 1.705474e+00-3.955452e-15j,...
The maximum relative error is 1.05935375%.
compare with numpy
The fft effect of numpy is excellent. Although the rebuild I wrote coincides with the ift waveform, the absolute error of ift is less than 14 digits after the decimal point.
# numpy
ft = np.fft.fft(signal)
ift = np.fft.ifft(ft)
plt.plot(time, rebuild, label="rebuild")
plt.plot(time, ift, label="ift")
plt.fill_between(time, rebuild * ift, alpha=0.25, label="product")
plt.legend()
plt.show()
np.testing.assert_array_almost_equal(signal, ift, decimal=20)
Arrays are not almost equal to 20 decimals
Mismatched elements: 1000 / 1000 (100%)
Max absolute difference: 1.875756e-15
Max relative difference: 1.
x: array([ 0.0000000000000000e+00, 3.7587797360061515e-01,
7.4286697945743752e-01, 1.0923466914234694e+00,
1.4162251787527200e+00, 1.7071811899304179e+00,...
y: array([ 0.0000000000000000e+00-9.2967300524549044e-17j,
3.7587797360061515e-01-7.7896022965262552e-17j,
7.4286697945743785e-01+1.0284828544371295e-16j,...
The algorithm complexity of fft is O ( N ⋅ log 2 N ) O(N \cdot log_2 N)O ( N⋅log2N ) , it can only be run when the number of sampling points is an integer power of 2.
symmetry
Remember to mention in the in-depth understanding of Fourier transform (1) : take the selected frequency as the abscissa, and the corresponding wave amplitude as the ordinate, and you will get something called a spectrum, as shown in the following figure:
if "__main__" == __name__:
time = np.linspace(0, 10, 1000)
sr = 1000 // (10 - 0)
signal = create_signal(frequency=1, time=time)
N = signal.size
pure_tones = []
frequencies = []
for k in np.linspace(0, N, N, endpoint=False):
pure_tone = create_pure_tone(frequency=k * sr / N, time=time)
pure_tones.append(pure_tone)
frequencies.append(k * sr / N)
cfs = []
for pure_tone in pure_tones:
mean, sum = plot_fourier_transform(signal,
pure_tone,
plot_mean=True,
plot_sum=True,
plot=False)
cfs.append(sum)
print(len(cfs))
magnitudes = np.abs(cfs)
rebuild = plot_inverse_fourier_transform(cfs, pure_tones, time, plot=False)
plt.plot(frequencies, magnitudes, label="spectrum")
plt.legend()
plt.show()
It is found that this picture is left-right symmetrical, and the center is sr 2 \frac{s_r}{2}2sr。
The reason is: For a periodic signal, if you want to accurately measure this signal, you need to sample at least two times per cycle: once for the peak part and once for the trough part. The more samples per cycle, the more accurately the original signal can be reconstructed. However, if there are less than two samples per cycle, the frequency information of the original signal is completely lost and it is impossible to reconstruct the original signal.
Now our sampling rate for the original signal is sr s_rsr, then it can be seen that this sampling rate allows us to reconstruct the highest frequency contained in the original signal at most as sr 2 \frac{s_r}{2}2srsignal, higher frequency signals cannot be reconstructed.
Theorem: Given a sampling rate, we can reconstruct a periodic signal whose frequency is half of that sampling rate. Half of this sampling rate is called the Nyquist frequency, which is the center of the above figure sr 2 \frac{s_r}{2}2sr。
The next section deals with the short-time Fourier transform.