news 2026/6/8 13:27:10

基于K-Means与TensorFlow Lite的振动异常检测边缘智能实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于K-Means与TensorFlow Lite的振动异常检测边缘智能实践

1. 项目概述:从振动数据到边缘智能的实践之路

在工业设备维护领域,预测性维护正逐渐取代传统的定期维护和事后维修,成为保障生产连续性与设备安全的关键策略。其核心在于,能否在设备发生实质性故障之前,就捕捉到那些预示着“不健康”的早期征兆。振动分析,作为旋转机械状态监测的“听诊器”,长期以来都是实现这一目标的重要手段。然而,传统的阈值报警或频谱分析往往依赖于专家经验,难以应对复杂工况和早期微弱故障。这正是机器学习,特别是异常检测技术,能够大显身手的地方。本文将分享一个完整的实践项目:如何将一台普通的桌面风扇作为“小白鼠”,利用其振动数据,训练一个基于K-Means聚类的异常检测模型,并最终将其部署到NXP i.MX RT1050这样的嵌入式微控制器上,实现一个低成本、低功耗的边缘智能监测节点。整个过程,我们将深入数据采集、特征工程、模型训练、轻量化转换与嵌入式部署的每一个环节,并剖析其中踩过的坑和总结出的实用技巧。

2. 核心思路与技术选型解析

2.1 为什么选择K-Means进行异常检测?

在开始动手之前,明确“为什么”至关重要。异常检测算法众多,如孤立森林、One-Class SVM、自编码器等,为何偏偏选择K-Means聚类?

首先,从问题本质看,我们的目标是区分“正常”振动和“异常”振动。在缺乏大量已标记的“异常”样本(事实上,设备大部分时间应处于正常状态)的情况下,无监督或半监督学习是更现实的选择。K-Means作为一种经典的无监督聚类算法,其核心思想是找到数据空间中的几个“中心点”(质心),并将所有数据点划分到最近的质心。在异常检测的语境下,我们可以假设:正常数据点会紧密地聚集在少数几个质心周围,而异常点则远离这些质心簇

其次,考虑到嵌入式部署的严苛约束。i.MX RT1050虽然性能强劲,但毕竟不是服务器,内存和算力有限。K-Means模型在推理阶段的计算非常简单:对于一个新的数据点,只需计算其到各个预定义质心的距离,并取最小值。这个距离(或与阈值比较)即可作为异常分数。这种计算只涉及基本的向量距离运算(如欧氏距离),没有复杂的矩阵乘法或非线性激活函数,非常适合在MCU上高效执行。

最后,是模型的可解释性。训练完成后,我们得到的是几个质心的坐标。在三维特征空间(本例中为X, Y, Z轴的RMS值)里,这些质心直观地代表了设备几种典型“健康”状态的核心。任何新数据点偏离这些核心区域,都可以被直观地理解为“状态发生了变化”。这种物理意义的可解释性,对于工业应用中的故障诊断和信任建立非常有价值。

注意:K-Means的局限性:K-Means假设数据是凸形分布且各类方差相近,对噪声和异常值本身敏感(可能影响质心位置)。因此,前期高质量的数据预处理和滤波至关重要,这也是本项目花费大量精力在数据清洗上的原因。

2.2 边缘计算范式:TensorFlow Lite与eIQ工具链

模型在PC上训练好后,如何让它在一块没有操作系统的嵌入式板卡上跑起来?这里就引入了TensorFlow Lite(TFLite)和NXP的eIQ(边缘智能加速)工具链。

TensorFlow Lite是TensorFlow针对移动和嵌入式设备的轻量级解决方案。它包含两部分:TFLite转换器(用于将标准TensorFlow模型转换为.tflite格式)和TFLite解释器(用于在目标设备上加载并运行模型)。.tflite格式模型经过优化,体积更小,并支持量化以进一步减少模型尺寸和加速推理。

而NXP的eIQ(Edge Intelligence)是一个软件环境,它集成了TensorFlow Lite for Microcontrollers(TFLM)等推理引擎,并针对NXP的MCU和MPU进行了优化,提供了从模型部署到应用开发的完整支持。在本项目中,eIQ SDE(软件开发环境)提供了必要的库文件、API接口和示例工程,使得在i.MX RT1050上集成TFLite模型变得相对标准化。

整个技术栈的流程可以概括为:在PC端用TensorFlow(Python)训练K-Means模型 -> 保存为SavedModel格式 -> 用TFLite转换器转为.tflite格式 -> 使用xxd工具将.tflite文件转换为C语言头文件(converted_model.h) -> 将该头文件作为常量数组嵌入到基于eIQ的嵌入式C++应用程序中 -> 在MCU上调用TFLite解释器进行推理。

