数字信号处理(Digital Signal Procession)总结

0、导入库

import numpy as np
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import pyplot as plt
from scipy.signal import find_peaks

1、创建时域信号

创建时间序列
T = 0.01 # 采样间隔
fs = 100 # 采样频率
L = 1000 # 采样点数
tl = 0 # 起始时间
tr = tl + (L - 1) * T # 终止时间
t = np.linspace(tl, tr, L)
创建时域信号

以正弦信号为例

def generate_time_domain_sin_signal(t, A, f):pi = np.pix = A * np.sin(2 * pi * f * t)return x
A1 = 1.4
A2 = 0.6
f1 = 16
f2 = 17
x = generate_time_domain_sin_signal(t, A1, f1) + generate_time_domain_sin_signal(t, A2, f2)

画一下,看看效果
在这里插入图片描述

2、傅里叶变换

理论分析
  • 原信号为正弦信号,假设频率为 f 0 f_0 f0的分量幅值为 A 0 A_0 A0,则傅里叶变换后,在f域中,在 f = ± f 0 f=±f_0 f=±f0处的幅值应为 A 0 2 \frac{A_0}{2} 2A0;相角在 f 0 f_0 f0处为 − 90 ° -90° 90°,在 − f 0 -f_0 f0处为 + 90 ° +90° +90°
  • 采样频率为 f s = 100 H z fs=100Hz fs=100Hz,相当于频域卷积梳状函数 f s δ f s ( f ) fs \delta_{fs}(f) fsδfs(f),体现在幅值上,应乘 f s f_s fs
  • 原信号其实是无限信号,但是只采样了 L L L个点,相当于在 t = L ∗ T = 10 s t=L *T=10s t=LT=10s处截断了,相当于乘上了一个 门宽为10,门高为1的矩形窗,相当于频域卷积了一个峰值为10的sinc函数,幅值应乘 L ∗ T L * T LT
  • 综合以上,幅值应乘 L 2 \frac{L}{2} 2L
  • 假如再在原信号的基础上加个别的窗,以hamming窗为例,幅值应乘hamming窗的积分,设积分为 I = ∑ h a m m i n g [ t ] d t I=\sum {hamming[t]dt} I=hamming[t]dt,总幅值的变化倍数为 f s 2 ∗ I = ∑ w i n d o w F u n c t i o n [ i ] 2 \frac{fs}{2}*I=\frac{\sum windowFunction[i]}{2} 2fsI=2windowFunction[i]
创建频率序列

在数字信号处理当中,任何信号的傅里叶变换都以奈奎斯特区间为周期,奈奎斯特区间为 [ 0 , f s ] [0, f_s] [0,fs],对应角频率为 w = [ 0 , 2 p i ] ∗ f s w=[0, 2pi] * fs w=[0,2pi]fs

批注:

奈奎斯特区间对应关系:

  • [ 0 , 1 ] [0,1] [0,1]
  • [ − 0.5 , 0.5 ] [-0.5,0.5] [0.5,0.5]
  • [ 0 , 2 π ] [0,2 \pi] [0,2π]
  • [ − π , π ] [-\pi, \pi] [π,π]
  • [ 0 , f s ] [0, fs] [0,fs]
  • [ − f s 2 , f s 2 ] [-\frac{fs}{2}, \frac{fs}{2}] [2fs,2fs]
  • [ 0 , 2 π f s ] [0, 2 \pi fs] [0,2πfs]
  • [ − π f s , π f s ] [-\pi fs, \pi fs] [πfs,πfs]
w = np.linspace(0, 2 * pi, SAMPLE_N) * fs
f = w / 2 / pi
做DTFT
def DTFT(nT, xn, w):Xw = np.zeros(len(w), dtype=complex)for i, wi in enumerate(w):Xw[i] = np.sum(xn * np.exp(-1j * wi * nT))#  Xw = np.fft.fft(xn)return Xw
Xw = DTFT(t, x, w)

画一下,看看效果

在这里插入图片描述
幅值也满足我们的推导。

