基于小波变换的脉搏信号去噪与分类识别实战

发布时间:2026/10/9 20:59:08

基于小波变换的脉搏信号去噪与分类识别实战 简介这份由同济大学完成的脉搏识别资料包面向生物医学工程、信号处理方向的学生与科研人员聚焦小波分析在脉搏信号去噪、特征提取与分类识别中的完整实现。包内共8个文件以4个m脚本为核心配合2个doc与1个docx说明文档、1个xlsx数据表整体约39KB涵盖采样频率设定、参数提取要求及butterlow、butterband、butterhigh等滤波函数便于直接运行与二次修改。已有237人学习下载。读者可借此掌握小波变换将一维脉搏信号转为多尺度表示、提取周期性与振幅特征并借助SVM或神经网络区分正常与异常脉搏的完整流程是理解信号识别与分类落地的实用参考。1. 脉搏信号分析从一份压缩包开始小波变换加分类到底能解决什么一份名为「脉搏识别」的压缩包里面塞着采集到的脉搏波形、一段小波处理脚本、一个分类器训练流程这大概是很多做生理信号方向的开发者都见过的场景。脉搏信号分析这件事核心难点不在采集而在于波形太「软」——它幅度小、频率低、极易被基线漂移和工频干扰淹没直接拿原始序列去喂分类器准确率往往惨不忍睹。小波变换在这里扮演的角色就是把一维时域波形拆成不同尺度上的细节系数和近似系数让噪声和有效成分在频带上分开再从中挑出真正有判别力的特征送进分类模型。这套「小波去噪 特征提取 分类」的组合适合做可穿戴健康监测、中医脉象辅助分析、运动心率变异性研究的人也适合手里已经有一批脉搏数据、想跑通一个端到端识别流程的工程师。下面我按自己实际搭过的路径把这条链路拆开讲清楚。2. 脉搏波形为什么必须先过小波从采样到预处理的完整链路脉搏信号本质是动脉血管壁随心脏搏动产生的压力波典型基频在 0.82 Hz 之间但它的形态信息藏在更高频的细节里比如重搏波切迹、上升支斜率。问题在于采集设备一动、呼吸一深基线就会漂市电和电磁环境又会往信号里灌 50 Hz 左右的干扰。如果直接做 FFT你只能看到全局频率分布看不到「这个切迹出现在第几个心跳周期」这种时间定位信息。小波变换的价值就在于它同时保留时间和尺度信息这是脉搏分析里绕不开的一步。2.1 小波去噪的三个参数怎么定小波基、分解层数、阈值规则先明确一件事脉搏信号去噪不是层数越多越好。分解层数太深低频近似系数会把重搏波这种关键形态抹平层数太浅高频噪声又压不干净。我一般按采样率来推假设采样率 fs脉搏有效成分上限大约在 40 Hz 以内那么分解层数 L 满足fs / 2^L ≈ 40就够了。比如 fs500 HzL 取 34 层比较稳。小波基的选择上db6 和 sym8 是我在脉搏数据上试下来比较平衡的前者消失矩高、对平滑波形友好后者近似对称、相位失真小。阈值规则用软阈值比硬阈值更平滑不容易在重构波形上留下台阶状伪影。import pywt import numpy as np def wavelet_denoise(signal, waveletdb6, level4, modesoft): 对脉搏信号做小波去噪 signal: 一维 numpy 数组原始脉搏序列 wavelet: 小波基脉搏常用 db6 / sym8 level: 分解层数按 fs/2^level ≈ 40Hz 估算 mode: 阈值模式soft 更平滑hard 保留尖峰 # 1. 小波分解拿到近似系数和各层细节系数 coeffs pywt.wavedec(signal, wavelet, levellevel) # 2. 用第一层细节系数估计噪声标准差Donoho 通用阈值 sigma np.median(np.abs(coeffs[-1])) / 0.6745 threshold sigma * np.sqrt(2 * np.log(len(signal))) # 3. 对每一层细节系数做阈值收缩近似系数不动 coeffs_thresh [coeffs[0]] for c in coeffs[1:]: coeffs_thresh.append(pywt.threshold(c, threshold, modemode)) # 4. 重构回时域 denoised pywt.waverec(coeffs_thresh, wavelet) return denoised[:len(signal)] # 重构长度可能多 1 个点截断对齐这段代码里最关键的是阈值计算那一步。np.median(np.abs(coeffs[-1])) / 0.6745是 Donoho 提出的鲁棒噪声估计用中位数而不是标准差是为了避免个别大幅值细节系数把噪声估计拉高。阈值本身用sigma * sqrt(2 * ln(N))N 是信号长度信号越长阈值越高这是符合统计规律的。如果你发现去噪后波形变「肉」了、切迹变钝就把 level 降一层如果还残留明显毛刺就把 mode 换成 hard 或者手动把 threshold 乘 1.2。2.2 从去噪波形到特征向量时域和频域各取什么去噪只是第一步分类器不认波形只认特征向量。脉搏特征我一般分两组取。时域这组主波峰幅度、上升支时间、重搏波相对幅度、相邻峰间隔也就是脉率、峰间隔标准差反映节律稳定性。频域这组对去噪信号做小波包分解取各频带的能量占比尤其是 010 Hz 和 1040 Hz 两个带的能量比这个比值对区分不同脉象类型有实际判别力。import numpy as np from scipy.signal import find_peaks def extract_pulse_features(signal, fs): 从去噪后的脉搏信号提取时域频域特征 signal: 去噪后的一维脉搏序列 fs: 采样率 返回: 特征字典 feats {} # --- 时域特征 --- # 找主波峰距离至少 0.4s对应最高 150bpm prominence 过滤小波动 peaks, props find_peaks(signal, distanceint(0.4 * fs), prominence0.3 * np.std(signal)) if len(peaks) 2: return None # 有效搏动太少这条样本丢弃 feats[peak_amplitude_mean] float(np.mean(signal[peaks])) intervals np.diff(peaks) / fs # 相邻峰间隔单位秒 feats[pulse_rate] float(60.0 / np.mean(intervals)) feats[interval_std] float(np.std(intervals)) # --- 频域特征小波包能量占比 --- wp pywt.WaveletPacket(signal, db4, modesymmetric, maxlevel4) total_energy np.sum(signal ** 2) 1e-12 low_band np.sum(wp[aaaa].data ** 2) # 0~约10Hz feats[low_band_ratio] float(low_band / total_energy) return featsfind_peaks里的distance参数是防止把重搏波误判成主波峰0.4 秒对应理论上限 150 bpm正常静息脉搏不会超过这个值。prominence用标准差的 0.3 倍做门槛是为了滤掉基线残余抖动。小波包那部分maxlevel4配合 db4在 fs500 Hz 时aaaa节点大致覆盖 015 Hz正好是脉搏主能量区。这些参数不是死的你换数据集就得重新看一眼峰检测结果别闭着眼睛套。3. 分类器怎么选怎么训从特征矩阵到可复现的识别流程特征提出来之后摆在面前的问题是选什么分类器。脉搏识别这种场景样本量通常不大几百到几千条特征维度也就十几维。这种「小样本、低维度」的局上深度学习是杀鸡用牛刀还容易过拟合。我一般先用 SVM 打底再拿随机森林做对照两者在脉搏数据上的表现往往很接近但 SVM 调参更直观。3.1 特征标准化和数据集划分别在划分之前做标准化这是血泪经验标准化一定要在训练集上 fit再 transform 到测试集。如果你先把整个数据集标准化再划分测试集的均值方差信息就泄漏进训练过程了交叉验证分数会虚高上线就翻车。from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report import numpy as np # X: (n_samples, n_features) 特征矩阵, y: 标签 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.25, stratifyy, random_state42 ) # 标准化只在训练集 fit scaler StandardScaler() X_train_s scaler.fit_transform(X_train) X_test_s scaler.transform(X_test) # 注意这里是 transform不是 fit_transform # SVMRBF 核C 和 gamma 用网格搜索定 svm SVC(kernelrbf, C10, gammascale, class_weightbalanced) svm.fit(X_train_s, y_train) print(classification_report(y_test, svm.predict(X_test_s))) # 随机森林做对照 rf RandomForestClassifier(n_estimators200, max_depth8, random_state42) rf.fit(X_train_s, y_train) print(classification_report(y_test, rf.predict(X_test_s)))stratifyy保证划分后各类比例一致样本不均衡时这个参数必须加。class_weightbalanced让 SVM 对少数类样本加大惩罚避免模型偏向多数类。随机森林的max_depth8是防过拟合的脉搏特征维度低树太深没意义。两个模型跑完对比一下如果 SVM 明显好于 RF说明特征和类别边界比较平滑如果 RF 反超可能是特征里有非线性交互可以考虑加点组合特征。3.2 交叉验证和混淆矩阵看清模型到底错在哪一类单看准确率没意义脉搏识别里不同类别的误判代价不一样。比如把「节律不齐」判成「正常」比反过来严重得多。所以必须看混淆矩阵。from sklearn.model_selection import cross_val_score, StratifiedKFold from sklearn.metrics import confusion_matrix import seaborn as sns import matplotlib.pyplot as plt # 5 折分层交叉验证看分数稳定性 cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) scores cross_val_score(svm, X_train_s, y_train, cvcv, scoringf1_macro) print(fCV F1-macro: {scores.mean():.3f} ± {scores.std():.3f}) # 混淆矩阵 cm confusion_matrix(y_test, svm.predict(X_test_s)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues) plt.xlabel(Predicted) plt.ylabel(True) plt.show()用f1_macro而不是 accuracy是因为它对每个类别一视同仁不会被多数类拉高。如果 CV 的 std 超过 0.05说明数据划分对结果影响大要么样本太少要么特征区分度不够得回去看特征工程。混淆矩阵里如果某一列特别亮说明模型对这个类有系统性偏好检查一下是不是这个类的样本在特征空间里和别的类重叠了。4. 脉搏识别落地时最容易踩的五个坑这一章是我自己踩过、也见过别人反复踩的地方按「现象 → 原因 → 解决」写你对着排查能省不少时间。4.1 去噪后波形整体偏移峰检测全乱现象小波重构出来的波形和原始波形对不上整体上下平移find_peaks找出来的峰位置全错。原因小波重构时边界处理没做好waverec默认的边界延拓方式在信号两端会产生畸变而且重构长度可能比原信号多一个点直接拿去对齐就错位了。解决重构后强制截断到原长度denoised[:len(signal)]并且对首尾各 10% 的数据不做峰检测或者改用modeperiodization做分解边界畸变会小很多。4.2 分类准确率虚高换一批数据就崩现象在自己数据集上交叉验证 95% 以上拿新采集的一批数据一测掉到 60%。原因标准化泄漏是最常见的一个另一个是特征里混进了和采集设备相关的量比如绝对幅度。不同设备增益不同绝对幅度根本没有泛化性。解决标准化严格在训练集 fit特征尽量用比值、斜率、时间间隔这类无量纲量少用绝对幅度。如果必须用幅度先做 z-score 归一化。4.3 样本不均衡导致少数类全被吞现象混淆矩阵里少数类几乎全被判成多数类recall 接近 0。原因脉搏数据里正常样本远多于异常样本分类器默认优化整体准确率就把少数类牺牲了。解决class_weightbalanced是最省事的再进一步可以用 SMOTE 做少数类过采样但注意 SMOTE 只能在训练集上做而且做完要重新标准化。我一般先试 class_weight不够再上 SMOTE。4.4 小波分解层数照搬教程结果切迹消失现象去噪后重搏波切迹变平特征里「重搏波相对幅度」全是接近 0 的值。原因分解层数太深近似系数把高频形态信息一起平滑掉了。解决按fs / 2^L ≈ 40重新算层数或者干脆把近似系数也纳入阈值处理范围别只处理细节系数。判断标准很简单去噪前后把波形叠在一起看切迹位置如果对不上就是层数深了。4.5 训练时随机种子没固定结果无法复现现象同样的代码跑两遍准确率差好几个百分点调参调了个寂寞。原因train_test_split、StratifiedKFold、随机森林的random_state没设每次划分和初始化都不一样。解决所有涉及随机的环节统一设random_state42包括划分、交叉验证、模型初始化。这不是玄学是工程纪律。5. 把脉搏识别做成可复用的模块一个特征管线的封装技巧走到这一步你已经能跑通「去噪 → 特征 → 分类」的完整链路了。但如果你打算把这个东西用到实际项目里散落的脚本迟早会变成维护噩梦。我的习惯是把整条链路封成一个Pipeline类用 sklearn 的BaseEstimator和TransformerMixin做接口对齐这样它能直接塞进GridSearchCV里调参也能和标准化、分类器串成一条流水线。from sklearn.base import BaseEstimator, TransformerMixin import pywt import numpy as np from scipy.signal import find_peaks class PulseFeatureExtractor(BaseEstimator, TransformerMixin): 把原始脉搏信号转成特征矩阵的 transformer 可直接放进 sklearn Pipeline def __init__(self, fs500, waveletdb6, level4): self.fs fs self.wavelet wavelet self.level level def _denoise(self, sig): coeffs pywt.wavedec(sig, self.wavelet, levelself.level) sigma np.median(np.abs(coeffs[-1])) / 0.6745 thresh sigma * np.sqrt(2 * np.log(len(sig))) coeffs [coeffs[0]] [pywt.threshold(c, thresh, soft) for c in coeffs[1:]] return pywt.waverec(coeffs, self.wavelet)[:len(sig)] def _features(self, sig): sig self._denoise(sig) peaks, _ find_peaks(sig, distanceint(0.4 * self.fs), prominence0.3 * np.std(sig)) if len(peaks) 2: return None intervals np.diff(peaks) / self.fs return [ float(np.mean(sig[peaks])), float(60.0 / np.mean(intervals)), float(np.std(intervals)), float(np.std(sig) / (np.mean(np.abs(sig)) 1e-12)), # 波形因子 ] def fit(self, X, yNone): return self def transform(self, X): # X 是 list of 1D arrays feats [self._features(s) for s in X] # 丢弃无效样本用 0 填充实际项目里建议记录索引 return np.array([f if f is not None else [0]*4 for f in feats])这个类的好处是fit什么都不做transform负责全部计算符合 sklearn 的无状态 transformer 约定。__init__里的参数全部暴露出来可以直接在GridSearchCV的param_grid里写extractor__level: [3, 4, 5]来搜。注意transform里对无效样本用 0 填充是个简化处理真实项目里应该记录哪些样本被丢弃避免把无效样本喂进分类器。封装完之后整条链路就是Pipeline([(feat, PulseFeatureExtractor()), (scaler, StandardScaler()), (clf, SVC())])一行grid.fit(X_raw, y)就能把特征参数和分类器参数一起搜。我现在的习惯是任何超过三个步骤的信号处理流程都先想清楚能不能封成 transformer能封就封后面调参和换模型的时候会感谢自己。这套东西值不值得投入取决于你后面还要不要反复迭代——如果只是跑一次实验脚本就够了如果要做成产品或者持续优化封装这一步省不掉。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/9 20:59:08