3. 硬件搭建与数据采集实战

3.1 硬件平台选择与传感器配置

本项目核心硬件是NXP的i.MX RT1050 EVKB评估板。选择它主要基于几点考量:其Cortex-M7内核主频高达600MHz,具备充足的算力运行轻量级ML模型;板载了FXOS8700CQ数字加速度计,集成了3轴加速度和磁力计,满足了振动数据采集的基本需求;丰富的生态与eIQ的官方支持,大大降低了开发门槛。

FXOS8700CQ通过I2C接口与主控通信。在数据采集阶段,我们需要对其进行配置以优化振动信号捕捉:

  • 模式:设置为仅加速度计模式(Accelerometer only),因为我们只关心振动。
  • 输出数据速率(ODR):设置为400Hz。这是传感器每秒输出数据的频率。根据奈奎斯特采样定理,要无失真地采集频率为f的信号,采样率必须大于2f。我们预估风扇振动的主要频率在100-300Hz范围内,因此400Hz的采样率是合理的起点。
  • I2C速率:设置为1 Mbps,确保数据能及时被MCU读取。
  • MCU读取频率:设定为每1.5毫秒读取一次传感器数据。这实际上决定了我们应用程序的采样周期,略高于传感器ODR的倒数(1/400Hz = 2.5ms),以确保每次读取都能获得新数据,避免重复。

将开发板牢固地安装在桌面风扇的电机外壳或扇叶防护罩上,确保振动能有效传递。连接串口线,用于输出数据和调试。

3.2 数据采集脚本的编写与技巧

数据采集由运行在MCU上的固件和PC上的Python脚本共同完成。MCU固件以1.5ms的周期读取加速度计X, Y, Z三轴的原始数据(通常是16位有符号整数),并通过UART串口实时发送出去。

PC端的Data_Collection.py脚本负责接收、解析并存储这些数据。这个脚本有几个关键设计点:

  1. 串口通信与数据解析:使用pyserial库打开指定COM口,配置正确的波特率(如115200)。MCU发送的数据格式通常是纯文本,例如“X:123 Y:45 Z:-987\n”。脚本需要逐行读取,并用字符串分割等方法提取出三个轴的数值。
  2. 数据存储策略:使用xlwt库将数据写入Excel文件(.xls)。一个重要的技巧是定时保存。脚本设定为每分钟自动保存一次工作簿。这样即使脚本意外崩溃或需要提前终止,已经采集的数据也不会丢失。代码中会维护一个缓冲区,每分钟将缓冲区的数据写入磁盘并清空缓冲区。
  3. 异常数据注入:为了进行半监督学习,我们需要在“健康”数据中人为制造“异常”。在脚本运行期间,手动、随机地轻敲或晃动开发板,模拟设备受到的冲击或安装松动。务必在记录数据的同时,用笔记或注释大致标记出发生“异常”的时间段,这将在后续数据分析时用于验证模型的有效性。
  4. 采集时长控制:在脚本中预设采集总时长(例如1小时)。采集足够长时间的健康数据,并穿插多次、短暂的异常干扰,以确保数据集的代表性。

4. 数据预处理与特征工程深度剖析

原始加速度计数据是包含噪声和无关高频成分的时间序列,直接喂给模型效果会很差。因此,数据预处理和特征提取是提升模型性能的关键。

4.1 时域与频域分析:理解你的数据

在动手滤波和提取特征前,先要“看懂”数据。将采集到的X, Y, Z三轴数据分别绘制成时域波形图。观察健康状态下波形的振幅范围、基线漂移情况。然后,人为制造异常(如敲击),在波形图上找到对应的位置,观察异常在时域上的表现:是出现了一个尖锐的脉冲?还是整体振幅的抬升?

接着,进行频域分析。编写Python脚本,对一段健康数据和一段异常数据分别做快速傅里叶变换(FFT),绘制频谱图。对比两者,可以回答关键问题:故障特征主要出现在哪个频段?在本项目的风扇案例中,通过FFT发现主要振动能量集中在100-300Hz。同时,可能还会看到50Hz工频干扰或其谐波。这些分析结果直接指导下一步的滤波参数设计。

4.2 滤波:去除噪声,保留精华

根据频域分析,我们决定采用移动平均滤波器,这是一种简单的低通滤波器。它的原理是取连续N个采样点的平均值作为当前输出点,能有效平滑数据、抑制高频噪声。

