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

news2024/11/26 11:07:11

一、基本概念

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.coloradmin.cn/o/2222961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【STM32+HAL】OV2640捕获图像显示

一、准备工作 有关CUBEMX的初始化配置&#xff0c;参见我的另一篇blog&#xff1a;【STM32HAL】CUBEMX初始化配置 二、所用工具 1、芯片&#xff1a; STM32F407ZGT6 2、IDE&#xff1a; MDK-Keil软件 3、库文件&#xff1a;STM32F4xxHAL库 三、实现功能 通过OV2640捕获图像…

Flutter UI组件库(JUI)

Flutter UI组件库 (JUI) 介绍 您是否正在寻找一种方法来简化Flutter开发过程&#xff0c;并创建美观、一致的用户界面&#xff1f;您的搜索到此为止&#xff01;我们的Flutter UI组件库&#xff08;JUI&#xff09;提供了广泛的预构建、可自定义组件&#xff0c;帮助您快速构建…

为什么会配置足够打LOL等网游很卡?12代大小核处理器最典型

卡顿原因及优化建议 大小核调度问题&#xff1a; 调度不当&#xff1a;某些游戏未针对大小核进行优化&#xff0c;可能导致系统将负载分配到效率核&#xff08;小核&#xff09;&#xff0c;而性能核&#xff08;大核&#xff09;未被充分利用。操作系统调度策略&#xff1a;尽…

15.6 JDBC数据库编程6——可滚动和可更新的ResultSet

目录 15.6 引言 15.6.1 可滚动的ResultSet 15.6.1 可更新的ResultSet 15.6 引言 可滚动的ResultSet是指在结果集对象上不但可以向前访问结果集中的记录&#xff0c;还可以向后访问结果集中记录。可更新的ResultSet是指不但可以访问结果集中的记录&#xff0c;还可以更新…

文件操作(1) —— 文件基础知识

目录 1. 为什么使用文件&#xff1f; 2. 文件种类【按功能分】 3. 文件名 4. 数据文件种类【按存储方式细分】 5. 文件的打开和关闭 5.1 流和标准流 5.2 文件指针 5.3 文件的打开和关闭函数 6. 文件缓冲区 1. 为什么使用文件&#xff1f; 如果没有⽂件&#xff0c;我…

Vue笔记-浏览器窗口改变时,重新计算表格高度并设置

当窗口大小改变时&#xff0c;你监听 window 对象的 resize 事件&#xff0c;然后在事件处理程序中重新计算表格的高度。在 Vue 中&#xff0c;可以在组件中通过 created 生命周期钩子来添加事件监听器&#xff0c;然后在组件销毁时移除事件监听器。 如下vue代码&#xff1a; …

Android GPU Inspector分析帧数据快速入门

使用 谷歌官方工具Android GPU Inspector (AGI) 可以对Android 应用进行深入和全面的系统性能分析和帧性能分析 。AGI 是一个非常强大的分析工具&#xff0c;尤其是在需要诊断 GPU 性能问题和优化应用时&#xff0c;可以帮助你精准找到性能瓶颈。本文介绍如何使用该工具对帧数据…

24V转3.3V2A同步降压WT6030

24V转3.3V2A同步降压WT6030 WT6030 是一种高效同步整流降压开关模式转换器&#xff0c;集成内部功率 MOSFET&#xff0c;能在宽输入电源范围内提供较高的输出电流&#xff0c;以下是使用 WT6030 将 24V 降压到 3.3V 输出 2A 电流的相关设计要点&#xff1a; 1. 电路设计 输入电…

零基础Java第九期:一维数组(二)和二维数组

目录 一、数组的练习 1.1. 顺序表查找 1.2. 二分查找 1.3. 冒泡排序 二、二维数组 2.1. 二维数组的性质 2.2. 不规则二维数组 一、数组的练习 1.1. 顺序表查找 题目描述&#xff1a;给定一个数组, 再给定一个元素, 找出该元素在数组中的位置。 利用for循环去遍历数组&am…

听一听语音助手的声音

分享自制树莓派语音助手的博文也有一些日子了&#xff0c;今天咱们来听听语音助手自己的声音。 上图是本次对话的log记录&#xff0c;从图上可以看到&#xff0c;主要的对话耗时是用于录音&#xff08;默认5秒&#xff09;和语音识别&#xff08;平均5秒&#xff09;这两个组件…

