在工业4.0时代,智能预测性维护已成为制造企业降本增效的关键技术。本文将基于实际工业数据集,详细介绍如何利用C#和ML.NET构建工业设备异常检测与故障预测系统,助力企业实现从被动维修向主动预防的转变。
关键词:工业设备监控、预测性维护、C#、ML.NET、异常检测、设备故障预测、工业物联网
通过分析上传的工业设备监控数据,我们可以看到系统监控了三类关键设备:
这些设备分布在五个主要城市:亚特兰大(Atlanta)、芝加哥(Chicago)、休斯顿(Houston)、纽约(New York)和旧金山(San Francisco),其中亚特兰大和芝加哥各占约20%。
监控数据包含四个关键传感器参数:
下面我们将根据实际数据集,展示如何使用C#和ML.NET构建完整的预测性维护解决方案。
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.ML.Trainers.LightGbm; // 添加LightGBM引用
namespace AppEquipment
{
/// <summary>
/// 工业设备数据类
/// </summary>
public class DeviceData
{
[LoadColumn(0)]
public float Temperature { get; set; }
[LoadColumn(1)]
public float Pressure { get; set; }
[LoadColumn(2)]
public float Vibration { get; set; }
[LoadColumn(3)]
public float Humidity { get; set; }
[LoadColumn(4)]
public string EquipmentType { get; set; }
[LoadColumn(5)]
public string Location { get; set; }
[LoadColumn(6)]
public bool Faulty { get; set; } // 注意:需要确保CSV的0.0/1.0能正确转为布尔值
}
/// <summary>
/// 异常检测预测结果类
/// </summary>
public class DeviceAnomalyPrediction
{
[ColumnName("PredictedLabel")]
public bool PredictedLabel { get; set; }
[ColumnName("Score")]
public float Prediction { get; set; }
}
/// <summary>
/// 故障预测结果类
/// </summary>
public class DeviceFailurePrediction
{
[ColumnName("PredictedLabel")]
public bool PredictedLabel { get; set; }
[ColumnName("Probability")]
public float Probability { get; set; }
}
// 自定义类型用于故障值转换
public class FaultyInput
{
public float FaultyValue { get; set; }
}
public class FaultyOutput
{
public bool Faulty { get; set; }
}
/// <summary>
/// 工业设备监控系统核心类
/// </summary>
public class DeviceMonitoringSystem
{
private readonly MLContext _mlContext;
private ITransformer _anomalyModel;
private ITransformer _failurePredictionModel;
public DeviceMonitoringSystem()
{
// 创建ML.NET上下文,设置固定种子确保结果可重现
_mlContext = new MLContext(seed: 42);
}
/// <summary>
/// 加载并预处理设备监控数据
/// </summary>
/// <param name="dataPath">CSV数据文件路径</param>
/// <returns>处理后的数据</returns>
public IDataView LoadAndPrepareData(string dataPath)
{
// 第一步:先将故障列作为浮点数加载
var options = new TextLoader.Options()
{
Separators = new char[] { ',' },
HasHeader = true,
Columns = new[]
{
new TextLoader.Column("Temperature", DataKind.Single, 0),
new TextLoader.Column("Pressure", DataKind.Single, 1),
new TextLoader.Column("Vibration", DataKind.Single, 2),
new TextLoader.Column("Humidity", DataKind.Single, 3),
new TextLoader.Column("equipment", DataKind.String, 4),
new TextLoader.Column("location", DataKind.String, 5),
new TextLoader.Column("FaultyValue", DataKind.Single, 6) // 先作为浮点数加载
}
};
// 从CSV文件加载数据
IDataView rawData = _mlContext.Data.LoadFromTextFile(dataPath, options);
// 第二步:将浮点数转换为布尔值
var convertedData = _mlContext.Transforms
.CustomMapping<FaultyInput, FaultyOutput>(
(input, output) => output.Faulty = input.FaultyValue > 0.5f,
"FaultyValueToBool")
.Fit(rawData)
.Transform(rawData);
// 第三步:复制列名以匹配类中的属性名
var namedData = _mlContext.Transforms
.CopyColumns("EquipmentType", "equipment")
.Append(_mlContext.Transforms.CopyColumns("Location", "location"))
.Fit(convertedData)
.Transform(convertedData);
Console.WriteLine("原始数据加载完成,数据预处理完成");
return namedData;
}
/// <summary>
/// 训练异常检测模型 - 基于实际工业设备数据
/// </summary>
/// <param name="preparedData">预处理后的数据</param>
/// <summary>
/// 训练异常检测模型 - 基于实际工业设备数据
/// </summary>
/// <param name="rawData">原始数据(不是预处理后的数据)</param>
public void TrainAnomalyDetectionModel(IDataView preparedData)
{
Console.WriteLine("开始训练异常检测模型...");
// 将数据分成训练集和测试集(80/20分割)
DataOperationsCatalog.TrainTestData dataSplit = _mlContext.Data.TrainTestSplit(preparedData, testFraction: 0.2);
// 构建异常检测管道
var pipeline = _mlContext.Transforms
// 分类特征处理
.Categorical.OneHotEncoding("EquipmentTypeEncoded", "EquipmentType")
.Append(_mlContext.Transforms.Categorical.OneHotEncoding("LocationEncoded", "Location"))
// 特征合并
.Append(_mlContext.Transforms.Concatenate("Features",
"Temperature", "Pressure", "Vibration", "Humidity", "EquipmentTypeEncoded", "LocationEncoded"))
// 标准化
.Append(_mlContext.Transforms.NormalizeMinMax("NormalizedFeatures", "Features"))
// 重要修改:移除PCA降维步骤,直接使用标准化特征
.Append(_mlContext.AnomalyDetection.Trainers.RandomizedPca(
featureColumnName: "NormalizedFeatures",
rank: 3)); // 设置rank与特征维度匹配,而不是使用默认的20
try
{
_anomalyModel = pipeline.Fit(dataSplit.TrainSet);
Console.WriteLine("异常检测模型训练完成!");
// 评估模型代码不变...
}
catch (Exception ex)
{
Console.WriteLine($"模型训练过程中发生错误: {ex.Message}");
Console.WriteLine($"详细信息: {ex.ToString()}");
}
}
/// <summary>
/// 检测设备数据是否异常
/// </summary>
/// <param name="data">设备数据</param>
/// <returns>异常检测结果</returns>
public DeviceAnomalyPrediction DetectAnomaly(DeviceData data)
{
// 确保模型已加载
if (_anomalyModel == null)
{
throw new InvalidOperationException("异常检测模型尚未训练,请先调用TrainAnomalyDetectionModel方法");
}
// 创建预测引擎
var predictionEngine = _mlContext.Model.CreatePredictionEngine<DeviceData, DeviceAnomalyPrediction>(_anomalyModel);
// 进行预测
var prediction = predictionEngine.Predict(data);
return prediction;
}
/// <summary>
/// 训练设备故障预测模型 - 针对实际工业设备故障数据
/// </summary>
/// <param name="preparedData">预处理后的数据</param>
public void TrainFailurePredictionModel(IDataView preparedData)
{
Console.WriteLine("开始训练故障预测模型...");
// 数据分割
DataOperationsCatalog.TrainTestData dataSplit = _mlContext.Data.TrainTestSplit(preparedData, testFraction: 0.2);
// 创建与异常检测模型相同的特征处理流程
var featurePipeline = _mlContext.Transforms
.Categorical.OneHotEncoding("EquipmentTypeEncoded", "EquipmentType")
.Append(_mlContext.Transforms.Categorical.OneHotEncoding("LocationEncoded", "Location"))
.Append(_mlContext.Transforms.Concatenate("Features",
"Temperature", "Pressure", "Vibration", "Humidity", "EquipmentTypeEncoded", "LocationEncoded"))
.Append(_mlContext.Transforms.NormalizeMinMax("NormalizedFeatures", "Features"));
// 先应用特征处理
var transformedData = featurePipeline.Fit(dataSplit.TrainSet).Transform(dataSplit.TrainSet);
var transformedTestData = featurePipeline.Fit(dataSplit.TestSet).Transform(dataSplit.TestSet);
// 创建故障预测训练管道
var failurePipeline = _mlContext.BinaryClassification.Trainers
.LightGbm(new LightGbmBinaryTrainer.Options
{
LabelColumnName = "Faulty",
FeatureColumnName = "NormalizedFeatures", // 使用之前处理好的特征
NumberOfLeaves = 32,
NumberOfIterations = 100,
MinimumExampleCountPerLeaf = 20,
LearningRate = 0.1
});
try
{
// 训练模型
_failurePredictionModel = failurePipeline.Fit(transformedData);
Console.WriteLine("故障预测模型训练完成!");
// 评估模型
var predictions = _failurePredictionModel.Transform(transformedTestData);
var metrics = _mlContext.BinaryClassification.Evaluate(predictions, "Faulty");
// 输出评估指标
Console.WriteLine($"准确率: {metrics.Accuracy:F4}");
Console.WriteLine($"精确率: {metrics.PositivePrecision:F4}");
Console.WriteLine($"召回率: {metrics.PositiveRecall:F4}");
Console.WriteLine($"F1分数: {metrics.F1Score:F4}");
Console.WriteLine($"AUC: {metrics.AreaUnderRocCurve:F4}");
}
catch (Exception ex)
{
Console.WriteLine($"故障预测模型训练错误: {ex.Message}");
Console.WriteLine($"详细信息: {ex.ToString()}");
}
}
/// <summary>
/// 预测设备故障风险
/// </summary>
/// <param name="data">设备数据</param>
/// <returns>故障风险预测结果</returns>
public DeviceFailurePrediction PredictFailure(DeviceData data)
{
// 确保模型已加载
if (_failurePredictionModel == null)
{
throw new InvalidOperationException("故障预测模型尚未训练,请先调用TrainFailurePredictionModel方法");
}
// 创建预测引擎
var predictionEngine = _mlContext.Model.CreatePredictionEngine<DeviceData, DeviceFailurePrediction>(_failurePredictionModel);
// 进行预测
var prediction = predictionEngine.Predict(data);
return prediction;
}
/// <summary>
/// 保存训练好的模型
/// </summary>
/// <param name="modelPath">模型保存路径</param>
/// <param name="modelType">模型类型:"anomaly"或"failure"</param>
public void SaveModel(string modelPath, string modelType)
{
try
{
if (modelType == "anomaly" && _anomalyModel != null)
{
_mlContext.Model.Save(_anomalyModel, null, modelPath);
Console.WriteLine($"异常检测模型已保存至: {modelPath}");
}
else if (modelType == "failure" && _failurePredictionModel != null)
{
_mlContext.Model.Save(_failurePredictionModel, null, modelPath);
Console.WriteLine($"故障预测模型已保存至: {modelPath}");
}
else
{
Console.WriteLine("无模型可保存或模型类型不正确");
}
}
catch (Exception ex)
{
Console.WriteLine($"模型保存失败: {ex.Message}");
}
}
/// <summary>
/// 加载已训练的模型
/// </summary>
/// <param name="modelPath">模型文件路径</param>
/// <param name="modelType">模型类型:"anomaly"或"failure"</param>
public void LoadModel(string modelPath, string modelType)
{
try
{
if (modelType == "anomaly")
{
_anomalyModel = _mlContext.Model.Load(modelPath, out _);
Console.WriteLine("异常检测模型加载成功");
}
else if (modelType == "failure")
{
_failurePredictionModel = _mlContext.Model.Load(modelPath, out _);
Console.WriteLine("故障预测模型加载成功");
}
}
catch (Exception ex)
{
Console.WriteLine($"模型加载失败: {ex.Message}");
}
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppEquipment
{
/// <summary>
/// 实时工业设备监控系统
/// </summary>
public class RealTimeMonitoringSystem
{
private readonly DeviceMonitoringSystem _monitoringSystem;
private readonly List<DeviceData> _recentAlerts;
private readonly int _alertHistoryLimit;
public RealTimeMonitoringSystem(DeviceMonitoringSystem monitoringSystem, int alertHistoryLimit = 10)
{
_monitoringSystem = monitoringSystem;
_recentAlerts = new List<DeviceData>();
_alertHistoryLimit = alertHistoryLimit;
}
/// <summary>
/// 启动实时监控
/// </summary>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>监控任务</returns>
public async Task StartMonitoringAsync(CancellationToken cancellationToken = default)
{
Console.WriteLine("实时监控系统已启动...");
// 模拟不同类型设备的数据流
var deviceSimulators = new List<Func<DeviceData>>
{
// 压缩机模拟器 - 基于真实数据范围
() => new DeviceData
{
EquipmentType = "Compressor",
Location = GetRandomLocation(),
Temperature = GetRandomValue(45.0f, 85.0f),
Pressure = GetRandomValue(25.0f, 45.0f),
Vibration = GetRandomValue(0.7f, 2.5f),
Humidity = GetRandomValue(35.0f, 60.0f)
},
// 涡轮机模拟器
() => new DeviceData
{
EquipmentType = "Turbine",
Location = GetRandomLocation(),
Temperature = GetRandomValue(60.0f, 95.0f),
Pressure = GetRandomValue(30.0f, 50.0f),
Vibration = GetRandomValue(0.9f, 3.0f),
Humidity = GetRandomValue(30.0f, 55.0f)
},
// 泵模拟器
() => new DeviceData
{
EquipmentType = "Pump",
Location = GetRandomLocation(),
Temperature = GetRandomValue(50.0f, 80.0f),
Pressure = GetRandomValue(30.0f, 65.0f),
Vibration = GetRandomValue(0.5f, 2.0f),
Humidity = GetRandomValue(40.0f, 70.0f)
},
// 异常压缩机 - 基于数据集中的异常案例
() => new DeviceData
{
EquipmentType = "Compressor",
Location = "Atlanta",
Temperature = GetRandomValue(120.0f, 140.0f), // 异常高温
Pressure = GetRandomValue(60.0f, 75.0f), // 异常高压
Vibration = GetRandomValue(3.5f, 4.8f), // 异常振动
Humidity = GetRandomValue(25.0f, 35.0f)
}
};
// 监控循环
while (!cancellationToken.IsCancellationRequested)
{
try
{
// 随机选择一个设备模拟器
var rand = new Random();
var deviceSimulator = deviceSimulators[rand.Next(deviceSimulators.Count)];
// 获取模拟设备数据
var deviceData = deviceSimulator();
// 监控设备
await MonitorDeviceAsync(deviceData);
// 间隔2秒
await Task.Delay(2000, cancellationToken);
}
catch (OperationCanceledException)
{
// 取消操作处理
break;
}
catch (Exception ex)
{
Console.WriteLine($"监控过程中发生错误: {ex.Message}");
}
}
Console.WriteLine("实时监控系统已停止");
}
/// <summary>
/// 监控单个设备
/// </summary>
/// <param name="deviceData">设备数据</param>
private async Task MonitorDeviceAsync(DeviceData deviceData)
{
// 异常检测
var anomalyResult = _monitoringSystem.DetectAnomaly(deviceData);
// 显示设备状态
Console.WriteLine($"\n设备: {deviceData.EquipmentType} @ {deviceData.Location}");
Console.WriteLine($"温度: {deviceData.Temperature:F2}°C, 压力: {deviceData.Pressure:F2} bar");
Console.WriteLine($"振动: {deviceData.Vibration:F2} mm/s, 湿度: {deviceData.Humidity:F2}%");
// 状态评估
var status = "正常";
var alertColor = ConsoleColor.Green;
if (anomalyResult.Prediction > 0.7f)
{
status = "严重异常";
alertColor = ConsoleColor.Red;
AddAlert(deviceData);
}
else if (anomalyResult.Prediction > 0.5f)
{
status = "轻微异常";
alertColor = ConsoleColor.Yellow;
}
// 显示状态
Console.Write("状态: ");
var originalColor = Console.ForegroundColor;
Console.ForegroundColor = alertColor;
Console.Write(status);
Console.ForegroundColor = originalColor;
Console.WriteLine($" (异常分数: {anomalyResult.Prediction:F4})");
// 如果是严重异常,记录并显示警报
if (anomalyResult.Prediction > 0.7f)
{
await Task.Delay(500); // 短暂延迟
DisplayAlertHistory();
}
}
/// <summary>
/// 添加警报到历史记录
/// </summary>
/// <param name="deviceData">设备数据</param>
private void AddAlert(DeviceData deviceData)
{
_recentAlerts.Add(deviceData);
// 保持历史记录在限制范围内
if (_recentAlerts.Count > _alertHistoryLimit)
{
_recentAlerts.RemoveAt(0);
}
}
/// <summary>
/// 显示警报历史
/// </summary>
private void DisplayAlertHistory()
{
Console.WriteLine("\n--- 最近警报历史 ---");
for (int i = _recentAlerts.Count - 1; i >= 0; i--)
{
var alert = _recentAlerts[i];
Console.WriteLine($"{DateTime.Now.AddMinutes(-(_recentAlerts.Count - i)):HH:mm:ss} - " +
$"{alert.EquipmentType} @ {alert.Location} - " +
$"温度: {alert.Temperature:F1}°C, 振动: {alert.Vibration:F1} mm/s");
}
Console.WriteLine("--------------------\n");
}
// 辅助方法 - 获取随机位置
private string GetRandomLocation()
{
var locations = new[] { "Atlanta", "Chicago", "Houston", "New York", "San Francisco" };
return locations[new Random().Next(locations.Length)];
}
// 辅助方法 - 获取随机值
private float GetRandomValue(float min, float max)
{
return (float)(min + new Random().NextDouble() * (max - min));
}
}
}
C#namespace AppEquipment
{
internal class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("===== 工业设备预测性维护系统 =====");
Console.WriteLine("基于ML.NET的实时设备监控与故障预测\n");
// 创建监控系统
var monitoringSystem = new DeviceMonitoringSystem();
// 数据文件路径
string dataPath = "equipment_anomaly_data.csv";
try
{
// 加载并预处理数据
Console.WriteLine("正在加载工业设备数据...");
var preparedData = monitoringSystem.LoadAndPrepareData(dataPath);
// 训练异常检测模型
Console.WriteLine("\n开始训练异常检测模型...");
monitoringSystem.TrainAnomalyDetectionModel(preparedData);
// 训练故障预测模型
Console.WriteLine("\n开始训练故障预测模型...");
monitoringSystem.TrainFailurePredictionModel(preparedData);
// 保存模型
Console.WriteLine("\n保存模型到本地...");
monitoringSystem.SaveModel("anomaly_model.zip", "anomaly");
monitoringSystem.SaveModel("failure_model.zip", "failure");
// 创建实时监控系统
Console.WriteLine("\n初始化实时监控系统...");
var realTimeSystem = new RealTimeMonitoringSystem(monitoringSystem);
// 启动监控
Console.WriteLine("\n启动实时监控 (按Ctrl+C退出)...\n");
// 设置取消令牌,以便用户可以停止监控
using var cts = new CancellationTokenSource();
// 处理Ctrl+C
Console.CancelKeyPress += (s, e) => {
e.Cancel = true;
cts.Cancel();
};
// 启动监控任务
await realTimeSystem.StartMonitoringAsync(cts.Token);
}
catch (Exception ex)
{
Console.WriteLine($"程序执行过程中发生错误: {ex.Message}");
Console.WriteLine(ex.StackTrace);
}
Console.WriteLine("\n程序执行完毕。按任意键退出...");
Console.ReadKey();
}
}
}

通过分析上传的设备数据,我们可以得出以下几点重要发现:
基于数据分析和模型结果,我们建议:
基于C#和ML.NET构建的工业设备预测性维护系统,通过对实际工业数据的深入分析,已证明能够:
未来系统优化方向:
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!