归一化

对结果乘 2 L \frac{2}{L} L2进行归一化
在这里插入图片描述

加窗

加个长度为 L L L和hamming窗

def hamming_window(L):a0 = 0.53836return a0 - (1 - a0) * np.cos(2 * np.pi * np.arange(L) / (L - 1))

同时要准备好hanmming窗函数的积分,用于观察幅值变换

画个图,看看效果

时域
在这里插入图片描述
频域
在这里插入图片描述
在这里插入图片描述
非常nice

3、不同傅里叶变换的比较

1)CTFT
def CTFT(x, t, w):"""x[i] and t[i] is the i-th sample of the signal and time,for each w[i], this function will calculate the CTFT of x(t) at w[i].## Examples```pydef g(t):return np.where((t >= -4) & (t <= 4), 2, 0)t_values = np.linspace(-5, 9, SAMPLE_N)g_values = g(t_values)maxw = 10 * np.piw_values = np.linspace(-maxw, maxw, SAMPLE_N)Gw = CTFT(g_values, t_values, w_values)```"""Xw = np.zeros_like(w, dtype=complex)dt = t[1] - t[0]for i, wi in enumerate(w):# Two iterators here, x and tXw[i] = np.sum(x * np.exp(-1j * wi * t) * dt)return Xw

正弦谐波做完CTFT的结果:

在这里插入图片描述

相比于DTFT,CTFT在计算机当中的做法就是用DTFT实现CTFT的效果,但是多乘了个 d t dt dt

2)DTFT

已做过

3)DFT
def DFT(ys):"""Calculate the Discrete Fourier Transform of the signal `ys`,which is an N-point sampling of the DTFT of the signal. ## Examples```pyy = np.array([-1, 2, 3, 0, -2, 1, 4, -3, 0, -2])dft_w_vec, dft_vec = DFT(y)debug_draw(dft_w_vec, np.abs(dft_vec))```"""n = len(ys)ns = np.arange(n)def omega_k(k):return 2 * np.pi * k / nw_vec = np.array([omega_k(k) for k in range(n)])dft_vec = np.array([sum(ys * np.exp(-1j * w * ns)) for w in w_vec])return w_vec, dft_vec

其中w_vec为数字角频率,范围为 [ 0 , 2 p i ] [0,2pi] [0,2pi],若要映射到范围 [ 0 , f s ] [0,fs] [0,fs],则需变换一下

w_dft, Xw_dft = DFT(x)
f_dft = w_dft / 2 / pi * fs

画一下,看看效果
在这里插入图片描述

同时我们还可以使用FFT实现

n_dft = len(x)
Xw_dft = np.fft.fft(x)
Xw_dft = np.fft.fftshift(Xw_dft)
f_dft = np.fft.fftfreq(n_dft, T)
f_dft = np.fft.fftshift(f_dft)

画一下,看看效果

在这里插入图片描述

4、帕斯瓦尔定理的验证

CTFT
print("帕斯瓦尔定理(CTFT)")
energy_time_domain = np.sum(np.abs(x) ** 2) * (t[1] - t[0])
energy_freq_domain = np.sum(np.abs(Xw) ** 2) * (f[1] - f[0])
print(energy_time_domain)
print(energy_freq_domain)
print("-------------")

在这里插入图片描述

DTFT
print("帕斯瓦尔定理(DTFT)")
energy_time_domain = np.sum(np.abs(x) ** 2)
energy_freq_domain = np.sum(np.abs(Xw) ** 2) / len(Xw)
print(energy_time_domain)
print(energy_freq_domain)
print("-------------")

在这里插入图片描述

DFT
print("帕斯瓦尔定理(DFT)")
energy_time_domain = np.sum(np.abs(x) ** 2)
energy_freq_domain = np.sum(np.abs(Xw_dft) ** 2) / n_dft
print(energy_time_domain)
print(energy_freq_domain)
print("-------------")

在这里插入图片描述

门函数的帕斯瓦尔定理

