曲线逻辑

This commit is contained in:
hsc
2026-06-26 13:55:37 +08:00
parent 52edf16176
commit 4567f058b5
8 changed files with 484 additions and 237 deletions

View File

@@ -0,0 +1,105 @@
using OxyPlot.Series;
using OxyPlot;
using System.Collections.Concurrent;
using Prism.Mvvm;
using NCalc;
namespace MonitorModule.ViewModels
{
/// <summary>
/// 监测通道:一个设备方法对应一个通道。
/// 数据记录DataPoints与图表显示Series完全分离
/// - IsMonitored=true 时始终记录 DataPoints
/// - IsDisplayed=true 时才创建 LineSeries 并绘制
/// </summary>
public class MonitorChannel : BindableBase
{
// ===== 标识 =====
public string DeviceName { get; init; } = string.Empty;
public string MethodName { get; init; } = string.Empty;
public string DisplayName { get; init; } = string.Empty;
// ===== 状态 =====
private bool _isMonitored = true;
/// <summary>是否在记录数据点(添加后始终为 true</summary>
public bool IsMonitored
{
get => _isMonitored;
set => SetProperty(ref _isMonitored, value);
}
private bool _isDisplayed = true;
/// <summary>是否在 OxyPlot 上显示</summary>
public bool IsDisplayed
{
get => _isDisplayed;
set => SetProperty(ref _isDisplayed, value);
}
// ===== 数学变换 =====
private string? _mathExpression;
/// <summary>可选数学变换表达式,如 "x*0.001"。为空则 DisplayValue=RawValue</summary>
public string? MathExpression
{
get => _mathExpression;
set => SetProperty(ref _mathExpression, value);
}
// ===== 颜色 =====
public OxyColor Color { get; set; } = OxyColors.SteelBlue;
// ===== 数据存储 =====
/// <summary>所有采样数据点(线程安全),与 OxyPlot 无关</summary>
public ConcurrentQueue<(double Time, double RawValue, double DisplayValue)> DataPoints { get; } = new();
/// <summary>最大缓冲数据点数,超出则丢弃最旧的</summary>
public int MaxBuffer { get; set; } = 5000;
// ===== OxyPlot Series仅 IsDisplayed=true 时存在)=====
private LineSeries? _series;
public LineSeries? Series
{
get => _series;
set => SetProperty(ref _series, value);
}
// ===== 辅助方法 =====
/// <summary>记录一个数据点RawValue 经数学变换后得到 DisplayValue一并入队</summary>
public void Record(double time, double rawValue)
{
double displayValue = rawValue;
if (!string.IsNullOrWhiteSpace(MathExpression))
{
try
{
var expr = new NCalc.Expression(MathExpression);
expr.Parameters["x"] = rawValue;
var result = expr.Evaluate();
displayValue = Convert.ToDouble(result);
}
catch
{
displayValue = rawValue;
}
}
DataPoints.Enqueue((time, rawValue, displayValue));
// 超出缓冲上限时批量丢弃旧数据
while (DataPoints.Count > MaxBuffer)
{
DataPoints.TryDequeue(out _);
}
// 如果正在显示,同步到 Series
if (_series != null)
{
_series.Points.Add(new DataPoint(time, displayValue));
while (_series.Points.Count > 200)
{
_series.Points.RemoveAt(0);
}
}
}
}
}