具体操作:对于一个序列[x1, x2, x3, x4, x5, x6, ...],取窗口大小N=5。

  • 第一个滤波后输出A1 = (x1 + x2 + x3 + x4 + x5) / 5
  • 第二个输出A2 = (x2 + x3 + x4 + x5 + x6) / 5
  • 以此类推...

在Python中,可以使用pandas.rolling(window=5).mean()函数方便地实现,但需要注意处理前4个(N-1)数据点。滤波后再次绘图,会发现波形变得平滑,毛刺减少,但异常事件的突变特征依然得以保留。

4.3 特征提取:从波形到特征向量

经过滤波,我们得到了更干净的时间序列,但数据量依然庞大(每秒数百个点)。直接输入模型维度太高,且相邻点间高度相关。我们需要提取有代表性的特征。这里选择计算均方根值

RMS是描述信号有效能量大小的经典时域特征。对于振动信号,RMS值对持续性的振幅变化敏感,非常适合检测不平衡、不对中等故障。计算方法是:取一段连续的数据点(例如M个点),计算其平方和的平均值的平方根。

RMS = sqrt( (x1^2 + x2^2 + ... + xM^2) / M )

关键参数M的选择:这是一个需要实验的“超参数”。M太小,则特征噪声大,不稳定;M太大,则时间分辨率下降,可能无法捕捉快速发生的瞬时异常。在本项目中,经过多次试验,选择M=10。这意味着,我们每10个滤波后的数据点,计算出一个RMS值,作为一个特征。这样,数据量被压缩了10倍,同时每个RMS值代表了约15毫秒(10 * 1.5ms)时间窗口内的振动能量。

最终,对于每一帧输入,我们分别计算X, Y, Z轴在2005个原始点上的RMS特征(经过滤波和RMS计算后,维度变为200),形成一个200维的特征向量。这个200,就是模型输入层的大小。

5. 模型训练、转换与验证全流程

5.1 在TensorFlow中构建与训练K-Means模型

虽然Scikit-learn有现成的K-Means实现,但为了最终能顺利转换为TFLite格式,我们选择使用TensorFlow的原生操作来构建模型。核心步骤包括:

  1. 数据准备:将预处理和特征提取后的所有数据(健康+部分异常)加载进来,整理成[num_samples, 200]的数组。这里num_samples是总样本数,200是每个样本的特征数(X/Y/Z轴RMS值拼接而成,具体维度根据实际情况调整,原文示例是综合处理)。
  2. 模型定义:使用tf.Variable定义可训练的质心(Centroids),例如设定3个质心(K=3)。初始化质心位置(可以使用随机初始化或从数据中随机选取样本)。
  3. 训练循环
    • 分配步骤:计算每个数据点到所有质心的距离(如欧氏距离),将其分配到最近的质心。
    • 更新步骤:计算属于每个质心的所有数据点的均值,用这个均值更新该质心的位置。
    • 重复以上两步,直到质心变化小于某个阈值或达到最大迭代次数。
  4. 保存模型:训练完成后,得到稳定的质心坐标。我们需要将这个“模型”保存下来。这里使用TensorFlow的SavedModel格式。需要注意的是,我们保存的并不是一个传统的“预测”计算图,而是一个将输入数据与这些固定质心进行比较的计算逻辑。这个计算图以训练好的质心作为常量,输入新的200维特征,输出该特征到每个质心的距离。

训练脚本kmeans_development_training.py会输出9个数值(假设3个质心 * 3个轴)。这9个值就是训练得到的质心坐标,是模型的核心。

5.2 模型转换:从TensorFlow到嵌入式头文件

这是将AI模型“植入”MCU的关键一步,也是最容易出错的一步。

  1. 生成SavedModel(.pb):运行Export_trained_data_model.py脚本。这个脚本接收上一步得到的9个质心值,构建一个固定的TensorFlow计算图(包含距离计算),并保存为SavedModel格式(包含.pb文件和变量目录)。这个模型的作用就是执行“距离计算”。
  2. 转换为TensorFlow Lite(.tflite):运行conversion.py脚本,使用TFLite转换器(tf.lite.TFLiteConverter.from_saved_model)将.pb模型转换为.tflite格式。这里可能会遇到算子兼容性问题。例如,原文档指出,tf.square算子在eIQ支持的TFLite版本中不是内置算子。解决方案是,在构建SavedModel时,避免直接使用tf.square,而是用乘法tf.multiply(x, x)来代替。
  3. 验证TFLite模型:在部署到MCU前,务必在PC上验证转换后的.tflite模型是否正确。使用check_tflite.py脚本,用TFLite解释器加载模型,输入一些测试数据,查看输出距离是否与在标准TensorFlow中的计算结果一致。这一步能提前发现转换问题。
  4. 生成C头文件(.h):使用xxd工具(一个二进制文件查看器)将.tflite文件转换为C语言数组。命令为:xxd -i converted_model.tflite > converted_model.h。生成的.h文件里包含一个unsigned char数组,其内容就是整个.tflite模型的二进制字节流。一个关键修改:需要将数组声明前的unsigned char改为const char,并将其放在MCU的只读存储区(如Flash),以节省RAM。