网络驱动重装实战指南:从掉线到恢复的完整排查方法

前两天有位朋友抱着笔记本过来找我,说家里宽带明明是好的,手机连同一个路由器能正常上网,偏这台电脑突然就掉线了。右下角网络图标上顶着一个黄色感叹号,Wi-Fi列表能搜到,但点连接一直转圈,最后弹一句“无法…

2026/10/9 20:59:08

Minecraft指令系统完全指南:从入门到自动化建造实战

1. 从“手忙脚乱”到“言出法随”:指令系统的底层逻辑刚接触这个沙盒游戏的时候,我总觉得指令是那些“技术流”玩家的专属玩具。看着别人在聊天框里敲几个英文单词,就能凭空变出一座城堡、召唤一场雷暴,甚至改变整个世界的规则&am…

2026/10/9 20:59:08

Agent-Reach:多智能体协作的触达保障与智能路由实践

Agent-Reach 这个名字听起来有点技术冷感,但如果你正在维护一个由几十个 AI Agent 组成的协作网络,你就会明白它有多重要。我做智能体平台做了将近两年,最头疼的从来不是模型本身,而是 Agent 之间的那根“网线”——明明服务都在&…

2026/10/9 22:09:19

餐饮外卖销售系统数据库设计:订单表、状态机与分库分表实战

