
简介本资源面向信号处理初学者、自动化与故障诊断方向的工程师及高校相关专业学生聚焦时域特征提取这一基础但关键的信号分析环节解决原始时间序列中有效信息挖掘难、特征选择无依据、工程落地缺乏参考等问题。压缩包共2个文件11KB含MATLAB实现脚本timeDomainFeatures.m——封装了平均值、标准差、峰峰值、自相关函数、路径长度等10类经典时域特征的计算逻辑支持批量信号输入与结果导出另附详实的Word文档系统梳理各特征的物理意义、适用场景、抗噪特性及在ECG分析、振动诊断、语音识别等领域的典型应用案例。目前已有2063人学习下载内容精炼实用代码可直接调用文档兼顾理论解释与实践提示是快速掌握时域特征工程核心方法的轻量级入门套件。1. 项目概述从信号中“听”出故事在数据分析和智能感知的世界里我们常常面对的是各种传感器采集到的、随时间变化的信号。比如一段音频、一段振动波形、或者是一段心电图。这些信号我们称之为“时间序列数据”。它们就像一本用特殊语言写成的日记忠实地记录着设备、系统或生命体的状态变化。然而这本日记的“语言”是连续的、高维的、充满噪声的直接让计算机去“阅读”和理解效率极低甚至无从下手。这就好比让你直接去听一段未经处理的、混杂着各种环境音的原始录音并立刻判断出说话人的情绪——这几乎是不可能的任务。“时域特征提取”正是解决这个问题的关键钥匙。它不是一个具体的软件或工具而是一整套方法论和计算过程。其核心目标就是从原始的时间序列信号中提炼出一系列能够表征其核心特性的、低维的、可计算的数值指标。这些指标我们称之为“时域特征”。它们就像是信号的“指纹”或“体检报告”用一组简洁的数字概括了信号的强度、波动、规律性、突发性等关键信息。通过提取这些特征我们将原始的、难以直接处理的波形数据转化为了结构化的、可供机器学习模型或统计分析算法直接“食用”的特征向量。无论是工业设备的故障诊断从振动信号判断轴承是否磨损、语音情感识别从音频信号判断喜怒哀乐还是金融时序预测从股价波动预测趋势时域特征都是最基础、最直观、也往往是第一步要做的特征工程。简单来说时域特征提取就是把“波形”变成“数字”把“听故事”变成“看报告”的过程。它不涉及将信号转换到频率域如傅里叶变换或时频域如小波变换而是直接在时间维度上对信号的幅值、时间间隔等原始信息进行统计和计算。这使得时域特征具有计算简单、物理意义明确、对某些类型的模式如冲击、趋势非常敏感的优点。对于任何需要处理时间序列数据的工程师、数据分析师或算法开发者而言掌握时域特征提取就如同掌握了一套解读信号世界的基础语法。2. 核心思路与特征家族全览时域特征提取并非随意计算几个平均值那么简单。一个成熟的时域特征体系需要从多个维度去刻画信号的“性格”。根据我多年的项目经验通常会从以下几个核心维度来构建特征家族每个维度下又包含一系列具体的特征指标。理解这个分类体系比死记硬背公式更重要。2.1 幅值域特征信号的“体格”检查这类特征关注信号幅值大小的统计分布回答“信号总体上有多大、多强、波动多剧烈”的问题。这是最基础的一类特征。均值信号的平均水平。它反映了信号的直流分量或稳态值。在振动分析中均值过大可能表示存在不对中或松动在音频中均值与响度相关。均方根值也称为有效值。它衡量信号的平均能量。对于振动和噪声信号RMS值与信号的破坏力或能量直接相关是评估设备健康状态的关键指标。峰值/峰峰值信号的最大瞬时值以及最大值与最小值的差值。它们反映了信号中可能存在的极端冲击或突变。在轴承故障早期峰值指标可能比RMS更敏感。方差与标准差衡量信号围绕其均值的波动程度。标准差大说明信号变化剧烈不稳定。偏度描述信号幅值分布的不对称性。正态分布的偏度为0。正偏度表示分布右侧有长尾存在较多大幅值的正向冲击负偏度则相反。在金融收益率序列中偏度可以衡量风险的不对称性。峰度描述信号幅值分布的尖锐程度。正态分布的峰度为3或0取决于定义。峰度大于3表示分布比正态分布更尖锐、尾部更厚意味着信号中存在比高斯噪声更剧烈的冲击。这是故障诊断中一个极其重要的指标高峰度往往与滚动轴承的局部缺陷如点蚀、剥落产生的周期性冲击密切相关。实操心得计算幅值域特征前务必先对信号进行去趋势处理。特别是对于长时间采集的信号传感器温漂或系统缓慢变化会引入趋势项这会严重污染均值、方差等统计量。一个简单的做法是先减去信号的最小二乘拟合直线。2.2 时序相关特征信号的“记忆力”与“节奏感”这类特征关注信号在时间轴上的依赖关系和变化模式回答“当前时刻的值与过去时刻的值有多大关系信号变化的快慢和规律性如何”。自相关函数衡量信号与其自身在不同时间延迟下的相似性。ACF的衰减速度可以反映信号的“记忆力”衰减慢意味着前后时刻关联性强如趋势性信号衰减快则接近白噪声。ACF的峰值位置可能对应着信号的周期性。零交叉率单位时间内信号穿过零电平的次数。这是一个非常简单但有效的特征能够粗略反映信号的频率成分。对于语音信号清音如/s/的ZCR通常远高于浊音如元音。过电平率单位时间内信号超过某个预设阈值的次数。可以用来检测信号中的脉冲或事件发生的频率。2.3 波形形状特征信号的“轮廓”分析这类特征直接从信号的波形形状中提取信息常用于模式匹配和形状分类。波形因子峰值与均方根值的比值。它反映了波形的尖锐程度。正弦波的波形因子约为1.414方波为1。对于冲击信号该值会显著增大。峰值因子峰值与均方根值的比值。与波形因子类似但更强调极端峰值的影响。是评估冲击类故障的经典指标。脉冲因子峰值与绝对平均值的比值。裕度因子峰值与方根幅值信号平方的均值的平方根的比值。这些因子从不同角度描述了波形的“冲击性”或“稀疏性”在旋转机械故障诊断中有一套成熟的经验值范围用于判断健康状态。2.4 基于信息论的特征信号的“复杂度”与“不可预测性”这类特征将信号视为一个随机过程用信息论的工具来量化其复杂度和规律性。近似熵衡量时间序列中新模式产生的概率。熵值越大序列越复杂、越不可预测熵值越小序列越规律、越有确定性。常用于生理信号如心率变异性分析。样本熵近似熵的改进版计算更一致不依赖于数据长度。排列熵通过比较相邻数据点的相对大小顺序排列模式来量化序列的复杂性。计算速度快对噪声有一定的鲁棒性。2.5 基于模型的特征为信号“建模”这类特征先为时间序列建立一个参数化模型如自回归模型AR然后将模型的参数作为特征。它假设信号是由一个线性系统受白噪声激励产生的。线性预测系数源于语音信号处理用过去的若干个采样点来线性预测当前点这些系数反映了信号频谱包络的信息。自回归模型系数与LPC类似AR模型的系数可以看作是对信号功率谱的一种参数化表示。高阶AR系数可以构成一个高维特征向量常用于模式分类。方案选型背后的考量在实际项目中我很少会一次性提取所有特征。盲目堆砌特征会导致“维度灾难”增加计算负担并可能引入噪声。我的策略是先基于领域知识进行初筛再通过特征重要性评估进行精选。例如对于旋转机械振动信号幅值域尤其是峰度、峰值因子和波形因子是必选项对于语音信号短时能量、过零率、MFCC虽属频域但常与时域特征结合是核心对于心电信号基于RR间期本质是时域的特征和样本熵是关键。理解每一类特征背后的物理或数学意义才能做到有的放矢。3. 实战演练用Python实现轴承振动信号特征提取理论说得再多不如一行代码。下面我将以一个经典的公开数据集——美国凯斯西储大学轴承数据中心的数据为例手把手演示如何从一段真实的振动信号中提取一套完整的时域特征。我们假设场景是通过安装在电机驱动端的加速度传感器采集振动信号目标是提取特征以供后续的故障分类模型使用。3.1 环境准备与数据加载首先确保你的Python环境安装了必要的科学计算库numpy,pandas,scipy,scikit-learn。我们将使用scipy进行信号读取假设数据是.mat格式和部分高级计算。import numpy as np import pandas as pd from scipy import io, signal, stats import warnings warnings.filterwarnings(ignore) # 假设我们有一个从CWRU数据集加载的信号 # 这里我们用一段模拟的正弦波加冲击噪声来演示实际应用中替换为 io.loadmat 读取真实数据 fs 12000 # 采样频率 12 kHz t np.arange(0, 1, 1/fs) # 1秒时长 # 模拟一个基频为100Hz的振动并加入一个局部的冲击模拟故障 freq 100 vibration 0.5 * np.sin(2 * np.pi * freq * t) # 在0.3秒处加入一个冲击 impulse np.zeros_like(t) impulse[int(0.3 * fs)] 2.0 # 合成信号并加入一些高斯噪声 signal_raw vibration impulse 0.05 * np.random.randn(len(t)) # 为了演示我们截取一段进行分析例如冲击发生前后各0.1秒 analysis_center int(0.3 * fs) window_size int(0.2 * fs) # 0.2秒窗口 start_idx max(0, analysis_center - window_size//2) end_idx min(len(signal_raw), analysis_center window_size//2) x signal_raw[start_idx:end_idx] N len(x) print(f分析信号段长度: {N} 个点 时长: {N/fs:.3f} 秒)3.2 核心特征计算函数实现我们将把之前讨论的各类特征封装成函数。这里注意工业上有时会对信号先进行带通滤波以聚焦感兴趣的频带本例为简化直接对原始信号操作。def extract_time_domain_features(signal, fs1): 从一维时间序列信号中提取一整套时域特征。 参数: signal: 一维numpy数组输入信号。 fs: 采样频率用于计算需要时间单位的特征如零交叉率。 返回: features_dict: 包含所有特征名称和值的字典。 x np.array(signal).flatten() n len(x) features {} # 1. 幅值域特征 features[mean] np.mean(x) features[rms] np.sqrt(np.mean(x**2)) features[peak] np.max(np.abs(x)) features[peak_to_peak] np.ptp(x) # 峰峰值 features[variance] np.var(x) features[std] np.std(x) features[skewness] stats.skew(x) features[kurtosis] stats.kurtosis(x, fisherFalse) # 返回Pearson定义正态分布为3 # 2. 波形因子与脉冲因子 x_abs np.abs(x) x_squared x**2 # 绝对平均值 features[abs_mean] np.mean(x_abs) # 方根幅值 (Square Root Amplitude) features[square_root_amplitude] (np.mean(np.sqrt(x_abs))) ** 2 # 波形因子 features[form_factor] features[rms] / features[abs_mean] if features[abs_mean] ! 0 else 0 # 峰值因子 (Crest Factor) features[crest_factor] features[peak] / features[rms] if features[rms] ! 0 else 0 # 脉冲因子 (Impulse Factor) features[impulse_factor] features[peak] / features[abs_mean] if features[abs_mean] ! 0 else 0 # 裕度因子 (Clearance Factor) features[clearance_factor] features[peak] / features[square_root_amplitude] if features[square_root_amplitude] ! 0 else 0 # 3. 时序相关特征 - 零交叉率 (简易版未考虑死区) # 计算过零点的位置 zero_crossings np.where(np.diff(np.signbit(x)))[0] features[zero_crossing_rate] len(zero_crossings) / (n / fs) if n 1 else 0 # 每秒过零次数 # 4. 基于信息论的特征 - 这里以近似熵为例 (需要较长数据短窗口可能不准) # 为演示我们实现一个简化的样本熵复杂度较高生产环境建议用库 # 此处省略具体实现通常使用 entropy 库或 nolds 库。 # features[sample_entropy] calculate_sample_entropy(x, ...) # 5. 简单时序统计 - 均方根斜率等 (变化率) dx np.diff(x) features[rms_slope] np.sqrt(np.mean(dx**2)) if len(dx) 0 else 0 return features # 对我们的信号段应用特征提取 feature_dict extract_time_domain_features(x, fsfs) print(提取的时域特征示例:) for key, value in list(feature_dict.items())[:10]: # 打印前10个 print(f{key:25s}: {value:.6f})3.3 特征批处理与结构化在实际项目中我们面对的是成千上万个数据文件每个文件包含多段信号。我们需要批量处理并将结果组织成特征矩阵样本×特征。def batch_feature_extraction(file_paths, segment_length1024, fs12000): 批量处理多个数据文件或长信号。 参数: file_paths: 数据文件路径列表。 segment_length: 每段信号的长度用于从长信号中截取分析段。 fs: 采样频率。 返回: feature_df: pandas DataFrame每一行是一个样本的特征向量。 labels: 对应的标签如果有。 all_features [] all_labels [] # 假设我们有标签 for file_path in file_paths: # 加载数据这里假设每个文件是一个字典包含data和label # data io.loadmat(file_path)[vibration_data].flatten() # label io.loadmat(file_path)[fault_type][0,0] # 为演示我们模拟从长信号中滑动截取 # 假设 file_path 指向一个长信号数组 # long_signal np.load(file_path) # 这里用我们之前的合成信号重复模拟一个长信号 long_signal np.tile(signal_raw, 3) # 重复3次模拟长信号 num_segments len(long_signal) // segment_length for i in range(num_segments): segment long_signal[i*segment_length : (i1)*segment_length] features extract_time_domain_features(segment, fsfs) all_features.append(features) # all_labels.append(label) # 实际使用中根据情况分配标签 # 转换为DataFrame feature_df pd.DataFrame(all_features) # 可以在这里进行简单的特征清洗如去除全为常数的列 feature_df feature_df.loc[:, (feature_df ! feature_df.iloc[0]).any()] return feature_df #, np.array(all_labels) # 模拟批量处理 print(\n模拟批量特征提取...) # 假设我们有3个“文件”每个文件我们截取2段 file_paths_simulated [sim_file_1, sim_file_2, sim_file_3] feature_dataframe batch_feature_extraction(file_paths_simulated, segment_length2400, fsfs) # 0.2秒一段 print(f特征矩阵形状: {feature_dataframe.shape}) print(f特征列名: {feature_dataframe.columns.tolist()})注意事项在滑动窗口分割信号时必须考虑信号的平稳性。对于非平稳信号如启动过程直接分割会破坏其物理意义。通常需要在稳态运行区间截取数据或者使用更复杂的时频分析方法。此外窗口长度的选择需要权衡太短则统计量不稳定太长则可能混入不同状态的信息。一个经验法则是窗口长度至少包含主要周期成分的10个周期以上。4. 特征工程深化标准化、筛选与可视化提取出几十个时域特征只是第一步。原始特征往往量纲不一均值是幅值零交叉率是频率数值范围差异巨大峰度可能几十均值可能零点几。直接将其喂给机器学习模型会导致模型被数值大的特征“主导”。因此后续的特征工程至关重要。4.1 特征标准化与归一化这是必不可少的一步旨在消除量纲影响使所有特征处于同一尺度。from sklearn.preprocessing import StandardScaler, RobustScaler # 假设 feature_dataframe 是我们上一步得到的特征DataFrame X_raw feature_dataframe.values # 方法1: Z-score标准化 (适用于特征大致符合正态分布) scaler_z StandardScaler() X_scaled_z scaler_z.fit_transform(X_raw) print(Z-score标准化后均值和标准差:) print(f均值: {np.mean(X_scaled_z, axis0).round(2)}) print(f标准差: {np.std(X_scaled_z, axis0).round(2)}) # 方法2: RobustScaler (使用中位数和四分位数对异常值不敏感) scaler_r RobustScaler() X_scaled_r scaler_r.fit_transform(X_raw) # 选择建议 # - 如果特征中存在明显的异常值如某些故障样本的峰值因子极大使用RobustScaler。 # - 如果数据比较“干净”分布接近正态使用StandardScaler即可。 # - 对于有明确边界的特征如百分比也可以考虑MinMaxScaler归一化到[0,1]区间。4.2 特征筛选去除冗余与噪声不是所有特征都是有用的。有些特征之间高度相关如RMS和标准差有些特征对目标变量如故障类型没有区分能力。我们需要筛选出最具信息量的特征子集。from sklearn.feature_selection import VarianceThreshold, SelectKBest, f_classif, mutual_info_classif import seaborn as sns import matplotlib.pyplot as plt # 1. 方差过滤去除方差接近0的常数特征可能由数据分割不当产生 selector_var VarianceThreshold(threshold0.01) # 阈值根据实际情况调整 X_high_var selector_var.fit_transform(X_scaled_z) print(f方差过滤后特征数: {X_high_var.shape[1]} (原{ X_scaled_z.shape[1]})) # 获取保留的特征索引 selected_var_indices selector_var.get_support(indicesTrue) selected_var_names feature_dataframe.columns[selected_var_indices] print(f保留的特征: {selected_var_names.tolist()}) # 2. 相关性分析 (需要标签这里用模拟标签) # 假设我们为模拟数据生成一些随机标签健康/故障 np.random.seed(42) y_simulated np.random.choice([0, 1], sizelen(feature_dataframe), p[0.7, 0.3]) # 模拟70%健康30%故障 # 计算特征与标签的相关性这里以ANOVA F值为例适用于分类问题 selector_f SelectKBest(score_funcf_classif, kall) # 先计算所有特征的得分 selector_f.fit(X_high_var, y_simulated) feature_scores selector_f.scores_ # 可视化特征重要性 plt.figure(figsize(10, 6)) sorted_idx np.argsort(feature_scores)[::-1] plt.bar(range(len(selected_var_names)), feature_scores[sorted_idx]) plt.xticks(range(len(selected_var_names)), np.array(selected_var_names)[sorted_idx], rotation45, haright) plt.xlabel(Features) plt.ylabel(ANOVA F-score) plt.title(Feature Importance based on ANOVA F-test (Simulated)) plt.tight_layout() plt.show() # 3. 特征间相关性热图 (检查多重共线性) corr_matrix pd.DataFrame(X_high_var, columnsselected_var_names).corr() plt.figure(figsize(12, 10)) sns.heatmap(corr_matrix, annotTrue, fmt.2f, cmapcoolwarm, center0, squareTrue) plt.title(Feature Correlation Matrix) plt.tight_layout() plt.show() # 如果发现某两个特征相关性极高如0.95可以考虑只保留其中一个。4.3 特征可视化直观理解数据在建模前可视化能帮助我们直观感受特征是否具有区分度。# 将标准化后的数据与标签结合进行降维可视化如PCA from sklearn.decomposition import PCA pca PCA(n_components2) X_pca pca.fit_transform(X_scaled_z) # 使用标准化后的数据 plt.figure(figsize(8, 6)) scatter plt.scatter(X_pca[:, 0], X_pca[:, 1], cy_simulated, cmapviridis, alpha0.7, edgecolorsk) plt.xlabel(fPC1 ({pca.explained_variance_ratio_[0]:.2%} variance)) plt.ylabel(fPC2 ({pca.explained_variance_ratio_[1]:.2%} variance)) plt.colorbar(scatter, labelLabel (0: Healthy Sim, 1: Fault Sim)) plt.title(PCA Visualization of Time-Domain Features) plt.grid(True, linestyle--, alpha0.5) plt.show() # 观察前两个主成分是否能够将不同类别的样本分开。如果能说明特征有效。通过以上步骤我们完成了从原始信号到标准化、筛选后的特征矩阵的完整流程。这个特征矩阵现在可以输入到SVM、随机森林、神经网络等分类器中进行故障诊断或状态识别了。5. 避坑指南与高级技巧时域特征提取看似简单但实操中陷阱不少。下面分享一些我踩过坑后总结的经验。5.1 常见问题与排查特征值全是NaN或Inf原因计算过程中出现了除零错误如RMS为0时计算峰值因子或输入信号全为0。解决在特征计算函数中加入保护性判断。例如在计算比值类特征如crest_factor前检查分母是否大于一个极小值如1e-10否则返回0或一个默认值。确保输入信号有效。特征区分度差模型准确率低原因提取的特征与目标不相关。例如用均值去区分不同频率的故障效果必然不好。排查可视化像上面一样用PCA或t-SNE可视化特征空间看不同类别样本是否混杂。单特征分析绘制每个特征在不同类别下的分布直方图或箱线图观察重叠程度。领域知识回归物理本质。轴承内圈故障会产生高频冲击峰度和峰值因子可能更敏感不平衡故障会导致工频幅值增大RMS和1倍频幅值需频域分析更关键。时域特征常需与频域特征结合使用。特征不稳定同一状态每次提取值波动大原因信号非平稳分析窗口太短统计量方差大未对齐信号的相位或周期。解决确保稳态分析在设备稳定运行时截取数据。增加窗口长度或对多个连续窗口的特征取平均。周期分割对于周期性明显的信号如旋转机械尝试按转速周期进行同步平均能极大抑制随机噪声突出周期性故障成分此时再提取时域特征如同步平均后的峰值会更稳定。计算速度慢无法满足实时性要求原因提取了过多复杂特征如计算长序列的样本熵或批量处理时循环效率低。优化特征初筛在线系统只保留最核心的3-5个关键特征如RMS、峰值、峰度。向量化计算使用numpy的向量化操作避免Python级循环。上述示例中的函数已基本实现向量化。滑动窗口增量更新对于实时流数据可以增量更新统计量而不是每个窗口都从头计算。例如均值、方差可以通过递推公式更新。5.2 高级技巧与融合策略多尺度分析对于包含多种成分的复杂信号可以在不同尺度分辨率上提取特征。例如先对原始信号进行小波分解得到近似系数和细节系数然后分别对每一层系数提取时域特征。这能同时捕捉信号的整体趋势和局部细节。差分与预处理有时原始信号的趋势会掩盖其真实变化。对信号进行一阶或二阶差分可以突出其变化率此时再对差分序列提取特征如差分序列的RMS可能对某些缓慢发展的故障更敏感。时域特征与模型结合不要将特征提取和建模完全割裂。例如在提取AR模型系数作为特征时模型的阶数选择本身就是一个超参数可以通过最终分类器的交叉验证性能来确定。基于深度学习的端到端特征学习对于极其复杂或先验知识不足的信号可以尝试使用一维卷积神经网络直接从原始信号中学习特征。CNN的卷积核本质上就是在学习一种局部时域模式。但在工业界可解释性至关重要。传统时域特征因其明确的物理意义在报告和决策中仍不可替代。一个混合策略是用CNN做高精度分类同时用传统时域特征做结果解释和健康指标跟踪。时域特征提取是时间序列分析的基石它简单、快速、物理意义清晰。掌握它意味着你掌握了打开信号世界大门的第一把钥匙。真正的功夫在于根据具体问题从这丰富的特征工具箱中挑选并组合出那把最合适的“钥匙”。这个过程没有银弹需要不断的实验、分析和领域知识的融合。从我个人的经验来看建立一个特征性能追踪表非常有用记录下每个候选特征在不同故障类型、不同工况下的表现如区分度、稳定性久而久之你就会形成对自己所在领域的“特征直觉”。本文还有配套的精品资源点击获取