数字信号处理实验(1)-抗混叠滤波器

1. 实验背景与目的

在数字信号处理中,连续时间信号在进入数字系统之前,必须先经过抽样,转换为离散时间序列。教材"连续时间信号的抽样"中指出:若抽样频率选择不当,则抽样后的频谱会发生周期延拓并产生重叠,从而出现频谱混叠。因此,在实际抽样之前,往往需要配置抗混叠滤波器,以抑制高频分量,减小混叠失真。

本实验正是围绕这一主线展开。通过构造一个由 10 kHz 和 70 kHz 两个正弦信号叠加而成的混频信号,先以较高采样率进行仿真,再做 10:1 抽取,观察抽样后频谱的变化;随后分别加入一阶和二阶 RC 低通滤波器,对比不同滤波条件下高频分量的衰减效果,从而验证教材中关于抽样定理、混叠现象以及实际抽样中抗混叠滤波器作用的相关结论。

2. 理论基础

2.1 连续时间信号的抽样

2.2 抽样的频域效应与频谱周期延拓

2.3 抽样定理与混叠

2.4 70 kHz 为什么会混叠到 30 kHz

2.5 实际抽样中的抗混叠滤波器

3.实验信号与参数设置

RC 系统

4.python库函数

import numpy as np,数值计算库。

import matplotlib.pyplot as plt,画图库。

np.arange()

复制代码
x1 = np.arange(0, T_SIM, T_SMP)
#从 0 开始,每次加 2,到 10 之前停止
a = np.arange(0, 10, 2)
print(a)
输出:
[0 2 4 6 8]

np.sin()

复制代码
y1 = np.sin(2 * np.pi * F_SIG * x1)
# 1 Hz 正弦波在几个典型时刻的取值
x = np.array([0, 0.25, 0.5, 0.75, 1.0])
y = np.sin(2*np.pi*x)
print(y)
输出:[0, 1, 0, -1, 0],

x2 = x1[::10],y2 = y1[::10]

复制代码
a = np.array([0,1,2,3,4,5,6,7,8,9])
print(a[::2])
输出:
[0 2 4 6 8]

plt.subplots(2,2)

复制代码
fig, ax = plt.subplots(2, 2)
#创建一个 2 行 2 列的子图窗口
ax[0][0]   ax[0][1]
ax[1][0]   ax[1][1]
你的图就是:
左上:原始时域
左下:原始频域
右上:抽取后时域
右下:抽取后频域

np.fft.fft()

复制代码
np.fft.fft(y1)

#把时域信号拆成"有哪些频率成分"

np.abs()

np.fft.fft(y1),返回的是复数,不是普通实数。有实部、虚部,所以画频谱时通常取模长:

复制代码
np.abs(np.fft.fft(y1))

频率轴

复制代码
freq_x1 = [F_SMP / len(x1) * i for i in range(len(x1))]
#len(x1) 就是数组长度。
#range(1000)表示:0,1,2,3,...,999

5. 三版代码的设计思路

课堂代码一:只有 10 kHz,验证"抽取后不混叠"

复制代码
import numpy as np                    # 数值计算库 
from matplotlib import pyplot as plt  # 画图库 
 
# ========== 参数设置 ========== 
F_SMP = 1e6      # 采样频率 1MHz(每秒采100万个点) Sampling Frequency(采样频率)
T_SIM = 1e-3     # 仿真时长 1ms 
F_SIG = 1e4      # 信号频率 10kHz 
T_SMP = 1/F_SMP  # 采样间隔 = 1/采样频率 = 1μs 
 
# ========== 生成原始信号 ========== 
x1 = np.arange(0, T_SIM, T_SMP)       # 时间轴:0到1ms,步长1μs,共1000个点 
y1 = np.sin(2*np.pi*F_SIG*x1)         # 生成10kHz正弦波 
 
# ========== 10:1抽取(降采样) ========== 
x2 = x1[::10]    # 每隔10个点取1个(采样率从1MHz降到100kHz) 
y2 = y1[::10]    # 对应的信号值 
 
# ========== 画4个子图 ========== 
fig, ax = plt.subplots(2, 2)          # 创建2×2的子图 
 
# 左上:原始信号时域波形 
ax[0][0].plot(x1*1000, y1)            # x轴乘1000把秒转成毫秒 
 
# 右上:抽取后信号时域波形 
ax[0][1].plot(x2*1000, y2) 
 
# 左下:原始信号频谱(FFT) 
ax[1][0].plot( 
    [F_SMP/len(x1)*i for i in range(len(x1))],  # 频率轴 
    np.abs(np.fft.fft(y1))                        # FFT取幅值 
) 
 
# 右下:抽取后信号频谱 
ax[1][1].plot( 
    [F_SMP/10/len(x2)*i for i in range(len(x2))], 
    np.abs(np.fft.fft(y2)) 
) 

#设置 Matplotlib 子图的标题和坐标轴标签
ax[0][0].set_title("Undecimated signal, time")
ax[0][1].set_title("Decimated signal at 10:1, time")
ax[1][0].set_title("Undecimated signal, freq")
ax[1][1].set_title("Decimated signal at 10:1, freq")

ax[0][0].set_xlabel("Time (ms)"); ax[0][0].set_ylabel("Amplitude")
ax[0][1].set_xlabel("Time (ms)"); ax[0][1].set_ylabel("Amplitude")
ax[1][0].set_xlabel("Freq (Hz)"); ax[1][0].set_ylabel("Amplitude")
ax[1][1].set_xlabel("Freq (Hz)"); ax[1][1].set_ylabel("Amplitude")

''Undecimated,"未抽取的"或"未降采样的",指原始、未经抽点的信号。

