计算方法实验8:快速傅里叶变换与快速傅里叶逆变换实现对给定函数的 Fourier 分析及重建

任务

通过快速傅里叶变换与快速傅里叶逆变换实现对给定函数的 Fourier 分析, t ∈ [ 0 , 1 ) t\in[0,1) t[0,1),函数 f f f以及划分数 n n n如下:

  1. f 1 ( t ) = 0.7 sin ⁡ ( 2 π × 2 t ) + sin ⁡ ( 2 π × 5 t ) , n = 2 4 , 2 7 ; f_1( t) = 0. 7\sin ( 2\pi \times 2t) + \sin ( 2\pi \times 5t) , n= 2^4, 2^7; f1(t)=0.7sin(2π×2t)+sin(2π×5t),n=24,27
  2. f 2 ( t ) = 0.7 sin ⁡ ( 2 π × 2 t ) + sin ⁡ ( 2 π × 5 t ) + 0.3 × r a n d o m ( t ) f_2( t) = 0. 7\sin ( 2\pi \times 2t) + \sin ( 2\pi \times 5t) + 0. 3\times random( t) f2(t)=0.7sin(2π×2t)+sin(2π×5t)+0.3×random(t),其中 random(t)为[0,1)区间内的随机数,n= 2 7 2^7 27.
  • 对于每个 f f f n n n, 程序应输出所得到的快速傅里叶变换后的向量 g g g, 将 g g g的每个分量的实部与虚部分开输出;
  • 对于每个 f f f, 将取不同的 n n n获得的 g g g的每个分量模长 ∣ g i ∣ |g_i| gi绘制成图像(为了使图像清晰,如果将不同的 n n n绘制到一张图上请绘制折线图),图像横轴为频率(获取方式见附录), 纵轴为 ∣ g i ∣ |g_i| gi
  • 对于 f 1 f_1 f1, 绘制 f 1 f_1 f1离散化后的图像 ( f 1 , k ) (f_{1,k}) (f1,k), 以及快速傅里叶变换与快速傅里叶逆变换后的最终结果图像。不同的 n n n需绘制在不同的图像上,绘制方式为折线图;
  • 对于 f 2 f_2 f2,绘制 f 2 f_2 f2离散化后的图像 ( f 2 , k ) (f_{2,k}) (f2,k), 快速傅里叶变换与快速傅里叶逆变换后的最终结果图像,以及快速傅里叶变换后取频率域前25%的系数进行快速傅里叶逆变换所得最终结果图像,绘制方式为折线图。

算法

1.FFT

n ← l e n g t h [ f ] n\leftarrow length[f] nlength[f]

if   n = = 1 \textbf{if }n= = 1 if n==1

then   return   f \quad\quad\textbf{then return }f then return f

end   if \textbf{end if} end if

ω n ← e i 2 π / n \omega_n\leftarrow e^{\boldsymbol{i}2\pi/n} ωnei2π/n

ω ← 1 \omega\leftarrow1 ω1

f 0 ← ( f 0 , f 2 , … , f n − 2 ) \mathbf{f}^{0}\leftarrow(f_{0},f_{2},\ldots,f_{n-2}) f0(f0,f2,,fn2)

f 1 ← ( f 1 , f 3 , … , f n − 1 ) \mathbf{f}^{1}\leftarrow(f_{1},f_{3},\ldots,f_{n-1}) f1(f1,f3,,fn1)

g 0 ← \mathbf{g}^0\leftarrow g0FFT ( f 0 ) (\mathbf{f}^0) (f0)

g 1 ← \mathbf{g}^1\leftarrow g1FFT ( f 1 ) (\mathbf{f}^1) (f1)

for   k ← 0 \textbf{for }k\leftarrow 0 for k0 to n / 2 − 1 do n/ 2- 1\textbf{do} n/21do

g k ← g k 0 + ω g k 1 \quad\quad\mathbf{g_k}\leftarrow\mathbf{g}_k^0+\omega\mathbf{g}_k^1 gkgk0+ωgk1

g k + n / 2 ← g k 0 − ω g k 1 \quad\quad\mathbf{g_{k+n/2}}\leftarrow\mathbf{g}_k^0-\omega\mathbf{g}_k^1 gk+n/2gk0ωgk1

ω ← ω ω n \quad\quad\omega\leftarrow\omega\omega_n ωωωn

end   for \textbf{end for} end for

return   g \textbf{return g} return g

2.IFFT

方法1

n ← l e n g t h [ f ] n\leftarrow length[f] nlength[f]

if   n = = 1 \textbf{if }n= = 1 if n==1

then   return   f \quad\quad\textbf{then return }f then return f

end   if \textbf{end if} end if

ω n ← e − i 2 π / n \omega_n\leftarrow e^{\boldsymbol{-i}2\pi/n} ωnei2π/n