简介:这份资源是一套基于C#与SQL Server 2019开发的餐饮外卖销售系统数据库设计,面向高校数据库课程设计的学生及需要实战练手的初学者。系统划分商家、客户、骑手三类用户界面并配有注册模块,采用扁平化设计,界面达到商业软件水准…

2026/10/9 22:09:19

云原生实训平台如何支撑百人并发大数据教学?

简介:这是一套面向高校计算机与大数据相关专业师生的校园智能实训系统源码,基于达梦云原生大数据平台构建,聚焦数据思维培养与工程实践能力提升,适用于Java后端开发、Vue前端交互、大数据平台集成等中高级实训教学场景。资源共174…

2026/10/9 22:09:19

DSC曲线分析入门:从读图到定量,避开常见误判的实战指南

1. 从一张“看不懂”的曲线说起:DSC到底在测什么第一次拿到DSC曲线的人,十有八九会盯着那条忽上忽下的线发懵——横坐标是温度,纵坐标是热流,曲线一会儿往下凹一个坑,一会儿又往上鼓一个包,旁边还标着各种玻…

2026/10/9 22:09:19

Oracle 19c认证备考:原题资料解构与考场环境实战验证

简介:本资源是面向Oracle数据库管理员、DBA初学者及19c认证备考人员的高价值原题解析资料,聚焦核心考点与易错陷阱,助力夯实SQL语法、对象管理与连接机制等关键能力。压缩包为单个674KB的PDF文件,内容完整覆盖1Z0-082新版真题&…

