当前位置: 首页 > article >正文

信号与系统学习:傅里叶级数

一、基本概念

1. 什么是傅里叶级数?

傅里叶级数是一种数学工具,可以将一个周期函数分解为一系列正弦和余弦函数(即三角函数)的和。这些正弦和余弦函数的频率是原函数的整数倍

2. 为什么要使用傅里叶级数?

  • 信号分析:将复杂的周期信号分解为简单的正弦和余弦分量,便于分析和处理。
  • 工程应用:在通信、电子、振动分析等领域,用于信号处理、滤波、频谱分析等。

二、周期信号的分解

1. 周期函数的定义

一个函数 f(t) 如果满足:,对于所有的 t,其中 T 是周期,那么 f(t) 就是周期函数

2. 傅里叶级数的表达式

对于周期为 T 的函数 f(t),它可以表示为:

  • ω0=2π/T 是基频角速度
  • a0,an,bn 是傅里叶系数,需要通过积分计算得到

3. 傅里叶系数的计算

(1) 直流分量(平均值) a0
                ​​​​​​​        ​​​​​​​        ​​​​​​​        
(2) 余弦系数 an
        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        
(3) 正弦系数 bn
        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        

三、奇偶函数的傅里叶级数

1. 偶函数的傅里叶级数

如果函数 f(t) 是偶函数,即满足 f(−t)=f(t),则:

  • 所有的正弦系数 bn=0
  • 傅里叶级数只包含余弦项

表达式:

2. 奇函数的傅里叶级数

如果函数 f(t) 是奇函数,即满足 f(−t)=−f(t),则:

  • 所有的余弦系数 an=0
  • 傅里叶级数只包含正弦项

表达式:

四、傅里叶级数的指数形式

1. 欧拉公式

欧拉公式将指数函数与三角函数联系起来:
        ​​​​​​​        ​​​​​​​        ​​​​​​​        

2. 指数形式的傅里叶级数

利用欧拉公式,傅里叶级数可以表示为:
        ​​​​​​​        ​​​​​​​        ​​​​​​​        
 

Cn 是复数形式的傅里叶系数
3. 傅里叶系数 Cn 的计算

                                

实际上,三角形式和指数形式的傅里叶级数是等价的

五、实例解析

例子:周期方波的傅里叶级数展开

1. 定义方波函数

设周期为 T,幅值为 A 的方波 f(t):

  • 在 0<t<T/2 时,f(t)=A
  • 在 −T/2<t<0 时,f(t)=−A
  • 这是一个奇函数
2. 计算傅里叶系数

(1) 由于 f(t) 是奇函数,所有 an=0

(2) 计算正弦系数 bn

 利用对称性和三角函数的性质,经过计算可得:
        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        

注意到:

  • 当 n 为奇数时,sin⁡(nπ/2)=±1
  • 当 n 为偶数时,sin⁡(nπ/2)=0

因此:

  • 当 n 为奇数时

  • 当 n 为偶数时:bn=0

3. 得到傅里叶级数表达式:
                                

六、代码辅助理解

这里为了更直观地理解傅里叶级数如何逼近原始信号
代码1:绘制原始方波和其傅里叶级数的近似

import numpy as np
import matplotlib.pyplot as plt

# 定义参数
A = 1          # 方波幅值
T = 2 * np.pi  # 周期
omega0 = 2 * np.pi / T  # 基频
t = np.linspace(-T, T, 1000)  # 时间轴

# 定义原始方波函数
def square_wave(t):
    return A * np.sign(np.sin(omega0 * t))

# 计算傅里叶级数近似
def fourier_series(t, N):
    f = np.zeros_like(t)
    for n in range(1, N + 1, 2):  # 只取奇数项
        bn = (4 * A) / (n * np.pi)
        f += bn * np.sin(n * omega0 * t)
    return f

# 绘制原始方波
plt.figure(figsize=(12, 6))
plt.plot(t, square_wave(t), label='原始方波', linewidth=2)