ω ← 1 \omega\leftarrow1 ω1

f 0 ← ( f 0 , f 2 , … , f n − 2 ) \mathbf{f}^{0}\leftarrow(f_{0},f_{2},\ldots,f_{n-2}) f0(f0,f2,,fn2)

f 1 ← ( f 1 , f 3 , … , f n − 1 ) \mathbf{f}^{1}\leftarrow(f_{1},f_{3},\ldots,f_{n-1}) f1(f1,f3,,fn1)

g 0 ← \mathbf{g}^0\leftarrow g0IFFT ( f 0 ) (\mathbf{f}^0) (f0)

g 1 ← \mathbf{g}^1\leftarrow g1IFFT ( f 1 ) (\mathbf{f}^1) (f1)

for   k ← 0 \textbf{for }k\leftarrow 0 for k0 to n / 2 − 1 do n/ 2- 1\textbf{do} n/21do

g k ← g k 0 + ω g k 1 \quad\quad\mathbf{g_k}\leftarrow\mathbf{g}_k^0+\omega\mathbf{g}_k^1 gkgk0+ωgk1

g k + n / 2 ← g k 0 − ω g k 1 \quad\quad\mathbf{g_{k+n/2}}\leftarrow\mathbf{g}_k^0-\omega\mathbf{g}_k^1 gk+n/2gk0ωgk1

ω ← ω ω n \quad\quad\omega\leftarrow\omega\omega_n ωωωn

end   for \textbf{end for} end for

g = g / 2 \mathbf{g} = \mathbf{g}/2 g=g/2

return   g \textbf{return g} return g

方法2

f t e m p ← ( f 0 , f n − 1 , f n − 2 … , f 2 ) \mathbf{f_{temp}}\leftarrow(f_{0},f_{n-1},f_{n-2}\ldots,f_{2}) ftemp(f0,fn1,fn2,f2)
g ← \mathbf{g}\leftarrow gFFT ( f t e m p ) (\mathbf{f_{temp}}) (ftemp)
g = g / n \mathbf{g} = \mathbf{g}/n g=g/n
return   g \textbf{return g} return g

代码

C++实现FFT与IFFT

#include<bits/stdc++.h>

using namespace std;

const double PI = acos(-1);
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<> dis(0, 1);

complex<double> f1(double t);
complex<double> f2(double t);
void fft(vector<complex<double>> &a);
void ifft(vector<complex<double>> &a);

int main() {
    ofstream fft_file;
    ofstream discrete;
    ofstream ifft_file;
    cout << "Function 1:\n";
    for (int n : {16, 128}) {
        discrete.open(n == 16 ? "discrete_f1(1).txt" : "discrete_f1(2).txt");
        vector<complex<double>> g1(n);
        for (int i = 0; i < n; i++) {
            g1[i] = f1(i / (double)n);
            discrete << i / (double)n << ' ' << g1[i].real() << endl;
        }
        discrete.close();

        fft(g1);
        
        fft_file.open(n == 16 ? "fft_f1(1).txt" : "fft_f1(2).txt");
        for (int i = 0; i < n; i++) {
            if (i < n / 2)
                fft_file << i + 1 << ' ' << abs(g1[i]) << endl;
            else
                fft_file << i - n << ' ' << abs(g1[i]) << endl;
        }
            
        fft_file.close();
        cout << "FFT of function for n = " << n << endl;
        cout << "Real part:\n";
        for (const auto& x : g1)
            cout << x.real() << ' ';
        cout << endl;
        cout << "Imaginary part:\n";
        for (const auto& x : g1)
            cout << x.imag() << ' ';
        cout << endl << endl;

        vector<complex<double>> inv1 = g1;
        ifft(inv1);
        ifft_file.open(n == 16 ? "ifft_f1(1).txt" : "ifft_f1(2).txt");
        for (int i = 0; i < n; i++)
            ifft_file << i / (double)n << ' ' << inv1[i].real() << endl;
        ifft_file.close();
    }
    fft_file.close();


    cout << "Function 2:\n";
    vector<complex<double>> g2(128);
    discrete.open("discrete_f2.txt");
    for (int i = 0; i < 128; i++) {
        g2[i] = f2((double)i / 128);
        discrete << i / 128.0 << ' ' << g2[i].real() << endl;
    }
    discrete.close();

    fft(g2);

    fft_file.open("fft_f2.txt");
    for (int i = 0; i < 128; i++){
        if (i < 64)
            fft_file << i + 1 << ' ' << abs(g2[i]) << endl;
        else
            fft_file << i - 128 << ' ' << abs(g2[i]) << endl;
    }
    cout << "FFT of function for n = " << 128 << endl;
    cout << "Real part:\n";
    for (const auto& x : g2)
        cout << x.real() << ' ';
    cout << endl;
    cout << "Imaginary part:\n";
    for (const auto& x : g2)
        cout << x.imag() << ' ';
    cout << endl;
    
    vector<complex<double>> inv2 = g2;
    ifft(inv2);
    ifft_file.open("ifft_f2(1).txt");
    for (int i = 0; i < 128; i++)
        ifft_file << (double)i / 128 << ' ' << inv2[i].real() << endl;
    ifft_file.close();

    vector<complex<double>> inv3(g2.begin(), g2.begin() + 32);
    inv3.resize(128, complex<double>(0, 0));
    ifft(inv3);
    ifft_file.open("ifft_f2(2).txt");
    for (int i = 0; i < 128; i++)
        ifft_file << (double)i / 128 << ' ' << inv3[i].real() << endl;
    ifft_file.close();
}

