news 2026/6/7 8:55:13

信号采样入门:用Python和NumPy手把手模拟冲激函数采样(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
信号采样入门:用Python和NumPy手把手模拟冲激函数采样(附完整代码)

信号采样实战:用Python代码模拟冲激函数采样全过程

在数字信号处理领域,采样是将连续时间信号转换为离散时间信号的关键步骤。而冲激函数作为理论基石,其数学抽象性常常让初学者感到困惑。本文将通过Python代码实现,带您直观理解采样原理,把抽象公式转化为可运行的实验。

1. 理解冲激函数的本质

冲激函数(δ函数)在数学上被定义为在原点处无限高、无限窄且面积为1的特殊函数。虽然现实中不存在完美的冲激信号,但它的理论模型对采样分析至关重要。

让我们先用NumPy构造一个近似的冲激序列:

import numpy as np import matplotlib.pyplot as plt def impulse(n, k=0): """生成离散冲激序列""" return np.where(n == k, 1.0, 0.0) n = np.arange(-5, 6) # 时间轴 impulse_seq = impulse(n) plt.stem(n, impulse_seq) plt.title('Discrete Impulse Function') plt.xlabel('n') plt.ylabel('δ[n]') plt.grid(True) plt.show()

这段代码生成的图形会显示在n=0处值为1,其余位置为0的离散序列。这就是离散冲激函数δ[n]的可视化表现。

注意:离散冲激函数与连续冲激函数的区别在于幅值——离散情况下为1,而连续情况下理论上是无穷大(实际实现时用极大值近似)

2. 连续信号的采样模拟

采样过程本质上是将连续信号与冲激串相乘。让我们模拟对一个正弦波进行理想采样的过程:

def continuous_signal(t): """定义连续时间信号""" return np.sin(2 * np.pi * 0.5 * t) # 0.5Hz正弦波 # 采样参数 fs = 5 # 采样频率(Hz) T = 1/fs # 采样间隔 duration = 5 # 信号时长(s) # 生成时间轴 t_continuous = np.linspace(0, duration, 1000) # 高密度点模拟连续 t_samples = np.arange(0, duration, T) # 采样时刻 # 生成信号 x_continuous = continuous_signal(t_continuous) x_samples = continuous_signal(t_samples) # 绘制结果 plt.figure(figsize=(10,4)) plt.plot(t_continuous, x_continuous, 'b-', label='Continuous Signal') plt.stem(t_samples, x_samples, 'r-', markerfmt='ro', basefmt=" ", label='Samples') plt.xlabel('Time (s)') plt.ylabel('Amplitude') plt.legend() plt.grid(True) plt.title('Signal Sampling Demonstration') plt.show()

这段代码展示了:

  1. 蓝色曲线代表原始连续信号
  2. 红色圆点代表采样结果
  3. 采样间隔T=0.2秒(对应fs=5Hz)

3. 冲激串采样的数学实现

理论上的采样是通过冲激串与信号相乘实现的。让我们用代码精确模拟这一数学过程:

def impulse_train(t, fs): """生成冲激串""" samples = np.zeros_like(t) sample_indices = (t * fs).astype(int) valid_indices = (sample_indices >= 0) & (sample_indices < len(samples)) samples[sample_indices[valid_indices]] = 1 return samples # 生成冲激串 impulse_str = impulse_train(t_continuous, fs) # 数学上的采样过程 sampled_signal = x_continuous * impulse_str # 可视化 plt.figure(figsize=(12,8)) plt.subplot(3,1,1) plt.plot(t_continuous, x_continuous) plt.title('Original Continuous Signal') plt.grid(True) plt.subplot(3,1,2) plt.stem(t_continuous, impulse_str, markerfmt='ro', linefmt='r-', basefmt=" ") plt.title('Impulse Train (Sampling Function)') plt.grid(True) plt.subplot(3,1,3) plt.stem(t_continuous, sampled_signal, markerfmt='go', linefmt='g-', basefmt=" ") plt.title('Sampled Signal (Product of Signal and Impulse Train)') plt.grid(True) plt.tight_layout() plt.show()

这个实现清晰地展示了:

  • 原始信号与冲激串相乘的过程
  • 采样结果只在冲激时刻保留信号值
  • 其他时刻乘积为零

4. 采样定理的验证实验

奈奎斯特采样定理指出,采样频率必须大于信号最高频率的两倍才能避免混叠。让我们通过实验验证这一点:

def plot_sampling_effect(f_signal, f_sample): """观察不同采样频率下的效果""" t = np.linspace(0, 3, 1000) x = np.sin(2 * np.pi * f_signal * t) # 采样时刻 sample_t = np.arange(0, 3, 1/f_sample) sample_x = np.sin(2 * np.pi * f_signal * sample_t) # 重建信号(线性插值) reconstructed = np.interp(t, sample_t, sample_x) plt.figure(figsize=(10,6)) plt.plot(t, x, 'b-', lw=2, label='Original') plt.stem(sample_t, sample_x, 'r-', markerfmt='ro', basefmt=" ", label='Samples') plt.plot(t, reconstructed, 'g--', lw=1.5, label='Reconstructed') plt.title(f'Signal Frequency: {f_signal}Hz, Sampling Frequency: {f_sample}Hz') plt.xlabel('Time (s)') plt.ylabel('Amplitude') plt.legend() plt.grid(True) plt.show() # 案例1:满足奈奎斯特条件 (fs > 2*f) plot_sampling_effect(f_signal=2, f_sample=5) # 案例2:不满足奈奎斯特条件 (fs < 2*f) plot_sampling_effect(f_signal=5, f_sample=8) # 看似满足,但实际有高频分量时会出现问题 # 案例3:明显不满足条件 plot_sampling_effect(f_signal=10, f_sample=15)

通过这三个案例,可以直观观察到:

  1. 当采样频率足够高时,重建信号与原始信号几乎一致
  2. 当采样频率不足时,会出现频率混叠现象
  3. 重建信号会表现出低于原始信号的频率成分

5. 实际应用中的采样技巧

在实际工程中,理想采样难以实现。以下是几个实用技巧:

抗混叠滤波器的模拟实现

from scipy import signal def apply_antialiasing(x, fs, cutoff_ratio=0.4): """模拟抗混叠滤波器""" nyquist = fs / 2 b, a = signal.butter(4, cutoff_ratio * nyquist / nyquist, 'low') return signal.filtfilt(b, a, x) # 带高频噪声的信号 noisy_signal = np.sin(2*np.pi*2*t_continuous) + 0.3*np.random.randn(len(t_continuous)) # 应用抗混叠滤波器 filtered_signal = apply_antialiasing(noisy_signal, fs=10) plt.figure(figsize=(10,4)) plt.plot(t_continuous, noisy_signal, 'b-', alpha=0.5, label='Noisy Signal') plt.plot(t_continuous, filtered_signal, 'r-', lw=2, label='Filtered Signal') plt.title('Anti-aliasing Filter Demonstration') plt.xlabel('Time (s)') plt.ylabel('Amplitude') plt.legend() plt.grid(True) plt.show()

采样保持电路的模拟

def sample_and_hold(t_continuous, t_samples, x_samples): """模拟采样保持电路""" return np.interp(t_continuous, t_samples, x_samples) # 生成采样数据 t_samples_sh = np.arange(0, duration, T) x_samples_sh = continuous_signal(t_samples_sh) # 采样保持 sh_signal = sample_and_hold(t_continuous, t_samples_sh, x_samples_sh) # 绘图 plt.figure(figsize=(10,4)) plt.plot(t_continuous, continuous_signal(t_continuous), 'b-', label='Original') plt.stem(t_samples_sh, x_samples_sh, 'r-', markerfmt='ro', basefmt=" ", label='Samples') plt.plot(t_continuous, sh_signal, 'g-', lw=2, alpha=0.7, label='Sample & Hold') plt.title('Sample-and-Hold Circuit Simulation') plt.xlabel('Time (s)') plt.ylabel('Amplitude') plt.legend() plt.grid(True) plt.show()

6. 完整采样系统模拟

将上述组件整合成一个完整的采样系统模拟:

def full_sampling_system(f_signal=1.0, fs=10.0, duration=3.0, noise_level=0.1): """完整的采样系统模拟""" # 1. 生成原始信号(含噪声) t = np.linspace(0, duration, 1000) original = np.sin(2 * np.pi * f_signal * t) + noise_level * np.random.randn(len(t)) # 2. 抗混叠滤波 nyquist = fs / 2 cutoff = 0.4 * nyquist # 保守的截止频率 b, a = signal.butter(4, cutoff / nyquist, 'low') filtered = signal.filtfilt(b, a, original) # 3. 采样 sample_t = np.arange(0, duration, 1/fs) sample_x = np.interp(sample_t, t, filtered) # 4. 采样保持(零阶保持) reconstructed = np.interp(t, sample_t, sample_x) # 计算误差 error = filtered - reconstructed rmse = np.sqrt(np.mean(error**2)) # 绘图 plt.figure(figsize=(12,8)) plt.subplot(3,1,1) plt.plot(t, original, 'b-', label='Original (with noise)') plt.plot(t, filtered, 'r-', lw=2, label='After anti-aliasing filter') plt.title('Input Signal Processing') plt.legend() plt.grid(True) plt.subplot(3,1,2) plt.plot(t, filtered, 'b-', label='Filtered Signal') plt.stem(sample_t, sample_x, 'r-', markerfmt='ro', basefmt=" ", label='Samples') plt.title(f'Sampling Process (fs={fs}Hz, f_signal={f_signal}Hz)') plt.legend() plt.grid(True) plt.subplot(3,1,3) plt.plot(t, filtered, 'b-', label='Original Filtered') plt.plot(t, reconstructed, 'g--', lw=2, label='Reconstructed') plt.title(f'Reconstruction (RMSE: {rmse:.4f})') plt.legend() plt.grid(True) plt.tight_layout() plt.show() # 运行完整系统 full_sampling_system(f_signal=2, fs=10) full_sampling_system(f_signal=4, fs=8) # 边缘情况 full_sampling_system(f_signal=6, fs=10) # 不满足奈奎斯特条件

这个完整系统展示了从原始信号到重建信号的完整流程,包括:

  1. 抗混叠滤波
  2. 理想采样
  3. 信号重建
  4. 误差分析

通过调整输入参数,可以直观观察不同条件下系统的表现。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/7 8:53:01

[智能体-297]:AI取代多数劳动后,人类劳动者何去何从

当人工智能飞速迭代&#xff0c;流水线作业、数据整理、基础文案、标准化客服等大量重复性劳动&#xff0c;正以肉眼可见的速度被AI接管。随之而来的&#xff0c;是大众普遍的焦虑&#xff1a;当机器包揽了人类大部分生产活动&#xff0c;传统劳动者是否会彻底消失&#xff0c;…

作者头像 李华
网站建设 2026/6/7 8:53:00

深度学习在脑电信号解码中的应用:CNN-Mamba混合架构

1. 项目概述&#xff1a;当深度学习遇上脑电信号解码癫痫作为一种常见的慢性神经系统疾病&#xff0c;影响着全球约5000万患者的生活质量。传统脑电图&#xff08;EEG&#xff09;监测需要专业医师长时间观察&#xff0c;不仅效率低下&#xff0c;还容易因疲劳导致误诊。我在神…

作者头像 李华
网站建设 2026/6/7 8:52:01

图像分割中的拓扑约束与宽度感知能量优化

1. 图像分割中的拓扑约束&#xff1a;从理论到实践在计算机视觉领域&#xff0c;图像分割一直是个既基础又具有挑战性的任务。传统分割方法如阈值分割、区域生长和基于边缘检测的方法&#xff0c;往往只关注像素级的分类准确性&#xff0c;而忽视了目标的整体结构特性。这就像是…

作者头像 李华
网站建设 2026/6/7 8:50:23

5步掌握Blender 3MF插件:3D打印文件格式的完整解决方案

5步掌握Blender 3MF插件&#xff1a;3D打印文件格式的完整解决方案 【免费下载链接】Blender3mfFormat Blender add-on to import/export 3MF files 项目地址: https://gitcode.com/gh_mirrors/bl/Blender3mfFormat Blender3mfFormat是一款专为Blender设计的开源插件&am…

作者头像 李华