# 绘制傅里叶级数近似
N_terms = [1, 3, 5, 9, 19]  # 不同项数的近似
for N in N_terms:
    f_approx = fourier_series(t, N)
    plt.plot(t, f_approx, label=f'傅里叶级数近似 (前 {N} 项)')

plt.title('方波的傅里叶级数近似')
plt.xlabel('时间 t')
plt.ylabel('幅值')
plt.legend()
plt.grid(True)
plt.show()

代码解释:

  • square_wave(t):定义了原始方波函数
  • fourier_series(t, N):计算傅里叶级数的前 N 项近似
  • N_terms:选择不同的项数来观察傅里叶级数的逼近效果

运行结果:

  • 当 N 较小时,傅里叶级数的近似效果不佳,出现明显的波动(吉布斯现象)
  • 随着 N 的增加,傅里叶级数对方波的逼近越来越精确

 

如右上角图例:蓝色的是源波形,下面的即是随着级数增加逐渐逼近

代码2:傅里叶级数分解锯齿波:

import numpy as np
import matplotlib.pyplot as plt

# 定义参数
A = 1          # 锯齿波幅值
T = 2 * np.pi  # 周期
omega0 = 2 * np.pi / T  # 基频
t = np.linspace(-T, T, 1000)  # 时间轴

# 定义原始锯齿波函数
def sawtooth_wave(t):
    return 2 * A * (t / T - np.floor(t / T + 0.5))

# 计算傅里叶级数近似
def fourier_series(t, N):
    f = np.zeros_like(t)
    for n in range(1, N + 1):
        bn = (-2 * A) / (n * np.pi) * ((-1)**n)
        f += bn * np.sin(n * omega0 * t)
    return f

# 绘制原始锯齿波
plt.figure(figsize=(12, 6))
plt.plot(t, sawtooth_wave(t), label='原始锯齿波', linewidth=2)

# 绘制傅里叶级数近似
N_terms = [1, 5, 10, 20, 50]  # 不同项数的近似
for N in N_terms:
    f_approx = fourier_series(t, N)
    plt.plot(t, f_approx, label=f'傅里叶级数近似 (前 {N} 项)')

plt.title('锯齿波的傅里叶级数近似')
plt.xlabel('时间 t')
plt.ylabel('幅值')
plt.legend()
plt.grid(True)
plt.show()

代码解释:

  • sawtooth_wave(t):定义了一个锯齿波,它比方波复杂得多,包含更多的频率分量
  • fourier_series(t, N):计算傅里叶级数的前 N 项近似,这次我们没有限制为奇数项,包含了所有频率分量
  • N_terms:从 1 项增加到 50 项,通过不同的傅里叶级数项数来逼近原始锯齿波

运行结果:
随着傅里叶级数的项数增加,锯齿波的傅里叶级数逐渐从简单的正弦波逼近一个复杂的锯齿形状。特别是,当项数达到较高值时(如 50 项),傅里叶级数几乎完全重构了锯齿波

这里应该就能感受到傅里叶级数将一个复杂信号分解为简单的正弦分量后,再通过这些分量逐步还原原始信号的过程了。傅里叶级数的魅力在于,无论信号多么复杂,它都可以被分解为不同频率的正弦波,且通过增加高频项的数量,可以逐渐还原信号的原始形态

代码3:叠加信号的傅里叶级数

import numpy as np
import matplotlib.pyplot as plt

# 定义参数
A1, A2, A3 = 1, 0.5, 0.75  # 锯齿波、三角波、方波的幅值
T = 2 * np.pi  # 周期
omega0 = 2 * np.pi / T  # 基频
t = np.linspace(-T, T, 1000)  # 时间轴

# 定义原始信号:锯齿波、三角波、方波叠加
def complex_wave(t):
    sawtooth = 2 * A1 * (t / T - np.floor(t / T + 0.5))  # 锯齿波
    triangle = A2 * (8 / np.pi**2) * np.sum([((-1)**n) * np.cos((2*n+1) * omega0 * t) / (2*n+1)**2 for n in range(20)], axis=0)  # 三角波
    square = A3 * np.sign(np.sin(omega0 * t))  # 方波
    return sawtooth + triangle + square  # 叠加成复杂信号