换一个信号,这次选择门函数,验证帕斯瓦尔定理是否正确

tl1 = 0
tr1 = 10
T = 0.01
fs = 100
L = 1000
t1 = np.linspace(tl1, tr1, L)
t1 = np.around(t1, 2)
x1 = np.where((t1 >= 2) & (t1 <= 8), 1, 0)w = np.linspace(0, 2 * pi, SAMPLE_N, endpoint=False) * fs
DTFT
Xw1 = DTFT(t1, x1, w)
print("帕斯瓦尔定理(DTFT)(门函数)")
energy_time_domain = np.sum(np.abs(x1) ** 2)
energy_freq_domain = np.sum(np.abs(Xw1) ** 2) / len(Xw1)
print(energy_time_domain)
print(energy_freq_domain)
print("-------------")

在这里插入图片描述

CTFT
Xw1 = CTFT(x1, t1, w)
print("帕斯瓦尔定理(CTFT)(门函数)")
energy_time_domain = np.sum(np.abs(x1) ** 2) * (t[1] - t[0])
energy_freq_domain = np.sum(np.abs(Xw1) ** 2) * (f[1] - f[0])
print(energy_time_domain)
print(energy_freq_domain)
print("-------------")

在这里插入图片描述

DFT
n1_dft = len(x1)
Xw1_dft = np.fft.fft(x1)
Xw1_dft = np.fft.fftshift(Xw1_dft)
f1_dft = np.fft.fftfreq(n1_dft, T)
f1_dft = np.fft.fftshift(f1_dft)
print("帕斯瓦尔定理(DFT)(门函数)")
energy_time_domain = np.sum(np.abs(x1) ** 2)
energy_freq_domain = np.sum(np.abs(Xw1_dft) ** 2) / n_dft
print(energy_time_domain)
print(energy_freq_domain)
print("-------------")

在这里插入图片描述

5、FFT

基本操作

对一个离散时间序列 x [ n ] x[n] x[n]

SAMPLE_N = 5000
pi = np.pix = np.array([1, 2, -1, -3, 0, 2, 1, 1, 0, -1])
N = len(x)
n = np.arange(N)

做FFT,做完之后,通过fftshift将零频率移到数组的中间

Xw_dft = np.fft.fft(x)
Xw_dft = np.fft.fftshift(Xw_dft)
w_dft = np.fft.fftfreq(N, 1)
w_dft = np.fft.fftshift(w_dft)

比较DTFT与FFT的结果
在这里插入图片描述

zero-padding

在时间序列的最后进行zero_padding,可以增加点数且不改变频率信号的形状

x = np.append(x, np.zeros(20))
N = len(x)
n = np.arange(N)

再次画图
在这里插入图片描述

ifft

n p . f f t . i f f t np.fft.ifft np.fft.ifft使用时需要注意:传进去的数组必须是[零频率项,正频率项,负频率项]
不能将fftshift过的数组传进去
画一下

在这里插入图片描述

跟原数组一样

在这里插入图片描述
zero-padding后也一样

6、FIR滤波器-频率采样法设计滤波器

创建时域信号

先准备一个时域信号,简单包含不同幅值,频率分别为 f 1 = 5 H z , f 2 = 5.5 H z f1=5Hz,f2=5.5Hz f1=5Hz,f2=5.5Hz的两个正弦波叠加,采样频率为 f s = 100 H z fs = 100Hz fs=100Hz,采 L = 1000 L = 1000 L=1000个点

T = 0.01
fs = 100
A1 = 4
A2 = 2
f1 = 5
f2 = 5.5
L = 1000
t = np.linspace(0, (L - 1) * T, L)
t = np.around(t, 2)
x = generate_time_domain_sin_signal(t, A1, f1) + generate_time_domain_sin_signal(t, A2, f2)

画一画x[n]与X[f]

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

可以发现,频谱中有5Hz与5.5Hz两个分量

频域采样

设计一个低通滤波器,把5.5Hz滤掉。
在一个ideal的低通滤波器上采样,设置截止频率为5.25Hz,通带增益为2,阻带增益为0.1