5.3 嵌入式端模型推理程序开发

在i.MX RT1050的工程中(基于MCUXpresso SDK和eIQ组件),集成模型推理的流程如下:

  1. 包含模型数据:将converted_model.h文件添加到工程中,并在主程序里通过extern声明引用这个模型数组。
  2. 初始化TFLite解释器
    // 从数组加载模型 tflite::MicroErrorReporter micro_error_reporter; const tflite::Model* model = tflite::GetModel(g_converted_model_data); // 创建解释器 static tflite::MicroInterpreter static_interpreter( model, resolver, tensor_arena, kTensorArenaSize, &micro_error_reporter); tflite::MicroInterpreter* interpreter = &static_interpreter; // 分配内存 interpreter->AllocateTensors();
  3. 准备输入数据:从加速度计读取2005个原始数据点,在MCU上实时进行移动平均滤波RMS特征计算。这个过程必须与PC端训练时的预处理流程完全一致,包括窗口大小(5点平均、10点RMS)。计算得到200维的特征向量。
  4. 执行推理:将200维特征向量复制到解释器的输入张量中,然后调用interpreter->Invoke()
  5. 解析输出与判断:解释器的输出张量包含了输入特征到各个质心的距离。我们取其中的最小值d_min设定一个阈值。如果d_min小于阈值,则认为当前状态接近某个健康质心,判定为“健康”;反之,则判定为“异常”。这个阈值需要在验证阶段通过测试数据来确定。

6. 关键问题排查与实战经验总结

6.1 模型转换与算子兼容性陷阱

这是边缘AI部署中最常见的坑。TensorFlow操作符成千上万,但TFLite,尤其是TFLite for Microcontrollers,仅支持一个有限的子集。

  • 问题:在转换.pb.tflite时,转换器报错,提示某些算子不支持。
  • 排查:首先检查使用的TensorFlow和TFLite版本是否与eIQ SDE文档要求一致。使用tf.lite.OpsSet指定转换目标。查看转换器输出的警告信息,明确哪个算子不被支持。
  • 解决
    1. 寻找替代算子:如原文档所述,用乘法替代平方算子。
    2. 自定义算子:对于复杂的、不支持的操作,可以在嵌入式端用C/C++实现自定义层。但这需要深入理解TFLite Micro的内部机制,难度较高。
    3. 简化模型:重新审视模型结构,是否能用一组支持的操作来等价实现?例如,某些归一化操作可以移到预处理阶段。
  • 经验在TensorFlow中构建模型时,就要时刻想着TFLite的兼容性。尽量使用最基础、最常见的算子。在转换前,用tf.lite.TFLiteConvertertarget_spec.supported_ops属性来限制可用的算子集进行试验。

6.2 数据不一致性:训练与推理的“隐形杀手”

模型在PC上测试完美,部署到板子上却乱报异常。最常见的原因是数据流水线不一致

  • 问题场景:PC端训练时,滤波和RMS计算是用Python的pandasnumpy在浮点数上完成的。嵌入式端是用C语言在整数(或定点数)上实现的。细微的边界处理(如四舍五入)、数组索引的起始/结束位置,甚至移动平均的填充方式,都可能引入微小差异。
  • 排查方法:实施“端到端”验证。在嵌入式程序中,将经过预处理后的200维特征向量通过串口打印出来。同时,在PC上,用Python脚本对同一段原始数据(也通过串口保存下来)进行预处理。对比两个200维的向量,逐元素检查差异。允许有极小的浮点误差,但如果出现系统性偏差,就要检查算法实现。
  • 解决:确保嵌入式端的预处理代码与Python脚本在数学上严格等价。可以考虑将PC端的预处理函数用C语言重写一遍,作为“黄金参考”,或者使用定点数算术库来保证精度可控。

6.3 阈值设定的艺术与挑战