2026/10/9 22:09:19

volatile与JMM深入解析:从内存可见性到并发实战

我从一个特别具体的场景开始聊:你写了一段代码,主线程把一个boolean标志位改成false,想让子线程跳出while循环,结果子线程像没看见一样继续死转,CPU 飙到 100%。这种问题在 Java 并发编程里几乎人人都撞过,…

2026/10/9 22:04:19

Python音乐爬虫实战:从架构设计到反爬应对的工程化指南

1. 音乐爬虫到底在爬什么:先搞清楚目标再动手很多人一听到“音乐爬虫”这四个字,脑子里第一反应就是“批量下载歌曲”。这个理解不能说错,但太窄了。我在实际折腾这类项目的过程中发现,音乐爬虫能做的事情远比下载歌曲丰富&#x…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/9 20:15:56

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 0:04:27

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略当数万字的学位论文初稿经历开题、实验、问卷与多轮文献梳理最终成形时,绝大多数研究生都会面临一道全新的形式审查关卡:AIGC 疑似度排查。在高校毕业审核流程中,盲审前的文本检测通…

2026/10/9 0:04:27

食堂节能改造源头工厂,商用厨房设备焕新方案广受好评

商用厨房作为餐饮经营、单位供餐的核心后勤阵地,其设备配置、动线规划与运维体系直接决定后厨作业效率、运营成本与合规性。从基础的灶具、制冷存储设备,到油烟净化、水处理等配套系统,每一个环节的合理性都与食品安全、能耗管控、消防安全挂…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