1364 lines
48 KiB
C#
1364 lines
48 KiB
C#
using MembranePoreTester.Communication;
|
||
using MembranePoreTester.Helpers;
|
||
using MembranePoreTester.Models;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Win32;
|
||
using OxyPlot;
|
||
using OxyPlot.Axes;
|
||
using OxyPlot.Legends;
|
||
using OxyPlot.Series;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.Collections.Specialized;
|
||
using System.ComponentModel;
|
||
using System.Linq;
|
||
using System.Net;
|
||
using System.Windows;
|
||
using System.Windows.Input;
|
||
|
||
namespace MembranePoreTester.ViewModels
|
||
{
|
||
public class PoreDistributionViewModel : ViewModelBase, IStationViewModel
|
||
{
|
||
|
||
#region
|
||
|
||
public class PressureModeItem
|
||
{
|
||
public string Text { get; set; }
|
||
public int Value { get; set; }
|
||
|
||
|
||
public override string ToString()
|
||
{
|
||
return Text; // 直接返回要显示的文本
|
||
}
|
||
}
|
||
|
||
private PressureModeItem _selectedPressureMode;
|
||
private List<PressureModeItem> _pressureModeList;
|
||
|
||
public List<PressureModeItem> PressureModeList => _pressureModeList ??= new List<PressureModeItem>
|
||
{
|
||
new PressureModeItem { Text = "小流量", Value = 1 },
|
||
new PressureModeItem { Text = "大流量", Value = 0 }
|
||
};
|
||
|
||
public PressureModeItem SelectedPressureMode
|
||
{
|
||
get => _selectedPressureMode;
|
||
set
|
||
{
|
||
if (SetProperty(ref _selectedPressureMode, value))
|
||
{
|
||
Task.Run(async () => await WriteFlowModeAsync(value?.Text ?? "小流量"));
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
#endregion
|
||
|
||
|
||
|
||
// 添加字段
|
||
private System.Windows.Threading.DispatcherTimer _autoCollectTimer;
|
||
private bool _isCollecting = false;
|
||
|
||
// 添加公共方法供工位调用
|
||
//public void StartCollecting()
|
||
//{
|
||
// System.Diagnostics.Debug.WriteLine($"StartCollecting 工位{StationId}, IsActive={IsActive}");
|
||
// //if (!IsActive)
|
||
// //{
|
||
// // // 如果当前不在孔分布界面,不启动采集
|
||
// // return;
|
||
// //}
|
||
|
||
// if (_isCollecting) return;
|
||
// _isCollecting = true;
|
||
// _autoCollectTimer = new System.Windows.Threading.DispatcherTimer
|
||
// {
|
||
// Interval = TimeSpan.FromSeconds(1)
|
||
// };
|
||
// _autoCollectTimer.Tick += AutoCollectTimer_Tick;
|
||
// _autoCollectTimer.Start();
|
||
//}
|
||
public void StartCollecting()
|
||
{
|
||
// 不再依赖 IsActive,定时器始终启动
|
||
if (_isCollecting) return;
|
||
_isCollecting = true;
|
||
_autoCollectTimer = new System.Windows.Threading.DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
|
||
_autoCollectTimer.Tick += AutoCollectTimer_Tick;
|
||
_autoCollectTimer.Start();
|
||
}
|
||
public void StopCollecting()
|
||
{
|
||
_isCollecting = false;
|
||
_autoCollectTimer?.Stop();
|
||
_autoCollectTimer = null;
|
||
}
|
||
|
||
private async void AutoCollectTimer_Tick(object sender, EventArgs e)
|
||
{
|
||
//if (!IsActive) return;
|
||
|
||
try
|
||
{
|
||
// 1. 读取当前压力
|
||
float rawPressure = await _plcService.ReadPressureAsync(StationId);
|
||
double pressure = Math.Round(rawPressure * _plcConfig.PressureFactor, 2);
|
||
|
||
|
||
|
||
|
||
|
||
|
||
// 2. 读取当前工位的加压上限(实时)
|
||
ushort upperLimitAddress = StationId == 1 ? _plcConfig.PressureUpperLimit
|
||
: StationId == 2 ? _plcConfig.PressureUpperLimit2
|
||
: _plcConfig.PressureUpperLimit3;
|
||
double pressureUpperLimit = await _plcService.ReadFloatAsync(upperLimitAddress);
|
||
|
||
// 3. 如果压力已达到或超过上限,停止采集
|
||
if (pressure >= pressureUpperLimit * 1000 - 10 * 1000 && pressure > 0)
|
||
{
|
||
StopCollecting();
|
||
return; // 不再添加当前数据点
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
// 2. 读取当前模式对应的流量
|
||
double flow = 0;
|
||
if (TestMode.Contains("湿膜"))
|
||
{
|
||
float rawFlow = await _plcService.ReadWetFlowAsync(StationId);
|
||
flow = Math.Round(ConvertFlowByMode(rawFlow), 3);
|
||
}
|
||
else
|
||
{
|
||
float rawFlow = await _plcService.ReadDryFlowAsync(StationId);
|
||
flow = Math.Round(ConvertFlowByMode(rawFlow), 3);
|
||
}
|
||
|
||
|
||
float Pressure = await _plcService.ReadPressureAsync(StationId);
|
||
CurrentPressure = Math.Round(rawPressure, 2);
|
||
|
||
|
||
if (pressure <= 0 || flow <= 0)
|
||
return;
|
||
CurrentFlow = flow;
|
||
// 3. 查找是否已有相同压力点(按两位小数匹配),有则更新对应流量,否则新增
|
||
var existing = Record.DataPoints.FirstOrDefault(p => Math.Abs(p.Pressure - pressure) < 0.001);
|
||
if (existing != null)
|
||
{
|
||
if (TestMode != null && TestMode.Contains("湿膜"))
|
||
existing.WetFlow = flow;
|
||
else
|
||
existing.DryFlow = flow;
|
||
}
|
||
else
|
||
{
|
||
var newPoint = new Models.DataPoint
|
||
{
|
||
Pressure = Math.Round(pressure, 2),
|
||
WetFlow = TestMode != null && TestMode.Contains("湿膜") ? flow : 0,
|
||
DryFlow = TestMode != null && TestMode.Contains("干膜") ? flow : 0
|
||
};
|
||
Record.DataPoints.Add(newPoint);
|
||
}
|
||
|
||
// 4. 刷新曲线
|
||
UpdatePlot();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"自动采集失败: {ex.Message}");
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 清空所有数据点,重置表格和曲线
|
||
/// </summary>
|
||
public void ClearData()
|
||
{
|
||
// 清空数据点集合
|
||
Record.DataPoints.Clear();
|
||
PlotModel = new PlotModel();
|
||
// 重置曲线
|
||
UpdatePlot();
|
||
|
||
// 重置计算结果
|
||
AveragePoreSize = 0;
|
||
RangePercentage = 0;
|
||
|
||
// 可选:显示提示
|
||
System.Diagnostics.Debug.WriteLine("孔分布数据已清空");
|
||
}
|
||
|
||
private bool _isActive;
|
||
public bool IsActive
|
||
{
|
||
get => _isActive;
|
||
set => SetProperty(ref _isActive, value);
|
||
}
|
||
|
||
|
||
private PoreDistributionRecord _record = new();
|
||
private TestLiquid _selectedLiquid;
|
||
private bool _isCustomLiquid;
|
||
private double _customSurfaceTension = 30.0;
|
||
private double _lowerPore = 0.05;
|
||
private double _upperPore = 0.65;
|
||
private double _rangePercentage;
|
||
|
||
|
||
|
||
// 添加字段
|
||
private readonly IPlcService _plcService;
|
||
private readonly PlcConfiguration _plcConfig;
|
||
private Models.DataPoint _selectedDataPoint;
|
||
|
||
|
||
// 添加属性
|
||
public Models.DataPoint SelectedDataPoint
|
||
{
|
||
get => _selectedDataPoint;
|
||
set => SetProperty(ref _selectedDataPoint, value);
|
||
}
|
||
|
||
public ICommand ReadPlcCommand { get; }
|
||
|
||
public PoreDistributionRecord Record
|
||
{
|
||
get => _record;
|
||
set
|
||
{
|
||
if (SetProperty(ref _record, value))
|
||
{
|
||
// 当 Record 替换时(例如从数据库加载),重新订阅其 DataPoints 集合
|
||
HookDataPointsCollection(_record?.DataPoints);
|
||
|
||
// 同步液体选择
|
||
if (_record?.Liquid != null)
|
||
{
|
||
var matchedLiquid = Liquids.FirstOrDefault(l => l.Name == _record.Liquid.Name);
|
||
SelectedLiquid = matchedLiquid ?? _record.Liquid;
|
||
}
|
||
else
|
||
{
|
||
SelectedLiquid = Liquids.FirstOrDefault();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public IReadOnlyList<TestLiquid> Liquids => TestLiquid.Predefined;
|
||
public List<string> PressureUnits => new() { "Pa", "cmHg", "psi" };
|
||
public List<string> MembraneTypes => new() { "平板膜", "中空纤维膜" };
|
||
|
||
public TestLiquid SelectedLiquid
|
||
{
|
||
get => _selectedLiquid;
|
||
set
|
||
{
|
||
if (SetProperty(ref _selectedLiquid, value))
|
||
{
|
||
Record.Liquid = value;
|
||
}
|
||
}
|
||
}
|
||
|
||
public bool IsCustomLiquid
|
||
{
|
||
get => _isCustomLiquid;
|
||
set
|
||
{
|
||
if (SetProperty(ref _isCustomLiquid, value))
|
||
{
|
||
UpdateCustomLiquid();
|
||
}
|
||
}
|
||
}
|
||
|
||
public double CustomSurfaceTension
|
||
{
|
||
get => _customSurfaceTension;
|
||
set
|
||
{
|
||
if (SetProperty(ref _customSurfaceTension, value))
|
||
{
|
||
UpdateCustomLiquid();
|
||
}
|
||
}
|
||
}
|
||
|
||
public double LowerPore
|
||
{
|
||
get => _lowerPore;
|
||
set => SetProperty(ref _lowerPore, value);
|
||
}
|
||
|
||
public double UpperPore
|
||
{
|
||
get => _upperPore;
|
||
set => SetProperty(ref _upperPore, value);
|
||
}
|
||
|
||
public double RangePercentage
|
||
{
|
||
get => _rangePercentage;
|
||
set => SetProperty(ref _rangePercentage, value);
|
||
}
|
||
|
||
public ICommand AddDataPointCommand { get; }
|
||
public ICommand RemoveDataPointCommand { get; }
|
||
public ICommand CalculateCommand { get; }
|
||
public ICommand GenerateReportCommand { get; }
|
||
private System.Windows.Threading.DispatcherTimer _timer; // 添加定时器字段
|
||
public PoreDistributionViewModel()
|
||
{
|
||
_plcService = App.PlcService;
|
||
_plcConfig = App.PlcConfig;
|
||
|
||
AddDataPointCommand = new RelayCommand(AddDataPoint);
|
||
RemoveDataPointCommand = new RelayCommand(RemoveDataPoint, () => Record.DataPoints.Any());
|
||
CalculateCommand = new RelayCommand(Calculate);
|
||
GenerateReportCommand = new RelayCommand(GenerateReport);
|
||
SelectedLiquid = Liquids[0];
|
||
Record.SampleType = "中空纤维膜";
|
||
Record.PressureUnit = PressureUnits[0]; // 默认 "Pa"
|
||
|
||
ReadPlcCommand = new RelayCommand(async () => await ReadPlcAsync());
|
||
SaveCommand = new RelayCommand(SaveToDatabase);
|
||
ExportCommand = new RelayCommand(ExportToExcel);
|
||
OpenFlowCalibCommand = new RelayCommand(OpenFlowCalibration);
|
||
OpenFlowCalibCommand2 = new RelayCommand(OpenFlowCalibration2);
|
||
|
||
// 订阅集合变更并为每个项订阅属性变化,保证 DataGrid 和 Plot 在项内容变化时同步刷新
|
||
HookDataPointsCollection(Record.DataPoints);
|
||
|
||
ClearAllCommand = new RelayCommand(ClearAllData);
|
||
|
||
RemoveDataPointCommand = new RelayCommand(RemoveSelectedDataPoint, () => SelectedDataPoint != null);
|
||
|
||
|
||
// 启动定时器,每秒读取一次
|
||
_timer = new System.Windows.Threading.DispatcherTimer();
|
||
_timer.Interval = TimeSpan.FromSeconds(1);
|
||
_timer.Tick += async (s, e) =>
|
||
{
|
||
if (StationId > 0 && !IsDisposed)
|
||
{
|
||
await ReadSpeedRateAsync();
|
||
}
|
||
};
|
||
_timer.Start();
|
||
|
||
|
||
// 延迟2秒后读取,确保连接稳定
|
||
Task.Delay(2000).ContinueWith(async _ =>
|
||
{
|
||
await ReadPressureModeAsync();
|
||
}, TaskScheduler.Default);
|
||
|
||
}
|
||
|
||
private void ClearAllData()
|
||
{
|
||
ClearData();
|
||
}
|
||
|
||
private string _speedRate1;
|
||
public string SpeedRate1
|
||
{
|
||
get => _speedRate1;
|
||
set => SetProperty(ref _speedRate1, value);
|
||
}
|
||
|
||
|
||
|
||
|
||
private async Task ReadSpeedRateAsync()
|
||
{
|
||
try
|
||
{
|
||
float speedRate = 0;
|
||
ushort address = 0;
|
||
switch (StationId)
|
||
{
|
||
case 1:
|
||
address = _plcConfig.HPCoeff11;
|
||
speedRate = await _plcService.ReadFloatAsync(address);
|
||
SpeedRate1 = speedRate.ToString("F3");
|
||
break;
|
||
case 2:
|
||
address = _plcConfig.HPCoeff12;
|
||
speedRate = await _plcService.ReadFloatAsync(address);
|
||
SpeedRate1 = speedRate.ToString("F3");
|
||
break;
|
||
case 3:
|
||
address = _plcConfig.HPCoeff13;
|
||
speedRate = await _plcService.ReadFloatAsync(address);
|
||
SpeedRate1 = speedRate.ToString("F3");
|
||
break;
|
||
}
|
||
// 如果需要刷新 Record 中的绑定(可选)
|
||
OnPropertyChanged(nameof(SpeedRate1));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"读取加压速率失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private async Task ReadPressureModeAsync()
|
||
{
|
||
await SafeExecuteAsync($"ReadPressureModeAsync{StationId}", async () =>
|
||
{
|
||
try
|
||
{
|
||
ushort[] values = await _plcService.ReadHoldingRegistersAsync(StationId == 1 ? _plcConfig.FlowModeRegister : StationId == 2 ? _plcConfig.FlowModeRegister2 : _plcConfig.FlowModeRegister3, 1);
|
||
ushort val = values[0];
|
||
string newValue = val == 0 ? "大流量" : "小流量";
|
||
|
||
Application.Current.Dispatcher.Invoke(() =>
|
||
{
|
||
// 更新选中项
|
||
HighLowPressure = newValue;
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"读取流量模式失败: {ex.Message}");
|
||
}
|
||
});
|
||
}
|
||
|
||
public string HighLowPressure
|
||
{
|
||
get => _selectedPressureMode?.Text ?? "小流量";
|
||
set
|
||
{
|
||
var mode = PressureModeList.FirstOrDefault(m => m.Text == value);
|
||
if (mode != null)
|
||
{
|
||
SelectedPressureMode = mode;
|
||
}
|
||
}
|
||
}
|
||
|
||
private async Task ReadPlcAsync()
|
||
{
|
||
await SafeExecuteAsync($"ManualRead_Station{StationId}", async () =>
|
||
{
|
||
|
||
// 始终读取压力
|
||
float rawPressure = await _plcService.ReadPressureAsync(StationId);
|
||
double pressure = Math.Round(rawPressure * _plcConfig.PressureFactor, 2);
|
||
|
||
if (SelectedDataPoint != null)
|
||
{
|
||
// 更新选中行
|
||
SelectedDataPoint.Pressure = pressure;
|
||
if (TestMode == "湿膜")
|
||
{
|
||
float rawWet = await _plcService.ReadWetFlowAsync(StationId);
|
||
SelectedDataPoint.WetFlow = ConvertFlowByMode(rawWet);
|
||
}
|
||
else
|
||
{
|
||
float rawDry = await _plcService.ReadDryFlowAsync(StationId);
|
||
SelectedDataPoint.DryFlow = ConvertFlowByMode(rawDry);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 新增一行
|
||
var newPoint = new Models.DataPoint { Pressure = pressure };
|
||
if (TestMode == "湿膜")
|
||
{
|
||
float rawWet = await _plcService.ReadWetFlowAsync(StationId);
|
||
newPoint.WetFlow = ConvertFlowByMode(rawWet);
|
||
}
|
||
else
|
||
{
|
||
float rawDry = await _plcService.ReadDryFlowAsync(StationId);
|
||
newPoint.DryFlow = ConvertFlowByMode(rawDry);
|
||
}
|
||
Record.DataPoints.Add(newPoint);
|
||
}
|
||
|
||
|
||
|
||
});
|
||
}
|
||
|
||
private void AddDataPoint()
|
||
{
|
||
Record.DataPoints.Add(new Models.DataPoint());
|
||
}
|
||
|
||
private void RemoveDataPoint()
|
||
{
|
||
if (Record.DataPoints.Any())
|
||
Record.DataPoints.RemoveAt(Record.DataPoints.Count - 1);
|
||
}
|
||
|
||
private void UpdateCustomLiquid()
|
||
{
|
||
if (IsCustomLiquid)
|
||
{
|
||
Record.Liquid = new TestLiquid
|
||
{
|
||
Name = "自定义",
|
||
SurfaceTension = CustomSurfaceTension
|
||
};
|
||
}
|
||
}
|
||
|
||
// 监听 DataPoints 集合与其子项的属性变更,确保 UI 同步更新
|
||
private void HookDataPointsCollection(ObservableCollection<Models.DataPoint> collection)
|
||
{
|
||
if (collection == null) return;
|
||
|
||
// 先解绑已有(避免重复订阅)
|
||
collection.CollectionChanged -= DataPoints_CollectionChanged;
|
||
collection.CollectionChanged += DataPoints_CollectionChanged;
|
||
|
||
// 为已有项订阅 PropertyChanged
|
||
foreach (var item in collection)
|
||
{
|
||
if (item is INotifyPropertyChanged inpc)
|
||
{
|
||
inpc.PropertyChanged -= DataPoint_PropertyChanged;
|
||
inpc.PropertyChanged += DataPoint_PropertyChanged;
|
||
}
|
||
}
|
||
}
|
||
|
||
private void DataPoints_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||
{
|
||
if (e.OldItems != null)
|
||
{
|
||
foreach (var old in e.OldItems)
|
||
{
|
||
if (old is INotifyPropertyChanged inpc)
|
||
inpc.PropertyChanged -= DataPoint_PropertyChanged;
|
||
}
|
||
}
|
||
|
||
if (e.NewItems != null)
|
||
{
|
||
foreach (var nw in e.NewItems)
|
||
{
|
||
if (nw is INotifyPropertyChanged inpc)
|
||
{
|
||
inpc.PropertyChanged -= DataPoint_PropertyChanged;
|
||
inpc.PropertyChanged += DataPoint_PropertyChanged;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 集合结构变化时刷新曲线
|
||
UpdatePlot();
|
||
}
|
||
|
||
private void DataPoint_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||
{
|
||
// 某个数据点属性改变时也刷新曲线
|
||
UpdatePlot();
|
||
}
|
||
|
||
// 添加私有字段和公共属性
|
||
private double _averagePoreSize;
|
||
public double AveragePoreSize
|
||
{
|
||
get => _averagePoreSize;
|
||
set => SetProperty(ref _averagePoreSize, value);
|
||
}
|
||
|
||
|
||
//修改 Calculate 方法:
|
||
private void Calculate()
|
||
{
|
||
// 先清洗数据并替换到绑定的集合中,确保DataGrid和曲线显示清洗后的数据
|
||
var originalPoints = Record.DataPoints.ToList();
|
||
|
||
System.Diagnostics.Debug.WriteLine("=== 清洗前的数据点 ===");
|
||
foreach (var p in originalPoints)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"P={p.Pressure}, Wet={p.WetFlow}, Dry={p.DryFlow}");
|
||
}
|
||
|
||
//var cleanedPoints = CleanDataPoints(originalPoints);
|
||
|
||
//if (cleanedPoints.Count < 2)
|
||
//{
|
||
// MessageBox.Show("有效数据点不足,至少需要 2 个数据点进行计算。");
|
||
// return;
|
||
//}
|
||
|
||
//int invalidCount = originalPoints.Count - cleanedPoints.Count;
|
||
|
||
// 用清洗后的点替换 ObservableCollection 的内容(触发UI更新)
|
||
Record.DataPoints.Clear();
|
||
foreach (var p in originalPoints)
|
||
Record.DataPoints.Add(p);
|
||
|
||
// 刷新曲线以显示清洗后的数据
|
||
UpdatePlot();
|
||
|
||
// 使用清洗后的集合进行计算
|
||
AveragePoreSize = PoreDistributionAnalysis.CalculateAveragePore(
|
||
Record.DataPoints, Record.PressureUnit, Record.Liquid);
|
||
|
||
RangePercentage = PoreDistributionAnalysis.CalculatePoreRangePercentage(
|
||
Record.DataPoints, Record.PressureUnit, Record.Liquid, LowerPore, UpperPore);
|
||
|
||
//if (invalidCount > 0)
|
||
//{
|
||
// MessageBox.Show($"已自动过滤 {invalidCount} 个无效数据点");
|
||
// System.Diagnostics.Debug.WriteLine($"已自动过滤 {invalidCount} 个无效数据点");
|
||
//}
|
||
}
|
||
|
||
//private void Calculate()
|
||
//{
|
||
// // 直接使用原始数据,不清洗
|
||
// if (Record.DataPoints.Count < 2)
|
||
// {
|
||
// MessageBox.Show("有效数据点不足,至少需要 2 个数据点进行计算。");
|
||
// return;
|
||
// }
|
||
|
||
// // 注意:不清洗,也不改变 Record.DataPoints 的顺序(但计算函数内部会自己排序)
|
||
// // 直接计算
|
||
// AveragePoreSize = PoreDistributionAnalysis.CalculateAveragePore(
|
||
// Record.DataPoints, Record.PressureUnit, Record.Liquid);
|
||
|
||
// RangePercentage = PoreDistributionAnalysis.CalculatePoreRangePercentage(
|
||
// Record.DataPoints, Record.PressureUnit, Record.Liquid, LowerPore, UpperPore);
|
||
|
||
// // 可选:提示用户当前使用了原始数据(不清洗)
|
||
// // MessageBox.Show("已使用原始数据(未清洗)进行计算");
|
||
//}
|
||
|
||
//private List<Models.DataPoint> CleanDataPoints(IEnumerable<Models.DataPoint> points)
|
||
//{
|
||
// return points
|
||
// .Where(p => p.Pressure > 0.001) // 移除压力接近0的点
|
||
// .Where(p => !(Math.Abs(p.WetFlow) < 0.001 && Math.Abs(p.DryFlow) < 0.001)) // 移除双零流量点
|
||
// .GroupBy(p => Math.Round(p.Pressure, 2)) // 按压力四舍五入分组(避免重复压力)
|
||
// .Select(g => new Models.DataPoint
|
||
// {
|
||
// Pressure = g.Key,
|
||
// WetFlow = g.Max(x => x.WetFlow), // 取最大值(避免0覆盖有效值)
|
||
// DryFlow = g.Max(x => x.DryFlow)
|
||
// })
|
||
// .OrderBy(p => p.Pressure)
|
||
// .ToList();
|
||
//}
|
||
|
||
|
||
|
||
private List<Models.DataPoint> CleanDataPoints(IEnumerable<Models.DataPoint> points)
|
||
{
|
||
// 第一步:基础清洗(移除压力≤0、双零流量、合并相同压力取最大流量)
|
||
var cleaned = points
|
||
.Where(p => p.Pressure > 0.001)
|
||
.Where(p => !(Math.Abs(p.WetFlow) < 0.001 && Math.Abs(p.DryFlow) < 0.001))
|
||
.GroupBy(p => Math.Round(p.Pressure, 2))
|
||
.Select(g => new Models.DataPoint
|
||
{
|
||
Pressure = g.Key,
|
||
WetFlow = g.Max(x => x.WetFlow),
|
||
DryFlow = g.Max(x => x.DryFlow)
|
||
})
|
||
.OrderBy(p => p.Pressure)
|
||
.ToList();
|
||
|
||
if (cleaned.Count < 4) return cleaned; // 点数太少,不进行高级剔除
|
||
|
||
// 第二步:仅对湿膜流量进行异常孤立点剔除(干膜保持原样,因为干膜可能有很多0和少量非零)
|
||
var result = new List<Models.DataPoint>();
|
||
const double threshold = 3.0; // 孤立高点阈值(倍),比之前放宽
|
||
|
||
for (int i = 0; i < cleaned.Count; i++)
|
||
{
|
||
var current = cleaned[i];
|
||
bool isAbnormal = false;
|
||
|
||
// 仅检查中间的点(非首尾),且只检查湿膜流量
|
||
if (i > 0 && i < cleaned.Count - 1)
|
||
{
|
||
double prevWet = cleaned[i - 1].WetFlow;
|
||
double nextWet = cleaned[i + 1].WetFlow;
|
||
double maxNeighbor = Math.Max(prevWet, nextWet);
|
||
double minNeighbor = Math.Min(prevWet, nextWet);
|
||
|
||
// 如果当前湿膜流量远大于前后邻居的最大值(孤立高峰),且前后邻居都不为0
|
||
if (maxNeighbor > 0 && current.WetFlow > maxNeighbor * threshold)
|
||
isAbnormal = true;
|
||
|
||
// 如果当前湿膜流量远小于前后邻居的最小值(孤立低谷),一般很少见,但保留
|
||
if (minNeighbor > 0 && current.WetFlow < minNeighbor / threshold)
|
||
isAbnormal = true;
|
||
}
|
||
|
||
// 不剔除干膜中的非零点(即使孤立也不删)
|
||
if (!isAbnormal)
|
||
result.Add(current);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
// 如果全部被误判为异常,则回退到原始清洗结果
|
||
return result.Count == 0 ? cleaned : result;
|
||
}
|
||
|
||
|
||
|
||
|
||
//private void GenerateReport()
|
||
//{
|
||
// ReportGenerator.GeneratePoreDistributionReport(Record);
|
||
//}
|
||
|
||
private void GenerateReport()
|
||
{
|
||
// 可选:先清洗数据再生成报告(但不改变原集合)
|
||
var cleanedPoints = CleanDataPoints(Record.DataPoints);
|
||
if (cleanedPoints.Count < 2)
|
||
{
|
||
MessageBox.Show("有效数据点不足,无法生成报告。");
|
||
return;
|
||
}
|
||
// 临时替换 Record 中的数据点用于报告(不影响界面)
|
||
var originalPoints = Record.DataPoints.ToList();
|
||
Record.DataPoints.Clear();
|
||
foreach (var p in cleanedPoints)
|
||
Record.DataPoints.Add(p);
|
||
|
||
|
||
|
||
|
||
|
||
ReportGenerator.GeneratePoreDistributionReport(Record, PlotModel);
|
||
|
||
// 恢复原始数据
|
||
Record.DataPoints.Clear();
|
||
foreach (var p in originalPoints)
|
||
Record.DataPoints.Add(p);
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//// 清空现有数据
|
||
//Record.DataPoints.Clear();
|
||
|
||
//Random rand = new Random();
|
||
|
||
//// 生成湿膜数据(模拟压力从0到100,流量先增后减)
|
||
//for (double pressure = 0; pressure <= 100; pressure += 5)
|
||
//{
|
||
// // 模拟流量曲线:先上升后下降,峰值在40-60之间
|
||
// double wetFlow = 0;
|
||
// if (pressure < 30)
|
||
// wetFlow = pressure * 1.5; // 上升段
|
||
// else if (pressure < 60)
|
||
// wetFlow = 45 - (pressure - 30) * 0.5; // 下降段
|
||
// else
|
||
// wetFlow = 30 - (pressure - 60) * 0.8; // 继续下降
|
||
|
||
// // 添加随机波动 (±15%)
|
||
// wetFlow = wetFlow * (0.85 + rand.NextDouble() * 0.3);
|
||
// wetFlow = Math.Round(Math.Max(0, wetFlow), 2);
|
||
|
||
// // 干膜数据(稍低于湿膜)
|
||
// double dryFlow = wetFlow * (0.6 + rand.NextDouble() * 0.3);
|
||
// dryFlow = Math.Round(dryFlow, 2);
|
||
|
||
// Record.DataPoints.Add(new Models.DataPoint
|
||
// {
|
||
// Pressure = Math.Round(pressure, 2),
|
||
// WetFlow = wetFlow,
|
||
// DryFlow = dryFlow
|
||
// });
|
||
//}
|
||
|
||
//// 设置一些测试基本参数
|
||
//Record.SampleType = "平板膜";
|
||
//Record.SampleSpec = "φ47mm";
|
||
//Record.RoomTemperature = 22.5;
|
||
//Record.SoakingTime = 2.0;
|
||
//Record.Liquid = TestLiquid.Predefined.FirstOrDefault();
|
||
//Record.LiquidManufacturer = "测试厂家";
|
||
//Record.PressureUnit = "kPa";
|
||
//Record.BubblePointPressure = 45.6;
|
||
//Record.AveragePoreSize = 0.856;
|
||
//Record.TestDate = DateTime.Now;
|
||
//Record.Tester = "测试员";
|
||
|
||
//// 刷新曲线显示
|
||
//UpdatePlot();
|
||
|
||
//ReportGenerator.GeneratePoreDistributionReport(Record, PlotModel);
|
||
|
||
}
|
||
|
||
private void OpenFlowCalibration()
|
||
{
|
||
// 弹出确认对话框
|
||
var result = MessageBox.Show(
|
||
"确定要进行流量校准吗?此操作将向PLC写入校准信号。",
|
||
"确认校准",
|
||
MessageBoxButton.YesNo,
|
||
MessageBoxImage.Question);
|
||
ushort address = new ushort();
|
||
switch (StationId)
|
||
{
|
||
case 1:
|
||
{
|
||
address = _plcConfig.BigFlow1;
|
||
break;
|
||
}
|
||
case 2:
|
||
{
|
||
address = _plcConfig.BigFlow2;
|
||
break;
|
||
}
|
||
case 3:
|
||
{
|
||
address = _plcConfig.BigFlow3;
|
||
break;
|
||
}
|
||
}
|
||
|
||
Task.Run(async () =>
|
||
{
|
||
await _plcService.WriteCoilAsync(address, true);
|
||
//MessageBox.Show("校准成功!");
|
||
});
|
||
}
|
||
|
||
private void OpenFlowCalibration2()
|
||
{
|
||
// 弹出确认对话框
|
||
var result = MessageBox.Show(
|
||
"确定要进行流量校准吗?此操作将向PLC写入校准信号。",
|
||
"确认校准",
|
||
MessageBoxButton.YesNo,
|
||
MessageBoxImage.Question);
|
||
ushort address = new ushort();
|
||
switch (StationId)
|
||
{
|
||
case 1:
|
||
{
|
||
address = _plcConfig.SmallFlow1;
|
||
break;
|
||
}
|
||
case 2:
|
||
{
|
||
address = _plcConfig.SmallFlow2;
|
||
break;
|
||
}
|
||
case 3:
|
||
{
|
||
address = _plcConfig.SmallFlow3;
|
||
break;
|
||
}
|
||
}
|
||
|
||
Task.Run(async () =>
|
||
{
|
||
await _plcService.WriteCoilAsync(address, true);
|
||
//MessageBox.Show("校准成功!");
|
||
});
|
||
}
|
||
|
||
private int _stationId;
|
||
public int StationId
|
||
{
|
||
get => _stationId;
|
||
set => SetProperty(ref _stationId, value);
|
||
}
|
||
|
||
// 初始化方法:在 MainViewModel 创建 StationItem 后调用,确保 StationId 已设置
|
||
public void Initialize(int stationId)
|
||
{
|
||
StationId = stationId;
|
||
// 延迟调用读取模式,确保PLC连接稳定
|
||
Task.Run(async () =>
|
||
{
|
||
await Task.Delay(200);
|
||
await ReadPressureModeAsync();
|
||
});
|
||
}
|
||
|
||
public void SaveToDatabase()
|
||
{
|
||
var entity = new PoreDistributionEntity
|
||
{
|
||
StationId = this.StationId,
|
||
TestDate = Record.TestDate,
|
||
Tester = Record.Tester ?? "系统操作员",
|
||
SampleType = Record.SampleType ?? "膜类型缺省值",
|
||
SampleSpec = Record.SampleSpec ?? "缺省值",
|
||
RoomTemperature = Record.RoomTemperature,
|
||
SoakingTime = Record.SoakingTime,
|
||
LiquidName = Record.Liquid?.Name,
|
||
LiquidSurfaceTension = Record.Liquid?.SurfaceTension ?? 0,
|
||
LiquidManufacturer = Record.LiquidManufacturer ?? "缺省值",
|
||
PressureUnit = Record.PressureUnit,
|
||
BubblePointPressure = Record.BubblePointPressure,
|
||
AveragePoreSize = AveragePoreSize, // 使用计算后的属性
|
||
DataPoints = Record.DataPoints.Select(dp => new DataPointEntity
|
||
{
|
||
Pressure = dp.Pressure,
|
||
WetFlow = dp.WetFlow,
|
||
DryFlow = dp.DryFlow
|
||
}).ToList()
|
||
};
|
||
|
||
using var db = new AppDbContext();
|
||
db.PoreDistributionRecords.Add(entity);
|
||
db.SaveChanges();
|
||
|
||
MessageBox.Show("保存成功!", "提示");
|
||
}
|
||
|
||
public void LoadFromDatabase(int recordId)
|
||
{
|
||
using var db = new AppDbContext();
|
||
var entity = db.PoreDistributionRecords
|
||
.Include(p => p.DataPoints)
|
||
.FirstOrDefault(p => p.Id == recordId);
|
||
if (entity == null) return;
|
||
|
||
Record.SampleType = entity.SampleType ?? "中空纤维膜";
|
||
Record.SampleSpec = entity.SampleSpec;
|
||
Record.RoomTemperature = entity.RoomTemperature;
|
||
Record.SoakingTime = entity.SoakingTime;
|
||
Record.Liquid = TestLiquid.Predefined.FirstOrDefault(l => l.Name == entity.LiquidName)
|
||
?? new TestLiquid { Name = entity.LiquidName, SurfaceTension = entity.LiquidSurfaceTension };
|
||
Record.LiquidManufacturer = entity.LiquidManufacturer;
|
||
Record.PressureUnit = entity.PressureUnit;
|
||
Record.BubblePointPressure = entity.BubblePointPressure;
|
||
Record.TestDate = entity.TestDate;
|
||
Record.Tester = entity.Tester;
|
||
|
||
Record.DataPoints.Clear();
|
||
foreach (var dp in entity.DataPoints)
|
||
{
|
||
Record.DataPoints.Add(new Models.DataPoint
|
||
{
|
||
Pressure = dp.Pressure,
|
||
WetFlow = dp.WetFlow,
|
||
DryFlow = dp.DryFlow
|
||
});
|
||
}
|
||
|
||
// 同步液体选择
|
||
if (Record.Liquid != null)
|
||
{
|
||
var matchedLiquid = Liquids.FirstOrDefault(l => l.Name == Record.Liquid.Name);
|
||
SelectedLiquid = matchedLiquid ?? Record.Liquid;
|
||
}
|
||
else
|
||
{
|
||
SelectedLiquid = Liquids.FirstOrDefault();
|
||
}
|
||
|
||
|
||
|
||
|
||
// 重新计算平均孔径和分布(触发计算命令)
|
||
Calculate();
|
||
}
|
||
|
||
|
||
public ICommand SaveCommand { get; }
|
||
|
||
|
||
public ICommand OpenFlowCalibCommand { get; }
|
||
|
||
public ICommand OpenFlowCalibCommand2 { get; }
|
||
public ICommand ExportCommand { get; }
|
||
|
||
|
||
|
||
private void ExportToExcel()
|
||
{
|
||
// 使用当前数据点(已通过手动删除或自动清洗,保证有效性)
|
||
var dataPoints = Record.DataPoints.ToList();
|
||
if (dataPoints.Count == 0)
|
||
{
|
||
MessageBox.Show("没有数据可导出。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
return;
|
||
}
|
||
|
||
var saveFileDialog = new SaveFileDialog
|
||
{
|
||
Filter = "Excel文件|*.xlsx",
|
||
FileName = $"孔分布_工位{StationId}_{DateTime.Now:yyyyMMddHHmmss}.xlsx"
|
||
};
|
||
if (saveFileDialog.ShowDialog() == true)
|
||
{
|
||
var entity = new PoreDistributionEntity
|
||
{
|
||
StationId = this.StationId,
|
||
TestDate = Record.TestDate,
|
||
Tester = Record.Tester ?? "系统操作员",
|
||
SampleType = Record.SampleType,
|
||
SampleSpec = Record.SampleSpec ?? "缺省值",
|
||
RoomTemperature = Record.RoomTemperature,
|
||
SoakingTime = Record.SoakingTime,
|
||
LiquidName = Record.Liquid?.Name,
|
||
LiquidSurfaceTension = Record.Liquid?.SurfaceTension ?? 0,
|
||
LiquidManufacturer = Record.LiquidManufacturer ?? "缺省值",
|
||
PressureUnit = Record.PressureUnit,
|
||
BubblePointPressure = Record.BubblePointPressure,
|
||
AveragePoreSize = AveragePoreSize, // 已计算的平均孔径
|
||
DataPoints = dataPoints.Select(dp => new DataPointEntity
|
||
{
|
||
Pressure = dp.Pressure,
|
||
WetFlow = dp.WetFlow,
|
||
DryFlow = dp.DryFlow
|
||
}).ToList()
|
||
};
|
||
ExportHelper.ExportPoreDistribution(entity, saveFileDialog.FileName);
|
||
MessageBox.Show("导出成功", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
}
|
||
}
|
||
|
||
|
||
private string _testMode = "湿膜"; // 默认湿膜
|
||
public string TestMode
|
||
{
|
||
get => _testMode;
|
||
set
|
||
{
|
||
if (SetProperty(ref _testMode, value))
|
||
{
|
||
// 切换测试模式时刷新曲线和相关逻辑
|
||
UpdatePlot();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
private OxyPlot.PlotModel _plotModel;
|
||
public OxyPlot.PlotModel PlotModel
|
||
{
|
||
get => _plotModel;
|
||
set => SetProperty(ref _plotModel, value);
|
||
}
|
||
|
||
// 用于保护绘图更新,避免并发导致渲染丢失
|
||
private readonly object _plotLock = new();
|
||
|
||
private async Task WriteFlowModeAsync(string mode)
|
||
{
|
||
ushort val = mode.ToString().Contains("大流量") ? (ushort)0 : (ushort)1;
|
||
try
|
||
{
|
||
if (StationId == 1)
|
||
await _plcService.WriteSingleRegisterAsync(_plcConfig.FlowModeRegister, val);
|
||
else if (StationId == 2)
|
||
await _plcService.WriteSingleRegisterAsync(_plcConfig.FlowModeRegister2, val);
|
||
else if (StationId == 3)
|
||
await _plcService.WriteSingleRegisterAsync(_plcConfig.FlowModeRegister3, val);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"写流量模式失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
//private void UpdatePlot()
|
||
//{
|
||
// // 确保在 UI 线程执行
|
||
// if (Application.Current != null && !Application.Current.Dispatcher.CheckAccess())
|
||
// {
|
||
// Application.Current.Dispatcher.BeginInvoke((Action)UpdatePlot);
|
||
// return;
|
||
// }
|
||
|
||
// var sorted = Record.DataPoints.OrderBy(p => p.Pressure).ToList();
|
||
// if (sorted.Count == 0)
|
||
// {
|
||
// PlotModel = null;
|
||
// return;
|
||
// }
|
||
|
||
// var model = new PlotModel
|
||
// {
|
||
// Title = "流量-压力曲线",
|
||
// TitleFontSize = 14,
|
||
// TitleFontWeight = 1
|
||
// };
|
||
|
||
// model.Axes.Add(new LinearAxis
|
||
// {
|
||
// Position = AxisPosition.Bottom,
|
||
// Title = "压力 (kPa)",
|
||
// TitleFontSize = 12
|
||
// });
|
||
// model.Axes.Add(new LinearAxis
|
||
// {
|
||
// Position = AxisPosition.Left,
|
||
// Title = "流量 (L/min)",
|
||
// TitleFontSize = 12,
|
||
// Minimum = 0,
|
||
// MajorGridlineStyle = LineStyle.Solid,
|
||
// MinorGridlineStyle = LineStyle.Dot
|
||
// });
|
||
|
||
// // 根据当前模式绘制对应的曲线(只绘制流量 > 0 的点)
|
||
// if (TestMode != null && TestMode.Contains("湿膜"))
|
||
// {
|
||
// var wetSeries = new LineSeries
|
||
// {
|
||
// Title = "湿膜流量 (Wet Flow)",
|
||
// Color = OxyColors.Blue,
|
||
// MarkerType = MarkerType.None,
|
||
// StrokeThickness = 1
|
||
// };
|
||
// foreach (var dp in sorted.Where(p => p.WetFlow > 0))
|
||
// wetSeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.WetFlow));
|
||
// if (wetSeries.Points.Count > 0)
|
||
// model.Series.Add(wetSeries);
|
||
// }
|
||
// else if (TestMode != null && TestMode.Contains("干膜"))
|
||
// {
|
||
// var drySeries = new LineSeries
|
||
// {
|
||
// Title = "干膜流量 (Dry Flow)",
|
||
// Color = OxyColors.Red,
|
||
// MarkerType = MarkerType.None,
|
||
// StrokeThickness = 1
|
||
// };
|
||
// foreach (var dp in sorted.Where(p => p.DryFlow > 0))
|
||
// drySeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.DryFlow));
|
||
// if (drySeries.Points.Count > 0)
|
||
// model.Series.Add(drySeries);
|
||
// }
|
||
// else
|
||
// {
|
||
// // “全部”模式:同时显示两条曲线,但仍过滤掉 0 值点
|
||
// var wetSeries = new LineSeries
|
||
// {
|
||
// Title = "湿膜流量 (Wet Flow)",
|
||
// Color = OxyColors.Blue,
|
||
// MarkerType = MarkerType.None,
|
||
// StrokeThickness = 1
|
||
// };
|
||
// var drySeries = new LineSeries
|
||
// {
|
||
// Title = "干膜流量 (Dry Flow)",
|
||
// Color = OxyColors.Red,
|
||
// MarkerType = MarkerType.None,
|
||
// StrokeThickness = 1
|
||
// };
|
||
// foreach (var dp in sorted)
|
||
// {
|
||
// if (dp.WetFlow > 0) wetSeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.WetFlow));
|
||
// if (dp.DryFlow > 0) drySeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.DryFlow));
|
||
// }
|
||
// if (wetSeries.Points.Count > 0) model.Series.Add(wetSeries);
|
||
// if (drySeries.Points.Count > 0) model.Series.Add(drySeries);
|
||
// }
|
||
|
||
|
||
// PlotModel = model;
|
||
//}
|
||
|
||
|
||
public void RefreshPlot()
|
||
{
|
||
UpdatePlot();
|
||
}
|
||
|
||
private void UpdatePlot()
|
||
{
|
||
// 确保在 UI 线程执行
|
||
if (Application.Current != null && !Application.Current.Dispatcher.CheckAccess())
|
||
{
|
||
Application.Current.Dispatcher.BeginInvoke((Action)UpdatePlot);
|
||
return;
|
||
}
|
||
|
||
var sorted = Record.DataPoints.OrderBy(p => p.Pressure).ToList();
|
||
//if (sorted.Count == 0)
|
||
//{
|
||
// PlotModel = null;
|
||
// return;
|
||
//}
|
||
|
||
var model = new PlotModel
|
||
{
|
||
Title = "流量-压力曲线",
|
||
TitleFontSize = 14,
|
||
TitleFontWeight = 1
|
||
};
|
||
|
||
model.Axes.Add(new LinearAxis
|
||
{
|
||
Position = AxisPosition.Bottom,
|
||
Title = "压力 (Pa)",
|
||
TitleFontSize = 12
|
||
});
|
||
model.Axes.Add(new LinearAxis
|
||
{
|
||
Position = AxisPosition.Left,
|
||
Title = "流量 (L/min)",
|
||
TitleFontSize = 12,
|
||
Minimum = 0,
|
||
MajorGridlineStyle = LineStyle.Solid,
|
||
MinorGridlineStyle = LineStyle.Dot
|
||
});
|
||
|
||
// 干膜半流量曲线(绿色虚线,每个压力点干膜流量的一半)
|
||
var halfDrySeries = new LineSeries
|
||
{
|
||
Title = "干膜半流量 (Half of Dry Flow)",
|
||
Color = OxyColors.Green,
|
||
MarkerType = MarkerType.None,
|
||
StrokeThickness = 1,
|
||
LineStyle = LineStyle.Dash
|
||
};
|
||
foreach (var dp in sorted.Where(p => p.DryFlow > 0))
|
||
{
|
||
halfDrySeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.DryFlow / 2.0));
|
||
}
|
||
|
||
// 根据当前模式绘制对应的曲线(只绘制流量 > 0 的点)
|
||
if (TestMode != null && TestMode.Contains("湿膜"))
|
||
{
|
||
var wetSeries = new LineSeries
|
||
{
|
||
Title = "湿膜流量 (Wet Flow)",
|
||
Color = OxyColors.Blue,
|
||
MarkerType = MarkerType.None,
|
||
StrokeThickness = 1
|
||
};
|
||
foreach (var dp in sorted.Where(p => p.WetFlow > 0))
|
||
wetSeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.WetFlow));
|
||
if (wetSeries.Points.Count > 0)
|
||
model.Series.Add(wetSeries);
|
||
// 湿膜模式下也显示半流量线(便于观察交点)
|
||
if (halfDrySeries.Points.Count > 0)
|
||
model.Series.Add(halfDrySeries);
|
||
}
|
||
else if (TestMode != null && TestMode.Contains("干膜"))
|
||
{
|
||
var drySeries = new LineSeries
|
||
{
|
||
Title = "干膜流量 (Dry Flow)",
|
||
Color = OxyColors.Red,
|
||
MarkerType = MarkerType.None,
|
||
StrokeThickness = 1
|
||
};
|
||
foreach (var dp in sorted.Where(p => p.DryFlow > 0))
|
||
drySeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.DryFlow));
|
||
if (drySeries.Points.Count > 0)
|
||
model.Series.Add(drySeries);
|
||
if (halfDrySeries.Points.Count > 0)
|
||
model.Series.Add(halfDrySeries);
|
||
}
|
||
else
|
||
{
|
||
// “全部”模式:同时显示两条曲线,但仍过滤掉 0 值点
|
||
var wetSeries = new LineSeries
|
||
{
|
||
Title = "湿膜流量 (Wet Flow)",
|
||
Color = OxyColors.Blue,
|
||
MarkerType = MarkerType.None,
|
||
StrokeThickness = 1
|
||
};
|
||
var drySeries = new LineSeries
|
||
{
|
||
Title = "干膜流量 (Dry Flow)",
|
||
Color = OxyColors.Red,
|
||
MarkerType = MarkerType.None,
|
||
StrokeThickness = 1
|
||
};
|
||
foreach (var dp in sorted)
|
||
{
|
||
if (dp.WetFlow > 0) wetSeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.WetFlow));
|
||
if (dp.DryFlow > 0) drySeries.Points.Add(new OxyPlot.DataPoint(dp.Pressure, dp.DryFlow));
|
||
}
|
||
if (wetSeries.Points.Count > 0) model.Series.Add(wetSeries);
|
||
if (drySeries.Points.Count > 0) model.Series.Add(drySeries);
|
||
if (halfDrySeries.Points.Count > 0) model.Series.Add(halfDrySeries);
|
||
}
|
||
|
||
PlotModel = model;
|
||
}
|
||
|
||
public ICommand ClearAllCommand { get; }
|
||
|
||
|
||
|
||
private double _currentFlow;
|
||
public double CurrentFlow
|
||
{
|
||
get => _currentFlow;
|
||
set => SetProperty(ref _currentFlow, value);
|
||
}
|
||
|
||
private double _currentPressure;
|
||
public double CurrentPressure
|
||
{
|
||
get => _currentPressure;
|
||
set => SetProperty(ref _currentPressure, value);
|
||
}
|
||
|
||
|
||
// 修改命令初始化(构造函数中)
|
||
|
||
|
||
// 实现删除方法
|
||
private void RemoveSelectedDataPoint()
|
||
{
|
||
if (SelectedDataPoint != null)
|
||
{
|
||
Record.DataPoints.Remove(SelectedDataPoint);
|
||
SelectedDataPoint = null; // 清除选中状态
|
||
UpdatePlot(); // 刷新曲线
|
||
}
|
||
}
|
||
|
||
|
||
public List<string> TestModes { get; } = new List<string> {"全部", "湿膜", "干膜" };
|
||
|
||
|
||
|
||
|
||
private double ConvertFlowByMode(double rawFlow)
|
||
{
|
||
// 如果当前选择的是小流量模式,则需要除以1000(因为PLC可能存储的是mL/min)
|
||
if (SelectedPressureMode != null && SelectedPressureMode.Text.Contains("小流量"))
|
||
return rawFlow / 1000.0;
|
||
else
|
||
return rawFlow;
|
||
}
|
||
|
||
}
|
||
} |