Files
ASTM-D7896-19TransientHot-W…/ViewModels/D7896ViewModel.cs
2026-04-18 19:00:34 +08:00

381 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using ASTM_D7896_Tester.Models;
using ASTM_D7896_Tester.Services;
using ASTM_D7896_Tester.Helpers;
using System.Linq;
using System.IO;
namespace ASTM_D7896_Tester.ViewModels;
public partial class D7896ViewModel : ObservableObject
{
private readonly IPlcCommunicationService _plcService;
private readonly ReportService _reportService;
private AppConfig _config;
public ObservableCollection<string> ReferenceLiquids { get; } = new ObservableCollection<string> { "蒸馏水", "甲苯", "乙二醇" };
// ========== 原有属性 ==========
[ObservableProperty]
private string _sampleId = "未命名样品";
[ObservableProperty]
private double _testTemperature = 25.0;
[ObservableProperty]
private string _testDateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
[ObservableProperty]
private bool _isTesting = false;
[ObservableProperty]
private string _statusMessage = "就绪";
[ObservableProperty]
private int _currentMeasurementIndex = 0;
[ObservableProperty]
private ObservableCollection<MeasurementResult> _measurements = new();
[ObservableProperty]
private double _averageThermalConductivity;
[ObservableProperty]
private double _averageThermalDiffusivity;
[ObservableProperty]
private double _averageVolumetricHeatCapacity;
// ========== 新增属性(补充缺失功能) ==========
// 章节7.5:样品量 (mL)
[ObservableProperty]
private double _sampleVolume = 40.0;
// 章节7.6:排气泡确认
[ObservableProperty]
private bool _bubbleRemoved = false;
// 附录A2加压测试
[ObservableProperty]
private bool _usePressure = false;
[ObservableProperty]
private double _pressureValue = 0.0; // kPa
// 章节7.1:清洁确认
[ObservableProperty]
private bool _isCleanConfirmed = false;
[ObservableProperty]
private string _cleanerName = "";
// 章节8.1:环境温度校准
[ObservableProperty]
private double _ambientTemperature = 25.0;
[ObservableProperty]
private bool _ambientCalibrated = false;
// 章节1.4:铂反应性确认
[ObservableProperty]
private bool _platinumCompatible = false;
[ObservableProperty]
private string _liquidReactivityNote = "";
// 系统校准模块章节A3相关
[ObservableProperty]
private bool _isCalibrating = false;
[ObservableProperty]
private string _calibrationStatus = "";
[ObservableProperty]
private string _selectedReferenceLiquid = "蒸馏水";
[ObservableProperty]
private double _referenceConductivity = 0.606;
[ObservableProperty]
private double _measuredConductivity = 0.0;
[ObservableProperty]
private double _calibrationErrorPercent = 0.0;
public D7896ViewModel()
{
_config = JsonConfigHelper.LoadConfig();
_plcService = new PlcCommunicationService();
_reportService = new ReportService(_config.TestParameters.ReportOutputPath);
// 加载配置中的默认值
SampleVolume = _config.TestParameters.DefaultSampleVolume;
UsePressure = _config.TestParameters.UsePressure;
PressureValue = _config.TestParameters.DefaultPressure;
SelectedReferenceLiquid = _config.TestParameters.ReferenceLiquid;
ReferenceConductivity = _config.TestParameters.ReferenceConductivity;
}
// ========== 原有命令 ==========
[RelayCommand]
private async Task StartTestAsync()
{
// 增加前置条件检查:清洁、气泡、铂兼容性、环境校准、样品量
if (!IsCleanConfirmed)
{
MessageBox.Show("请确认采样池已清洁干燥章节7.1)。", "前置条件未满足");
return;
}
if (!BubbleRemoved)
{
MessageBox.Show("请确认已清除铂丝表面气泡章节7.6)。", "前置条件未满足");
return;
}
if (!PlatinumCompatible)
{
MessageBox.Show("请确认所测液体不与铂发生反应章节1.4)。", "前置条件未满足");
return;
}
if (!AmbientCalibrated)
{
MessageBox.Show("请先进行环境温度校准章节8.1)。", "前置条件未满足");
return;
}
if (SampleVolume <= 0)
{
MessageBox.Show("请输入有效的样品量≥1 mL。", "参数错误");
return;
}
if (UsePressure && PressureValue <= 0)
{
MessageBox.Show("请设置有效的加压值(>0 kPa。", "参数错误");
return;
}
if (IsTesting)
{
MessageBox.Show("测试正在进行中,请稍后...", "提示");
return;
}
if (!await _plcService.IsConnectedAsync())
{
var connected = await _plcService.ConnectAsync();
if (!connected)
{
MessageBox.Show("无法连接到PLC请检查配置。", "错误");
return;
}
}
Measurements.Clear();
IsTesting = true;
StatusMessage = "开始测试...";
try
{
for (int i = 1; i <= _config.TestParameters.MeasurementCount; i++)
{
CurrentMeasurementIndex = i;
StatusMessage = $"正在执行第 {i} 次测量...";
await _plcService.WriteSingleCoilAsync(_config.PlcRegisterAddresses.StartCommand, true);
await Task.Delay(500);
await _plcService.WriteSingleCoilAsync(_config.PlcRegisterAddresses.StartCommand, false);
await Task.Delay(2000);
float lambda = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.ThermalConductivity);
float alpha = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.ThermalDiffusivity);
float temperature = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.TestTemperature);
if (i == 1) TestTemperature = temperature;
var result = new MeasurementResult
{
Index = i,
ThermalConductivity = lambda,
ThermalDiffusivity = alpha
};
result.CalculateVhc();
Application.Current.Dispatcher.Invoke(() =>
{
Measurements.Add(result);
});
StatusMessage = $"第 {i} 次测量完成,λ={lambda:F4} W/m·K";
if (i < _config.TestParameters.MeasurementCount)
{
await Task.Delay(_config.TestParameters.IntervalSeconds * 1000);
}
}
CalculateAverages();
StatusMessage = "测试完成。";
}
catch (Exception ex)
{
StatusMessage = $"测试出错: {ex.Message}";
MessageBox.Show($"测试过程中发生错误: {ex.Message}", "错误");
}
finally
{
IsTesting = false;
await _plcService.DisconnectAsync();
}
}
private void CalculateAverages()
{
if (Measurements.Count == 0) return;
AverageThermalConductivity = Measurements.Average(m => m.ThermalConductivity);
AverageThermalDiffusivity = Measurements.Average(m => m.ThermalDiffusivity);
AverageVolumetricHeatCapacity = Measurements.Average(m => m.VolumetricHeatCapacity);
}
[RelayCommand]
private void Reset()
{
Measurements.Clear();
AverageThermalConductivity = 0;
AverageThermalDiffusivity = 0;
AverageVolumetricHeatCapacity = 0;
CurrentMeasurementIndex = 0;
StatusMessage = "已重置";
TestDateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// 重置确认标志(可根据需要决定是否重置)
// IsCleanConfirmed = false;
// BubbleRemoved = false;
// PlatinumCompatible = false;
// AmbientCalibrated = false;
}
[RelayCommand]
private async Task GenerateReportAsync()
{
if (Measurements.Count == 0)
{
MessageBox.Show("没有测试数据,请先执行测试。", "提示");
return;
}
try
{
// 收集所有额外参数用于报告
var extraParams = new Dictionary<string, object>
{
["SampleVolume"] = SampleVolume,
["BubbleRemoved"] = BubbleRemoved,
["UsePressure"] = UsePressure,
["PressureValue"] = PressureValue,
["IsCleanConfirmed"] = IsCleanConfirmed,
["CleanerName"] = CleanerName,
["AmbientTemperature"] = AmbientTemperature,
["AmbientCalibrated"] = AmbientCalibrated,
["PlatinumCompatible"] = PlatinumCompatible,
["LiquidReactivityNote"] = LiquidReactivityNote
};
string reportPath = await _reportService.GenerateReportAsync(
SampleId,
TestTemperature,
Measurements.ToList(),
AverageThermalConductivity,
AverageThermalDiffusivity,
AverageVolumetricHeatCapacity,
_config.TestParameters,
extraParams
);
MessageBox.Show($"报告已生成:{reportPath}", "成功");
}
catch (Exception ex)
{
MessageBox.Show($"生成报告失败:{ex.Message}", "错误");
}
}
// ========== 新增命令:排气泡确认 ==========
[RelayCommand]
private void ConfirmBubbleRemoved()
{
BubbleRemoved = true;
StatusMessage = "已确认清除气泡。";
}
// ========== 新增命令:清洁确认 ==========
[RelayCommand]
private void ConfirmClean()
{
if (string.IsNullOrWhiteSpace(CleanerName))
{
MessageBox.Show("请输入清洁人员姓名。", "提示");
return;
}
IsCleanConfirmed = true;
StatusMessage = "已确认采样池清洁干燥。";
}
// ========== 新增命令:铂兼容性确认 ==========
[RelayCommand]
private void ConfirmPlatinumCompatible()
{
PlatinumCompatible = true;
StatusMessage = "已确认液体与铂兼容。";
}
// ========== 新增命令:环境温度校准 ==========
[RelayCommand]
private async Task CalibrateAmbientAsync()
{
if (!await _plcService.IsConnectedAsync())
{
await _plcService.ConnectAsync();
}
// 读取PLC当前环境温度假设寄存器地址可配置
// 这里简化让用户手动输入或从PLC读取
// 为了演示从PLC读取温度
float temp = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.TestTemperature);
AmbientTemperature = temp;
AmbientCalibrated = true;
StatusMessage = $"环境温度校准完成:{AmbientTemperature:F1} °C";
}
// ========== 新增命令系统校准章节A3 ==========
[RelayCommand]
private async Task PerformSystemCalibrationAsync()
{
if (IsCalibrating)
{
MessageBox.Show("校准正在进行中...", "提示");
return;
}
var result = MessageBox.Show($"将使用参考液 [{SelectedReferenceLiquid}] 进行系统校准。\n请确保传感器已浸入参考液中并已清除气泡。\n是否继续", "系统校准", MessageBoxButton.YesNo);
if (result != MessageBoxResult.Yes) return;
IsCalibrating = true;
CalibrationStatus = "正在测量参考液...";
try
{
// 执行一次测量
if (!await _plcService.IsConnectedAsync())
await _plcService.ConnectAsync();
await _plcService.WriteSingleCoilAsync(_config.PlcRegisterAddresses.StartCommand, true);
await Task.Delay(500);
await _plcService.WriteSingleCoilAsync(_config.PlcRegisterAddresses.StartCommand, false);
await Task.Delay(2000);
float lambda = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.ThermalConductivity);
MeasuredConductivity = lambda;
CalibrationErrorPercent = Math.Abs((lambda - ReferenceConductivity) / ReferenceConductivity * 100);
CalibrationStatus = $"测量值: {MeasuredConductivity:F4} W/m·K, 参考值: {ReferenceConductivity:F4} W/m·K, 误差: {CalibrationErrorPercent:F2}%";
if (CalibrationErrorPercent <= 2.0)
MessageBox.Show($"校准成功!误差 {CalibrationErrorPercent:F2}% 在允许范围内≤2%)。", "校准结果");
else
MessageBox.Show($"校准警告:误差 {CalibrationErrorPercent:F2}% 超出2%限值,请检查传感器或参考液。", "校准结果", MessageBoxButton.OK, MessageBoxImage.Warning);
}
catch (Exception ex)
{
CalibrationStatus = $"校准失败: {ex.Message}";
MessageBox.Show($"校准失败: {ex.Message}", "错误");
}
finally
{
IsCalibrating = false;
}
}
}