def generate_lowpass_signal(fc, n_samples, passband, stopband):w = np.linspace(0, 2 * pi, n_samples)h = np.zeros(n_samples, dtype=complex)for i, wi in enumerate(w):if (wi <= fc or wi >= 2 * pi - fc):h[i] = passbandelse:h[i] = stopbandreturn h, w
orders = 1000
H, wh = generate_lowpass_signal(5.25 / (fs / 2) * pi, orders, 2, 0.1)

画一画
在这里插入图片描述
画出来也是挺ideal的!

反傅里叶变换

对采出来的滤波器数组进行 i f f t ifft ifft
要注意传进去的数组 遵循【零频率,正频率,负频率】顺序,我们是 [ 0 , 2 π ] [0,2\pi] [0,2π],刚刚好!
做了 i f f t ifft ifft之后也要将零频率移到数组中间

h = np.fft.ifft(H)
h = np.fft.ifftshift(h)
n = np.arange(orders)

画一画,这里将阶数改为100了,因为1000太丑了
在这里插入图片描述

求滤波器的频率响应

先准备一个频率序列 w w w,在 [ − π , π ] [-\pi, \pi] [π,π]中取几千个点

  • 对于FIR滤波器, h [ n ] = b [ n ] , a [ n ] = [ 1 , 0 , 0... ] h[n]=b[n],a[n]=[1,0,0...] h[n]=b[n],a[n]=[1,0,0...]
  • 对于IIR滤波器,也不需要用频率采样哈哈哈
def freqz(bz, az, w):def cap_h_value(bz, az, z: complex):num = sum([bz[i] * z ** (-i) for i in range(len(bz))])den = sum([az[i] * z ** (-i) for i in range(len(az))])return num / dencap_hs = np.array([cap_h_value(bz, az, np.exp(1j * omega)) for omega in w])return cap_hs  # values of H(w)
w_frf = np.linspace(-pi, pi, SAMPLE_N)
H_frf = freqz(h, [1], w_frf)

画一画

在这里插入图片描述
发现还是频谱泄露了很多

缓解频谱泄漏:加个窗

对于一个滤波器序列,序列长度为 o r d e r s orders orders,其零频率在序列中间
加个窗, 长度为 w i n d o w O r d e r windowOrder windowOrder,通常加窗还有一个功能就是减少阶数,所以 w i n d o w O r d e r < o r d e r s windowOrder<orders windowOrder<orders
巧的是,窗函数序列的零频率也在中间

所以有