complex<double> f1(double t) {
    return 0.7 * sin(2 * PI * 2 * t) + sin(2 * PI * 5 * t);
}

complex<double> f2(double t) {
    return 0.7 * sin(2 * PI * 2 * t) + sin(2 * PI * 5 * t) + 0.3 * dis(gen);
}

void fft(vector<complex<double>> &a) {
    int n = a.size();
    if (n == 1) 
        return;

    vector<complex<double>> a0(n / 2), a1(n / 2);
    for (int i = 0; 2 * i < n; i++) {
        a0[i] = a[2 * i];
        a1[i] = a[2 * i + 1];
    }

    fft(a0);
    fft(a1);
    
    double ang = 2 * PI / n;
    complex<double> w(1), wn(cos(ang), sin(ang));
    for (int i = 0; 2 * i < n; i++) {
        a[i] = a0[i] + w * a1[i];
        a[i + n / 2] = a0[i] - w * a1[i];
        w *= wn;
    }
}

/*void ifft(vector<complex<double>> &a) {
    int n = a.size();
    reverse(a.begin() + 1, a.end());

    fft(a);

    for (auto& x : a)
        x /= n;
}*/

void ifft(vector<complex<double>> &a) {
    int n = a.size();
    if (n == 1)
        return;

    vector<complex<double>> a0(n / 2), a1(n / 2);
    for (int i = 0; 2 * i < n; i++) {
        a0[i] = a[2 * i];
        a1[i] = a[2 * i + 1];
    }

    ifft(a0);
    ifft(a1);

    double ang = -2 * PI / n; // negative sign
    complex<double> w(1), wn(cos(ang), sin(ang));
    for (int i = 0; 2 * i < n; i++) {
        a[i] = a0[i] + w * a1[i];
        a[i + n / 2] = a0[i] - w * a1[i];
        w *= wn;
    }

    for (auto& x : a)
        x /= 2;
}

python实现结果可视化

f1 FFT

import matplotlib.pyplot as plt

# 读取数据
def read_data(file_path):
    with open(file_path, 'r') as file:
        data = file.readlines()
    x = []
    y = []
    for line in data:
        values = line.split()
        x.append(float(values[0]))
        y.append(float(values[1]))
    return x, y

# 从文件中读取数据
x1, y1 = read_data('fft_f1(1).txt')
x2, y2 = read_data('fft_f1(2).txt')

# 绘制图像
plt.figure(figsize=(12, 6))

plt.plot(x1, y1, marker='o', color='blue', label='n=16')
plt.plot(x2, y2, marker='o', color='red', label='n=128')

plt.title('FFT of f1')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()

plt.tight_layout()
plt.show()

f2 FFT

import matplotlib.pyplot as plt

def read_data(file_path):
    with open(file_path, 'r') as file:
        data = file.readlines()
    x = []
    y = []
    for line in data:
        values = line.split()
        x.append(float(values[0]))
        y.append(float(values[1]))
    return x, y

x, y = read_data('fft_f2.txt')

# 绘制图像
plt.plot(x, y, marker='o', label='FFT of f2')

plt.title('FFT of f2')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()

plt.show()

Discrete and IFFT of f1(1)

import matplotlib.pyplot as plt

# 读取数据
def read_data(file_path):
    with open(file_path, 'r') as file:
        data = file.readlines()
    x = []
    y = []
    for line in data:
        values = line.split()
        x.append(float(values[0]))
        y.append(float(values[1]))
    return x, y

# 从文件中读取数据
x_discrete, y_discrete = read_data('discrete_f1(1).txt')
x_ifft, y_ifft = read_data('ifft_f1(1).txt')

# 绘制图像
plt.figure(figsize=(12, 6))

plt.plot(x_discrete, y_discrete, marker='o', color='blue', label='Discrete f1')
plt.plot(x_ifft, y_ifft, marker='o', color='red', label='IFFT of f1')

plt.title('Discrete and IFFT of f1')
plt.xlabel('x')
plt.ylabel('f1')
plt.legend()