K-Means本身是一个聚类算法,不直接输出“正常/异常”的二元判断。这个判断依赖于我们设定的距离阈值。

  • 问题:阈值设得太低,轻微的环境振动(如有人走过)都可能被误报为异常(虚警率高)。阈值设得太高,真实的早期故障可能被漏掉(漏报率高)。
  • 方法:在PC端完成模型训练后,使用一个独立的验证数据集(包含已知的健康和异常片段)来进行阈值调优。绘制ROC曲线或计算F1分数,寻找一个在误报和漏报之间可接受的平衡点。这个阈值应作为一个可配置的参数固化在嵌入式代码中。
  • 进阶思考:静态阈值可能不适应所有工况。可以考虑动态阈值,例如基于最近一段时间内距离值的统计(如均值+3倍标准差)来调整。

6.4 实时性与资源瓶颈

在MCU上,实时处理数据流并运行模型,需要关注性能。

  • 时序分析:使用定时器或GPIO翻转来测量关键段的执行时间:1)读取2005个原始点所需的总时间(应约等于2005*1.5ms≈3秒);2)执行一次滤波和RMS特征计算的时间;3)执行一次TFLite推理的时间。确保整个处理周期满足应用要求。
  • 内存管理tensor_arena是TFLite Micro用于分配中间张量的内存区域。如果kTensorArenaSize设置过小,AllocateTensors()会失败。需要通过试验或查看模型信息来确定所需的最小arena大小。同时,用于存储原始数据和中间结果的缓冲区也要合理规划,避免栈溢出。
  • 优化技巧:如果推理时间成为瓶颈,可以探索TFLite的量化功能,将模型从FP32转换为INT8,这能显著提升速度并减少模型体积,但可能会轻微损失精度。

7. 项目扩展与优化方向思考

完成基础版本后,这个项目还有很大的深化空间:

  1. 多特征融合:除了时域的RMS,还可以在特征提取阶段加入其他特征,如峰值因子、峭度、频域中的特定频段能量等,构成一个多维特征向量,可能提升检测的灵敏度。
  2. 自适应学习:当前的质心是离线训练、固定不变的。可以探索在线学习或增量学习算法,让模型能够缓慢地适应设备因老化而产生的正常性能漂移,减少误报。
  3. 更复杂的模型:如果资源允许,可以尝试更先进的轻量级模型,如微型自编码器,它能够学习更复杂的正常数据分布,可能对未知类型的异常有更好的检测能力。
  4. 系统集成:将异常检测模块与无线通信模块(如Wi-Fi, LoRa)结合,实现远程报警。或者与控制系统联动,在检测到严重异常时自动执行停机操作。

这个项目从数据采集到边缘部署的完整闭环,清晰地展示了如何将一个机器学习想法落地为一个实实在在的嵌入式产品原型。其中最大的体会是,边缘AI的成功,三分之一在于算法,三分之一在于工程实现(数据流水线、模型转换),另外三分之一在于对硬件和实际应用场景的深刻理解。每一个环节的疏忽,都可能导致最终效果的失败。希望这份详细的实践记录,能为你在嵌入式智能化的探索之路上提供一块坚实的垫脚石。

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

抖音内容保存完整指南:douyin-downloader工具深度解析

抖音内容保存完整指南:douyin-downloader工具深度解析 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppo…

作者头像 李华
网站建设 2026/6/8 13:16:20

从MR24到MR32:嵌入式MCU无缝升级的硬件兼容性与软件迁移实战

1. 项目概述:从MR24到MR32的无缝升级之路在嵌入式产品开发中,最让人头疼的场景之一莫过于“芯片停产”。你手上一个运行稳定的老产品,核心微控制器(MCU)突然被厂商宣布进入生命周期末期(EOL)&am…

作者头像 李华
网站建设 2026/6/8 13:15:10

如何免费解锁九大网盘直链下载?LinkSwift终极指南

如何免费解锁九大网盘直链下载?LinkSwift终极指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘…

作者头像 李华
网站建设 2026/6/8 13:11:37

JPEG2000算术编码原理与StarCore SC140 DSP平台深度优化实践

1. 项目概述在嵌入式图像处理领域,尤其是在资源受限的DSP平台上实现高效的图像压缩,一直是个既考验算法功底又挑战工程实现能力的活儿。今天我想和大家深入聊聊JPEG2000标准里的算术编码,以及我们如何在飞思卡尔的StarCore SC140这颗DSP上把它…

作者头像 李华
网站建设 2026/6/8 13:07:48

飞思卡尔串行Bootloader设计:低成本固件更新与FC协议解析

1. 项目概述:低成本串行Bootloader的设计哲学在嵌入式产品开发与维护的漫长周期里,固件更新是一个绕不开的环节。想象一下,一个已经部署在工厂流水线或智能家居设备中的控制器,发现了一个需要修复的软件缺陷,或者需要增…

作者头像 李华