【数据结构】包装类简单认识泛型-Java

包装类 在Java中&#xff0c;由于基本类型不是继承自Object&#xff0c;为了在泛型代码中可以支持基本类型&#xff0c;Java给每个基本类型都给了一个包装类型 基本数据类型和对应的包装类 基本数据类型包装类ByteByteshortShortint Integer longLongfloatFloatdoubleDoublec…

洞察前沿趋势!2024深圳国际金融科技大赛——西丽湖金融科技大学生挑战赛技术公开课指南

在当前信息技术与“互联网”深度融合的背景下&#xff0c;金融行业的转型升级是热门话题&#xff0c;创新与发展成为金融科技主旋律。随着区块链技术、人工智能技术、5G通信技术、大数据技术等前沿科技的飞速发展&#xff0c;它们与金融领域的深度融合&#xff0c;正引领着新型…

模型的部署:服务端与客户端建立连接(Flask)

目录 一、服务端部署&#xff08;使用Flask&#xff09; 1.安装Flask 2.加载模型&#xff08;这里以识别图片的类型模型为例&#xff09; 3.定义API端点 4.运行Flask应用 二、客户端请求 1.安装HTTP客户端库 2.发送请求 请求成功示例&#xff1a; 监控与日志 总结 在…

物联网消息队列Emqx日志配置及日志追踪以及Centos7上的rc.local开机不执行、git提交的小问题

一、物联网消息队列Emqx日志配置及日志追踪 EMQX支持将日志输出到控制台或者日志文件&#xff0c;或者同时使用两者。使用 Docker 部署 EMQX&#xff0c;默认只能通过 docker logs 命令查看 EMQX 日志。EMQX 的默认日志级别为 warning&#xff0c;默认在单日志文件超过10MB(log…

nginx 隐藏版本号与WEB服务器信息

nginx 隐藏版本号与WEB服务器信息 1.安装相关软件2.下载软件包解压并进入3.修改C文件4.编译配置./configure --prefix/usr/local/nginx5.编译安装make && make install5.1.错误处理15.2.错误处理25.2.编译安装make && make install 6.修改nginx配置文件,http节…

【Vue】Vue3.0(十四)接口,泛型和自定义类型的概念及使用

上篇文章&#xff1a; 【Vue】Vue3.0&#xff08;十三&#xff09;中标签属性ref&#xff08;加在普通标签上、加在组件标签上&#xff09;、局部样式 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Vue专栏&#xff1a;点击&#xff01; ⏰️创作时间&…

从0开始深度学习(20)——延后初始化和自定义层

一般情况下&#xff0c;模型参数在被创建时就被立即初始化了&#xff0c;但如果使用了延后初始化技术&#xff0c;就能在首次传入数据后&#xff0c;再初始化参数&#xff0c;旨在输入维度未知的情况下&#xff0c;预定义灵活的模型&#xff0c;动态推断各个层的参数大小。 有时…

robosense 激光雷达安装

官方github 1、ROBOSENSE 驱动安装并运行 1、改雷达型号 2、修改网口地址 3、改变点的类型 https://github.com/RoboSense-LiDAR/rslidar_sdk/blob/main/doc/howto/05_how_to_change_point_type.md 2、ROBOSENSE 点云转换成 velodyne git clone https://github.com/HVikto…

Linux 部署 Harbor 镜像仓库详解

文章目录 安装 Docker安装 Harbor访问 Harbor 安装 Docker 本次部署流程使用的是1台阿里云ECS&#xff1a; Ubuntu 22.04&#xff0c;2核4G开放 9999 端口号 首先需要做的是在当前服务器上&#xff0c;安装好 Docker&#xff0c;参考链接如下&#xff1a; https://blog.csdn.n…

算法(四)前缀和

前缀和也是一个重要的算法&#xff0c;一般用来快速求静态数组的某一连续区间内所有数的和&#xff0c;效率很高&#xff0c;但不支持修改操作。分为一维前缀和、二维前缀和。 重要的前言&#xff01; 不要死记模板&#xff0c;具体题目可能是前缀和、前缀乘积、后缀和、后缀乘…