# 计算傅里叶级数近似
def fourier_series(t, N):
    f = np.zeros_like(t)
    for n in range(1, N + 1):
        # 锯齿波的傅里叶系数
        bn_sawtooth = (-2 * A1) / (n * np.pi) * ((-1)**n)
        f += bn_sawtooth * np.sin(n * omega0 * t)
        
        # 三角波的傅里叶系数
        if n % 2 != 0:  # 只有奇数项有非零系数
            bn_triangle = (8 * A2) / (n**2 * np.pi**2)
            f += bn_triangle * np.sin(n * omega0 * t)
        
        # 方波的傅里叶系数
        if n % 2 != 0:  # 只有奇数项有非零系数
            bn_square = (4 * A3) / (n * np.pi)
            f += bn_square * np.sin(n * omega0 * t)
            
    return f

# 绘制原始复杂信号
plt.figure(figsize=(12, 6))
plt.plot(t, complex_wave(t), label='原始复杂信号', linewidth=2)

# 绘制傅里叶级数近似
N_terms = [1, 5, 10, 20, 50]  # 不同项数的近似
for N in N_terms:
    f_approx = fourier_series(t, N)
    plt.plot(t, f_approx, label=f'傅里叶级数近似 (前 {N} 项)')

plt.title('复杂信号的傅里叶级数近似')
plt.xlabel('时间 t')
plt.ylabel('幅值')
plt.legend()
plt.grid(True)
plt.show()

解释:

  • complex_wave(t):这是一个更加复杂的周期信号,由锯齿波、三角波和方波叠加而成。每个波形的幅值不同。
  • fourier_series(t, N):计算傅里叶级数的前 N 项近似。它分别为锯齿波、三角波和方波计算傅里叶系数,并叠加它们的贡献。
  • N_terms:通过不同的傅里叶级数项数来逼近原始复杂信号

运行结果:

  • 当 N=1 时,傅里叶级数只是一个简单的正弦波,无法很好地还原复杂的信号
  • 随着 N 的增加(如 N=50),傅里叶级数能够逼近更复杂的信号形状

 


http://www.kler.cn/news/363897.html

相关文章:

  • CSS 网格布局
  • 讲个故事:关于一次接口性能优化的心里路程
  • 高薪、高含金量、高性价比的“三高”证书——PMP证书
  • 15.正则化——防止过拟合的有效手段
  • 初始JavaEE篇——多线程(2):join的用法、线程安全问题
  • Xamarin学习计划
  • HarmonyOS 最新API12 创建云端一体化项目(带图展示)
  • 基于stm32的楼宇照明控制系统设计
  • 代码解释(10.20)
  • Oracle 第2章:安装与配置Oracle
  • react18中在列表项中如何使用useRef来获取每项的dom对象
  • 博饼代码【Python】
  • WPF MVVM模式实现DataGrid编辑
  • vue2.x 的依赖收集通知更新
  • 【力扣 | SQL题 | 每日4题】力扣1164,3293,1308,1270
  • 【scene_manager_msgs】ROS2 自定义消息、服务的包
  • 动态规划:17.简单多状态 dp 问题_买卖股票的最佳时机III_C++
  • OpenCV高级图形用户界面(17)设置一个已经创建的滚动条的最小值函数setTrackbarMin()的使用
  • 七、高级查询和数据操作及数据完整性和约束
  • 基于Linux来讲解Kconfig的基础知识
  • 【2024版】sql-liabs靶场前十关解题过程和思路----适合入门小白
  • Appium环境搭建全流程(含软件)
  • Java项目-基于springboot框架的社区疫情防控平台系统项目实战(附源码+文档)
  • React 纯手写一个 Modal 组件,除了样式不太美观以外,其他功能都不错呢?附上全部源码
  • vscode ssh连接远程服务器一直卡在正在打开远程
  • linux,socket编程,select,poll,epoll学习