def hamming_window(L):a0 = 0.53836return a0 - (1 - a0) * np.cos(2 * np.pi * np.arange(L) / (L - 1))
h = h[orders // 2 - window_order // 2 : orders // 2 + window_order // 2] * hamming_window(window_order)

这里以hamming窗为例了

加了窗之后再画一下频响,简直眉清目秀!

在这里插入图片描述
FIR滤波器的相位谱为线性相位,专门只取了200个点,看看相位:
在这里插入图片描述

滤波
def filter(bz, az, x, L):def expand(arr, n):return np.pad(arr, (0, n - len(arr)), 'constant')xs = expand(x, L)ys = np.zeros_like(xs)def y_at(n):return 0 if n < 0 else ys[n]def x_at(n):return 0 if n < 0 else xs[n]for n in range(L):ys[n] = sum([bz[i] * x_at(n - i) for i in range(len(bz))]) - \sum([az[i] * y_at(n - i) for i in range(1, len(az))])return xs, ys
x, y = filter(h, [1], x, L)

这里的阶数设置为500
滤波结果存在y里面

滤波结果分析

滤完之后,首先y的结果,需要把暂态的部分去掉,只看稳态部分
在这里插入图片描述
发现大概300~1000为稳态
把这一部分取出,再加窗缓解频谱泄漏

y = y[300 : 1000] * hamming_window(700)

画一画y的频谱

Yw = np.fft.fft(y)
Yw = np.fft.fftshift(Yw)
w = np.fft.fftfreq(700, T)
w = np.fft.fftshift(w)plot_a_signal(w, np.abs(Yw) * 2 / hamming_intergal(700))

在这里插入图片描述

发现5.5Hz的成分已经被消灭了,且幅值满足增益为2的设定。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/477476.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

医院信息化与智能化系统(22)

医院信息化与智能化系统(22) 这里只描述对应过程&#xff0c;和可能遇到的问题及解决办法以及对应的参考链接&#xff0c;并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图&#xff0c;可以试试PlantUML&#xff0c;告诉GPT你的文件结构&#xff0c;让他给你对应…

01Web3.0行业

目录 一、什么是Web 3.0? 二、Web 1.0 vs Web 2.0 vs Web 3.0 三、为什么选择Web 3.0 四、从法律角度观察Web 3.0 1. Web 3.0前时代的数字身份 问题1&#xff1a;个人信息的过度收集 问题2&#xff1a;个人信息的泄露和滥用 2. Web 3.0的解决方案及其法律问题 问题一&…

width设置100vh但出现横向滚动条的问题

在去做flex左右固定,中间自适应宽度的布局时, 发现这样一个问题: 就是我明明是宽度占据整个视口, 但是却多出了横向的滚动条 效果是这样的 把width改成100%,就没有滚动条了 原因: body是有默认样式的, 会有一定的默认边距, 把默认边距清除就是正常的了 同时, 如果把高度设…

opencv undefined reference to `cv::noarray()‘ 。window系统配置opencv,找到opencv库,但连接不了

之前都是在ubuntu里用opencv&#xff0c;今天为了方便在平时用Window10系统也用下c版的cv&#xff0c;就想配置一下vscode的cv环境&#xff0c;直接下载了一个编译好的opencv库&#xff08;带build文件夹的&#xff09;&#xff0c;刚开始用的是visual studio的编译器&#xff…

php常用伪协议整理

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理php常见的伪协议 php伪协议介绍 直观点&#xff0c;就是php可以识别的协议。 类似于我们访问网站的http协议&#xff0c;我们用浏览器访问我们自己本地文件的file协议等。 php可以识别这些协议&#xf…

神经网络(系统性学习二):单层神经网络(感知机)

此前篇章&#xff1a; 神经网络中常用的激活函数 神经网络&#xff08;系统性学习一&#xff09;&#xff1a;入门篇 单层神经网络&#xff08;又叫感知机&#xff09; 单层网络是最简单的全连接神经网络&#xff0c;它仅有输入层和输出层&#xff0c;没有隐藏层。即&#x…

后端:事务

文章目录 1. 事务2. Spring 单独配置DataSource3. 利用JdbcTemplate操作数据库4. 利用JdbcTemplate查询数据5. Spring 声明式事务6. 事务的隔离级别6.1 脏读6.2 不可重复读6.3 幻读6.4 不可重复读和幻读的区别6.5 三种方案的比较 7. 事务的传播特性8. 设置事务 只读(readOnly)9…

Fakelocation Server服务器/专业版 Windows11

前言:需要Windows11系统 Fakelocation开源文件系统需求 Windows11 | Fakelocation | 任务一 打开 PowerShell&#xff08;以管理员身份&#xff09;命令安装 Chocolatey Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProto…

MySQL系列之身份鉴别(安全)

导览 前言Q&#xff1a;如何保障MySQL数据库身份鉴别的有效性一、有效性检查1. 用户唯一2. 启用密码验证3. 是否存在空口令用户4. 是否启用口令复杂度校验5. 是否设置口令的有效期6. 是否限制登录失败尝试次数7. 是否设置&#xff08;超过尝试次数&#xff09;锁定的最小时长8.…

MySQL面试题补

内连接和外连接的区别&#xff1a; ○1.功能和用法不同&#xff1a;内连接是连接两表都满足情况的数据&#xff1b;而外连接是以一边的表为主表&#xff0c;另一个表只显示匹配的行&#xff1b; ○2.用途&#xff1a;内连接一般是用于检索不同表需要根据共同的列值进行匹配的&a…

线程(三)【线程互斥(下)】

目录 4. 互斥锁4.1 解决数据不一致问题 5. 锁的原理5.1 加锁5.2 解锁 6. 可重入 vs 线程安全 4. 互斥锁 NAMEpthread_mutex_destroy, pthread_mutex_init - destroy and initialize a mutex // 创建、释放锁SYNOPSIS#include <pthread.h>// pthread_mutex_t: 线程库提供…

如何使用AWS Lambda构建一个云端工具(超详细)

首发地址&#xff08;欢迎大家访问&#xff09;&#xff1a;如何使用AWS Lambda构建一个云端工具&#xff08;超详细&#xff09; 1 前言 1.1 无服务器架构 无服务器架构&#xff08;Serverless Computing&#xff09;是一种云计算服务模型&#xff0c;它允许开发者构建和运行…

网络爬虫总结与未来方向

通过深入学习和实际操作&#xff0c;网络爬虫技术从基础到进阶得以系统掌握。本节将全面总结关键内容&#xff0c;并结合前沿技术趋势与最新资料&#xff0c;为开发者提供实用性强的深度思考和方案建议。 1. 网络爬虫技术发展趋势 1.1 趋势一&#xff1a;高性能分布式爬虫 随…

实验十三 生态安全评价

1 背景及目的 生态安全是生态系统完整性和健康性的整体反映&#xff0c;完整健康的生态系统具有调节气候净化污染、涵养水源、保持水土、防风固沙、减轻灾害、保护生物多样性等功能。维护生态安全对于人类生产、生活、健康及可持续发展至关重要。随着城市化进程的不断推进&…

archlinux安装waydroid

目录 参考资料 注意 第一步切换wayland 第二步安装binder核心模组 注意 开始安装 AUR安裝Waydroid 启动waydroid 设置网络&#xff08;正常的可以不看&#xff09; 注册谷歌设备 安装Arm转译器 重启即可 其他 参考资料 https://ivonblog.com/posts/archlinux-way…

鸿蒙NEXT开发案例:随机数生成

【引言】 本项目是一个简单的随机数生成器应用&#xff0c;用户可以通过设置随机数的范围和个数&#xff0c;并选择是否允许生成重复的随机数&#xff0c;来生成所需的随机数列表。生成的结果可以通过点击“复制”按钮复制到剪贴板。 【环境准备】 • 操作系统&#xff1a;W…

【Android】Service使用方法:本地服务 / 可通信服务 / 前台服务 / 远程服务(AIDL)

1 本地Service 这是最普通、最常用的后台服务Service。 1.1 使用步骤 步骤1&#xff1a;新建子类继承Service类&#xff1a;需重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()方法步骤2&#xff1a;构建用于启动Service的Intent对象步骤3&#xff1a;调用st…

【LeetCode热题100】队列+宽搜

这篇博客是关于队列宽搜的几道题&#xff0c;主要包括N叉树的层序遍历、二叉树的锯齿形层序遍历、二叉树最大宽度、在每个数行中找最大值。 class Solution { public:vector<vector<int>> levelOrder(Node* root) {vector<vector<int>> ret;if(!root) …

双因子认证:统一运维平台安全管理策略

01双因子认证概述 双因子认证&#xff08;Two-Factor Authentication&#xff0c;简称2FA&#xff09;是一种身份验证机制&#xff0c;它要求用户提供两种不同类型的证据来证明自己的身份。这通常包括用户所知道的&#xff08;如密码&#xff09;、用户所拥有的&#xff08;如…

Apple Vision Pro开发002-新建项目配置

一、新建项目 可以选择默认的&#xff0c;也可以选择Universal 3D 二、切换打包平台 注意选择Target SDK为Devices SDk&#xff0c;这种适配打包到真机调试 三、升级新的Input系统 打开ProjectSettings&#xff0c;替换完毕之后引擎会重启 四、导入PolySpatial 修改上图红…