Decimated,"抽取后的"或"降采样后的",指经过降采样处理的信号。

at 10:1 指抽取比例为 10:1,即每 10 个原始采样点保留 1 个。

time 这里指 Time Domain(时域),显示信号幅度随时间的变化。

freq 是 Frequency 的缩写,指 Frequency Domain(频域),显示信号的频谱成分。''
 
 
plt.tight_layout()  # 自动调整子图间距 
plt.show()          # 显示图形窗口 

关键代码:

复制代码
np.arange(0, T_SIM, T_SMP)
/*生成时间轴:
从 0 到 1 ms
步长 1 us
得到 1000 个采样点。
*/
np.sin(2*np.pi*F_SIG*x1)
/*生成 10 kHz 正弦波:*/
x1[::10]
/*Python 切片语法,意思是:
从头到尾,每隔 10 个取 1 个
这就是 10:1 抽取。
*/

抽取后有效采样率变成:100 kHz

奈奎斯特频率:50 kHz,而信号只有 10 kHz,所以满足:10 kHz<50 kHz

因此不会混叠。

课堂代码二:加 70 kHz,观察混叠

第二版核心就是把信号改成了:

复制代码
y1 = np.sin(2*np.pi*F_SIG1*x1) + np.sin(2*np.pi*F_SIG2*x1)

抽取后新采样率:fs′=100 kHz

奈奎斯特频率:fN=50 kHz

由于:70 kHz>50 kHz,所以发生混叠。

课堂代码三:加入一阶 RC 低通后再抽取

课堂代码四:加入二阶 RC 低通后再抽取

问题:

6.实验结果的整体比较

三版实验可归纳为以下结论:

7.代码:

复制代码
#!/usr/bin/env python3

import numpy as np
from matplotlib import pyplot as plt

F_SMP = 1e6        # 原始采样率 1MHz
T_SIM = 1e-3       # 仿真时间 1ms
F_SIG1 = 1e4       # 信号1:10kHz
F_SIG2 = 70e3      # 信号2:70kHz (新增!)
T_SMP = 1 / F_SMP
FC= 70e3

x1 = np.arange(0, T_SIM, T_SMP)
# 把 10kHz 和 70kHz 的正弦波叠加在一起
y1 = np.sin(2 * np.pi * F_SIG1 * x1) + np.sin(2 * np.pi * F_SIG2 * x1)
"""

k = 1 - np.exp(-2 * np.pi * FC / F_SMP)

# 第一级
y1_filt = np.zeros_like(y1)
y1_filt[0] = y1[0]

# 第二级
y2_filt = np.zeros_like(y1)
y2_filt[0] = y1_filt[0]

for n in range(1, len(y1)):
    y1_filt[n] = y1_filt[n-1] + (y1[n] - y1_filt[n-1]) * k
    y2_filt[n] = y2_filt[n-1] + (y1_filt[n] - y2_filt[n-1]) * k
    """

# 抽取
x2 = x1[::10]
#y2 = y2_filt[::10]
y2 = y1[::10]

fig, ax = plt.subplots(2, 2) 

# 时域画图
ax[0][0].plot(x1 * 1000, y1)
ax[0][1].plot(x2 * 1000, y2, marker='.', linestyle='-') # 加了点(marker)更清楚看到离散点

# 频域画图 (FFT)
freq_x1 = [F_SMP / len(x1) * i for i in range(len(x1))]
ax[1][0].plot(freq_x1, np.abs(np.fft.fft(y1))/len(y1))

freq_x2 = [F_SMP / 10 / len(x2) * i for i in range(len(x2))]
ax[1][1].plot(freq_x2, np.abs(np.fft.fft(y2))/len(y2))

# 设置标题和坐标轴
ax[0][0].set_title("Undecimated signal, time")
ax[0][1].set_title("Decimated signal at 10:1, time")
ax[1][0].set_title("Undecimated signal, freq")
ax[1][1].set_title("Decimated signal at 10:1, freq")

ax[0][0].set_xlabel("Time (ms)"); ax[0][0].set_ylabel("Amplitude")
ax[0][1].set_xlabel("Time (ms)"); ax[0][1].set_ylabel("Amplitude")
ax[1][0].set_xlabel("Freq (Hz)"); ax[1][0].set_ylabel("Amplitude")
ax[1][1].set_xlabel("Freq (Hz)"); ax[1][1].set_ylabel("Amplitude")

# 限制频域显示的范围,方便观察低频部分(选做,但我推荐加上这行)
#ax[1][0].set_xlim(0, 150000) 
#ax[1][1].set_xlim(0, 100000) 

plt.tight_layout()
plt.show()
相关推荐
Mr数据杨2 小时前
不可学习 ImageNet 二分类实战 从图像识别到训练数据投毒防御
学习·机器学习·分类·数据挖掘·数据分析·kaggle
@小博的博客2 小时前
【Linux探索学习】进程的概念及详细解释和一些简单的相关操作
linux·运维·学习
条tiao条2 小时前
鸿蒙 ArkTS 学习入门
学习·华为·harmonyos
雨霁初曦2 小时前
学习通解除粘贴限制完整详细教程(电脑网页版+手机版,含截图示例)
学习·学习通
EnglishJun2 小时前
ARM嵌入式学习(二十四)--- 库移植(移植到开发板)
arm开发·学习
HalvmånEver2 小时前
MySQL数据库表(table)操作
linux·数据库·学习·mysql
后端漫漫2 小时前
Redis学习框架
数据库·redis·学习
safedebug2 小时前
此服务器的证书无效 您可能正在连接到一个伪装
笔记·学习
库奇噜啦呼2 小时前
【iOS】alloc & init & new 源码学习
学习·ios·cocoa