plt.tight_layout()
plt.show()

Discrete and IFFT of f1(2)

import matplotlib.pyplot as plt

# 读取数据
def read_data(file_path):
    with open(file_path, 'r') as file:
        data = file.readlines()
    x = []
    y = []
    for line in data:
        values = line.split()
        x.append(float(values[0]))
        y.append(float(values[1]))
    return x, y

# 从文件中读取数据
x_discrete, y_discrete = read_data('discrete_f1(2).txt')
x_ifft, y_ifft = read_data('ifft_f1(2).txt')

# 绘制图像
plt.figure(figsize=(12, 6))

plt.plot(x_discrete, y_discrete, marker='o', color='blue', label='Discrete f1')
plt.plot(x_ifft, y_ifft, marker='o', color='red', label='IFFT of f1')

plt.title('Discrete and IFFT of f1')
plt.xlabel('x')
plt.ylabel('f1')
plt.legend()

plt.tight_layout()
plt.show()

Discrete and IFFT of f2(1)

import matplotlib.pyplot as plt

# 读取数据
def read_data(file_path):
    with open(file_path, 'r') as file:
        data = file.readlines()
    x = []
    y = []
    for line in data:
        values = line.split()
        x.append(float(values[0]))
        y.append(float(values[1]))
    return x, y

# 从文件中读取数据
x_discrete, y_discrete = read_data('discrete_f2.txt')
x_ifft, y_ifft = read_data('ifft_f2(1).txt')

# 绘制图像
plt.figure(figsize=(12, 6))

plt.plot(x_discrete, y_discrete, marker='o', color='blue', label='Discrete f2')
plt.plot(x_ifft, y_ifft, marker='o', color='red', label='IFFT of f2')

plt.title('Discrete and IFFT of f2')
plt.xlabel('x')
plt.ylabel('f1')
plt.legend()

plt.tight_layout()
plt.show()

Discrete and IFFT of f2(2)

import matplotlib.pyplot as plt

# 读取数据
def read_data(file_path):
    with open(file_path, 'r') as file:
        data = file.readlines()
    x = []
    y = []
    for line in data:
        values = line.split()
        x.append(float(values[0]))
        y.append(float(values[1]))
    return x, y

# 从文件中读取数据
x_discrete, y_discrete = read_data('discrete_f2.txt')
x_ifft, y_ifft = read_data('ifft_f2(2).txt')

# 绘制图像
plt.figure(figsize=(12, 6))

plt.plot(x_discrete, y_discrete, marker='o', color='blue', label='Discrete f2')
plt.plot(x_ifft, y_ifft, marker='o', color='red', label='IFFT of f2')

plt.title('Discrete and IFFT of f2')
plt.xlabel('x')
plt.ylabel('f2')
plt.legend()

plt.tight_layout()
plt.show()

python直接实现FFT和IFFT及结果的可视化

import numpy as np
import matplotlib.pyplot as plt

# 定义函数
def f1(t):
    return 0.7 * np.sin(2 * np.pi * 2 * t) + np.sin(2 * np.pi * 5 * t)

# 设置采样率和时间范围
sample_rates = [128]  # 只使用抽样频率为128的情况
time_duration = 1  # 总时间范围

# 对每个采样率进行FFT并绘图
for sample_rate in sample_rates:
    # 生成采样点
    time_range = np.arange(0, time_duration, 1/sample_rate)
    samples = f1(time_range)

    # 计算FFT
    fft_result = np.fft.fft(samples)
    fft_result = np.fft.fftshift(fft_result)  # Shift zero freq to center

    # 计算频率
    freqs = np.fft.fftfreq(len(samples), d=1/sample_rate)
    freqs = np.fft.fftshift(freqs)  # Shift zero freq to center

    # 计算IFFT
    ifft_result = np.fft.ifft(np.fft.ifftshift(fft_result))

    # 创建一个新的图形窗口
    plt.figure(figsize=(10, 5))

    # 在同一图上绘制f1的离散点折线图和IFFT图像
    plt.plot(time_range, samples, label='f1 discrete points')
    plt.plot(time_range, ifft_result.real, label='IFFT result')
    plt.title(f'f1 discrete points and IFFT result with sample rate {sample_rate}')
    plt.xlabel('Time (s)')
    plt.ylabel('Amplitude')
    plt.grid(True) # 显示网格
    plt.legend()

    # 创建一个新的图形窗口
    plt.figure(figsize=(10, 5))

    # 绘制FFT图像
    plt.plot(freqs, np.abs(fft_result), label='FFT result')
    plt.title(f'FFT of f1 with sample rate {sample_rate}')
    plt.xlabel('Frequency (Hz)')
    plt.ylabel('Amplitude')
    plt.grid(True)
    plt.legend()

    # 显示图形
    plt.show()

结果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里澄江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值