@@ -8,7 +8,6 @@ using OxyPlot.Axes;
using OxyPlot.Series ;
using System ;
using System.Collections.ObjectModel ;
using System.IO ;
using System.Linq ;
using System.Threading.Tasks ;
using System.Windows ;
@@ -21,146 +20,107 @@ public partial class D7896ViewModel : ObservableObject
private AppConfig _config ;
private readonly ReportService _reportService ;
public ObservableCollection < string > ReferenceLiquids { get ; } = new ( ) { "蒸馏水" , "甲苯" , "乙二醇" } ;
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 ;
// ========== 原有属性 ==========
[ObservableProperty]
private string _sampleId = "未命名样品" ;
[ObservableProperty]
private double _testTemperatur e = 25 .0;
[ObservableProperty]
private string _testDateTime = DateTime . Now . ToString ( "yyyy-MM-dd HH:mm:ss" ) ;
[ObservableProperty]
private bool _isTesting = fals e;
[ObservableProperty]
private string _statusMessag e = "就绪 " ;
[ObservableProperty]
private int _currentMeasurementIndex = 0 ;
[ObservableProperty]
private ObservableCollection < MeasurementResult > _measurements = new ( ) ;
[ObservableProperty]
private double _averageThermalConductivity ;
[ObservableProperty]
private double _averageThermalDiffusivity ;
[ObservableProperty]
private double _averageVolumetricHeatCapacity ;
// 测试条件
[ObservableProperty] private double _sampleVolume = 40.0 ;
[ObservableProperty] private bool _bubbleRemoved = true ;
[ObservableProperty] private bool _usePressure = false ;
[ObservableProperty] private double _pressureValu e = 0 .0;
[ObservableProperty] private bool _isCleanConfirmed = true ;
[ObservableProperty] private string _cleanerName = "" ;
[ObservableProperty] private double _ambientTemperature = 25.0 ;
[ObservableProperty] private bool _ambientCalibrated = tru e;
[ObservableProperty] private bool _platinumCompatible = true ;
[ObservableProperty] private string _liquidReactivityNot e = "" ;
// ========== 新增属性(补充缺失功能) ==========
// 章节7.5:样品量 (mL)
[ObservableProperty]
private double _sampleVolume = 40.0 ;
// 系统校准
[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 ;
// 章节7.6:排气泡确认
[ObservableProperty]
private bool _bubbleRemoved = false ;
// 实时核心参数( 直接从PLC读取)
[ObservableProperty] private double _platinumVoltage ; // 铂丝电压 U_pt (V)
[ObservableProperty] private double _standardResistorVoltage ; // 标准电阻电压 (V)
[ObservableProperty] private double _platinumResistance ; // 铂丝电阻 (Ω)
[ObservableProperty] private double _chamberPressure ; // 样品池压力 (kPa)
// 附录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 ;
// 新增核心参数(实时显示)
[ObservableProperty]
private double _platinumVoltage ; // 铂丝电压 U_pt (V)
[ObservableProperty]
private double _standardResistorVoltage ; // 标准电阻电压 U_std (V)
[ObservableProperty]
private double _platinumResistance ; // 铂丝电阻 R_pt (Ω)
[ObservableProperty]
private double _chamberPressure ; // 样品池压力 (kPa)
// 当前曲线标题
[ObservableProperty]
private string _curveTitle = "温升曲线" ;
// 在 ViewModel 中
[ObservableProperty]
private PlotModel _temperatureCurveModel ;
// 温升曲线
[ObservableProperty] private string _curveTitle = "温升曲线" ;
[ObservableProperty] private PlotModel _temperatureCurveModel ;
public D7896ViewModel ( )
{
// 获取应用全局配置并确保不为 null
_config = ASTM_D7896_Tester . App . PlcConfig ? ? new Models . AppConfig ( ) ;
_plcService = ASTM_D7896_Tester . App . PlcService ;
_config = App . PlcConfig ? ? new AppConfig ( ) ;
_plcService = App . PlcService ;
_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 ;
// 默认确认项为 true( 避免每次手动勾选)
IsCleanConfirmed = true ;
BubbleRemoved = true ;
PlatinumCompatible = true ;
AmbientCalibrated = true ;
}
// ========== 原有命令 ==========
// ======================= 实时数据更新 ============= ==========
private async Task UpdateRealTimeParametersAsync ( )
{
if ( ! await _plcService . IsConnectedAsync ( ) )
return ;
try
{
// 读取温度( D1376, 假设为0.1℃单位,转换为℃)
float rawTemp = await _plcService . ReadFloatAsync ( _config . PlcRegisterAddresses . Temperature ) ;
TestTemperature = rawTemp / 10.0 ;
// 读取压力( D1322, 假设为0.1kPa单位)
float rawPressure = await _plcService . ReadFloatAsync ( _config . PlcRegisterAddresses . Pressure ) ;
ChamberPressure = rawPressure / 10.0 ;
// 读取铂丝电阻( D1422, 假设为0.001Ω单位)
float rawResistance = await _plcService . ReadFloatAsync ( _config . PlcRegisterAddresses . Resistance ) ;
PlatinumResistance = rawResistance / 1000.0 ;
// 注意:铂丝电压和标准电阻电压可能需要从其他寄存器读取,如果没有则不更新
// 如有对应寄存器请添加
}
catch ( Exception ex )
{
StatusMessage = $"实时参数读取失败: {ex.Message}" ;
}
}
// ======================= 核心测试流程 =======================
[RelayCommand]
private async Task StartTestAsync ( )
{
// 增加前置条件检查:清洁、气泡、铂兼容性、环境校准、样品量
if ( ! IsCleanConfirmed )
// 前置检查
if ( ! IsCleanConfirmed | | ! BubbleRemoved | | ! PlatinumCompatible | | ! AmbientCalibrated )
{
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)。" , "前置条件未满足" ) ;
MessageBox . Show ( "请完成所有测试前确认项(清洁、排泡、铂兼容性、环境校准 )。" , "前置条件未满足" ) ;
return ;
}
if ( SampleVolume < = 0 )
@@ -190,6 +150,17 @@ public partial class D7896ViewModel : ObservableObject
}
}
// 如果需要加压,开启进气阀并等待压力稳定
if ( UsePressure )
{
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . InletValveCoil , true ) ;
await Task . Delay ( 2000 ) ; // 等待加压
// 实时读取压力并显示
await UpdateRealTimeParametersAsync ( ) ;
if ( ChamberPressure < PressureValue - 5 )
MessageBox . Show ( $"压力未达到设定值 {PressureValue} kPa, 当前 {ChamberPressure:F1} kPa" , "警告" ) ;
}
Measurements . Clear ( ) ;
IsTesting = true ;
StatusMessage = "开始测试..." ;
@@ -201,18 +172,24 @@ public partial class D7896ViewModel : ObservableObject
CurrentMeasurementIndex = i ;
StatusMessage = $"正在执行第 {i} 次测量..." ;
// 启动单次测量( 触发PLC内的加热脉冲)
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . StartCommand , true ) ;
await Task . Delay ( 500 ) ;
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . StartCommand , false ) ;
// 等待测量完成( PLC计算需要时间)
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 ;
GenerateTemperatureCurve ( lambda , alpha ) ; // 更新曲线图
// 实时更新温度、压力、电阻
await UpdateRealTimeParametersAsync ( ) ;
// 生成温升曲线( 根据实际λ和α , 如果用真实U_pt数据需额外采集)
GenerateTemperatureCurve ( lambda , alpha ) ;
var result = new MeasurementResult
{
Index = i ,
@@ -221,20 +198,13 @@ public partial class D7896ViewModel : ObservableObject
} ;
result . CalculateVhc ( ) ;
Application . Current . Dispatcher . Invoke ( ( ) = >
{
Measurements . Add ( result ) ;
} ) ;
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 = "测试完成。" ;
}
@@ -245,87 +215,55 @@ public partial class D7896ViewModel : ObservableObject
}
finally
{
// 测试结束,关闭进气阀,打开排气阀泄压
if ( UsePressure )
{
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . InletValveCoil , false ) ;
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . OutletValveCoil , true ) ;
await Task . Delay ( 1000 ) ;
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . OutletValveCoil , false ) ;
}
IsTesting = false ;
await _plcService . DisconnectAsync ( ) ;
}
}
// 模拟获取实时核心参数( 实际应从PLC读取)
private async Task UpdateRealTimeParametersAsync ( )
{
if ( await _plcService . IsConnectedAsync ( ) )
{
// 示例: 从PLC读取这些值( 地址需在配置文件中定义)
PlatinumVoltage = await _plcService . ReadFloatAsync ( 40010 ) ; // 假设地址
StandardResistorVoltage = await _plcService . ReadFloatAsync ( 40012 ) ;
PlatinumResistance = await _plcService . ReadFloatAsync ( 40014 ) ;
ChamberPressure = await _plcService . ReadFloatAsync ( 40016 ) ;
}
}
// ======================= 温升曲线( 真实数据需要U_pt时间序列, 此处暂用理论公式) =======================
private void GenerateTemperatureCurve ( float lambda , float alpha )
{
// 第一次调用时初始化 PlotModel( 只创建一次)
if ( TemperatureCurveModel = = null )
{
TemperatureCurveModel = new PlotModel
{
Title = "温升曲线对比 (10次测量)" ,
Background = OxyColors . White
} ;
// 添加坐标轴(只添加一次)
TemperatureCurveModel . Axes . Add ( new LinearAxis
{
Position = AxisPosition . Bottom ,
Title = "时间 (s)" ,
Minimum = 0 ,
Maximum = 2
} ) ;
TemperatureCurveModel . Axes . Add ( new LinearAxis
{
Position = AxisPosition . Left ,
Title = "温升 (℃)" ,
Minimum = 0
} ) ;
TemperatureCurveModel = new PlotModel { Title = "温升曲线对比" , Background = OxyColors . White } ;
TemperatureCurveModel . Axes . Add ( new LinearAxis { Position = AxisPosition . Bottom , Title = "时间 (s)" , Minimum = 0 , Maximum = 2 } ) ;
TemperatureCurveModel . Axes . Add ( new LinearAxis { Position = AxisPosition . Left , Title = "温升 (℃)" , Minimum = 0 } ) ;
}
// 创建本次测量的曲线系列(用不同颜色区分)
var series = new LineSeries
{
Title = $"第{CurrentMeasurementIndex}次测量" ,
Color = GetColorForIndex ( CurrentMeasurementIndex ) ,
StrokeThickness = 1.5 ,
MarkerType = MarkerType . None
StrokeThickness = 1.5
} ;
// 添加数据点(这里仍用模拟数据,实际应替换为真实采集数据)
// 理论公式: ΔT = (Q/(4πλL)) * ln(t/t0) + C
// 其中 Q 是加热功率, L 是铂丝长度, C 是常数
double Q = 0.01 ; // 假设 10mW, 实际应从电流和电阻计算
double L = 0.04 ; // 40mm
// 理论公式 ΔT = (Q/(4πλL)) * ln(t/t0) + C, Q = I²R
// 实际应用时应根据采集的铂丝电压 U_pt(t) 计算温升
double Q = 0.01 ; // 示例值,应从实际电流和电阻计算
double L = _config . TestParameters . PlatinumWireLength ;
double constant = 0.2 ;
for ( int i = 0 ; i < = 200 ; i + + )
for ( int i = 1 ; i < = 200 ; i + + )
{
double t = i * 0.01 ;
double deltaT = ( Q / ( 4 * Math . PI * lambda * L ) ) * Math . Log ( t + 0.1 ) + constant ;
series . Points . Add ( new DataPoint ( t , deltaT ) ) ;
}
// 将本次曲线添加到同一个 Model 中(叠加)
TemperatureCurveModel . Series . Add ( series ) ;
TemperatureCurveModel . InvalidatePlot ( true ) ;
CurveTitle = $"已完成 {CurrentMeasurementIndex} 次测量" ;
}
// 辅助方法:根据测量序号返回不同的颜色
private OxyColor GetColorForIndex ( int index )
{
var colors = new [ ]
{
OxyColors . Red , OxyColors . Blue , OxyColors . Green , OxyColors . Orange ,
OxyColors . Purple , OxyColors . Brown , OxyColors . Pink , OxyColors . Cyan ,
OxyColors . Magenta , OxyColors . Olive
} ;
var colors = new [ ] { OxyColors . Red , OxyColors . Blue , OxyColors . Green , OxyColors . Orange , OxyColors . Purple , OxyColors . Brown , OxyColors . Pink , OxyColors . Cyan , OxyColors . Magenta , OxyColors . Olive } ;
return colors [ ( index - 1 ) % colors . Length ] ;
}
@@ -341,15 +279,11 @@ public partial class D7896ViewModel : ObservableObject
private void Reset ( )
{
Measurements . Clear ( ) ;
AverageThermalConductivity = 0 ;
AverageThermalDiffusivity = 0 ;
AverageVolumetricHeatCapacity = 0 ;
AverageThermalConductivity = AverageThermalDiffusivity = AverageVolumetricHeatCapacity = 0 ;
CurrentMeasurementIndex = 0 ;
StatusMessage = "已重置" ;
TestDateTime = DateTime . Now . ToString ( "yyyy-MM-dd HH:mm:ss" ) ;
TemperatureCurveModel = null ; // 下次测量会重新初始化
// 重置确认标志(可根据需要决定是否重置)
TemperatureCurveModel = null ;
}
[RelayCommand]
@@ -360,10 +294,8 @@ public partial class D7896ViewModel : ObservableObject
MessageBox . Show ( "没有测试数据,请先执行测试。" , "提示" ) ;
return ;
}
try
{
// 收集所有额外参数用于报告
var extraParams = new Dictionary < string , object >
{
["SampleVolume"] = SampleVolume ,
@@ -377,17 +309,9 @@ public partial class D7896ViewModel : ObservableObject
["PlatinumCompatible"] = PlatinumCompatible ,
["LiquidReactivityNote"] = LiquidReactivityNote
} ;
string reportPath = await _reportService . GenerateReportAsync (
SampleId ,
TestTemperature ,
Measurements . ToList ( ) ,
AverageThermalConductivity ,
AverageThermalDiffusivity ,
AverageVolumetricHeatCapacity ,
_config . TestParameters ,
extraParams
) ;
string reportPath = await _reportService . GenerateReportAsync ( SampleId , TestTemperature , Measurements . ToList ( ) ,
AverageThermalConductivity , AverageThermalDiffusivity , AverageVolumetricHeatCapacity ,
_config . TestParameters , extraParams ) ;
MessageBox . Show ( $"报告已生成:{reportPath}" , "成功" ) ;
}
catch ( Exception ex )
@@ -396,15 +320,53 @@ public partial class D7896ViewModel : ObservableObject
}
}
// ========== 新增命令:排气泡确认 ==========
// ======================= 新增控制命令 ============= ==========
[RelayCommand]
private void ConfirmBubbleRemoved ( )
private async Task PressureCalibrationAsync ( )
{
BubbleRemoved = true ;
StatusMessage = "已确认清除气泡。" ;
await EnsureConnected ( ) ;
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . PressureCalibrationCoil , true ) ;
await Task . Delay ( 500 ) ;
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . PressureCalibrationCoil , false ) ;
StatusMessage = "压力校准指令已发送" ;
}
// ========== 新增命令:清洁确认 ==========
[RelayCommand]
private async Task ResistanceZeroAsync ( )
{
await EnsureConnected ( ) ;
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . ResistanceZeroCoil , true ) ;
await Task . Delay ( 500 ) ;
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . ResistanceZeroCoil , false ) ;
StatusMessage = "电阻归零指令已发送" ;
}
[RelayCommand]
private async Task InletValveControlAsync ( )
{
await EnsureConnected ( ) ;
bool current = await _plcService . ReadCoilAsync ( _config . PlcRegisterAddresses . InletValveCoil ) ;
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . InletValveCoil , ! current ) ;
StatusMessage = $"进气阀 {(current ? " 关 闭 " : " 开 启 ")}" ;
}
[RelayCommand]
private async Task OutletValveControlAsync ( )
{
await EnsureConnected ( ) ;
bool current = await _plcService . ReadCoilAsync ( _config . PlcRegisterAddresses . OutletValveCoil ) ;
await _plcService . WriteCoilAsync ( _config . PlcRegisterAddresses . OutletValveCoil , ! current ) ;
StatusMessage = $"排气阀 {(current ? " 关 闭 " : " 开 启 ")}" ;
}
private async Task EnsureConnected ( )
{
if ( ! await _plcService . IsConnectedAsync ( ) )
await _plcService . ConnectAsync ( ) ;
}
// 以下原有的 Confirm 命令保持不变,但可根据需要简化(因默认已勾选)
[RelayCommand] private void ConfirmBubbleRemoved ( ) = > BubbleRemoved = true ;
[RelayCommand]
private void ConfirmClean ( )
{
@@ -414,34 +376,17 @@ public partial class D7896ViewModel : ObservableObject
return ;
}
IsCleanConfirmed = true ;
StatusMessage = "已确认采样池清洁干燥。" ;
}
// ========== 新增命令:铂兼容性确认 ==========
[RelayCommand]
private void ConfirmPlatinumCompatible ( )
{
PlatinumCompatible = true ;
StatusMessage = "已确认液体与铂兼容。" ;
}
// ========== 新增命令:环境温度校准 ==========
[RelayCommand] private void ConfirmPlatinumCompatible ( ) = > PlatinumCompatible = true ;
[RelayCommand]
private async Task CalibrateAmbientAsync ( )
{
if ( ! await _plcService . Is ConnectedAsync ( ) )
{
await _plcService . ConnectAsync ( ) ;
}
// 读取PLC当前环境温度( 假设寄存器地址可配置)
// 这里简化: 让用户手动输入或从PLC读取
// 为了演示, 从PLC读取温度
float temp = await _plcService . ReadFloatAsync ( _config . PlcRegisterAddresses . TestTemperature ) ;
await Ensure Connected( ) ;
float temp = await _plcService . ReadFloatAsync ( _config . PlcRegisterAddresses . Temperature ) ;
AmbientTemperature = temp ;
AmbientCalibrated = true ;
StatusMessage = $"环境温度校准完成:{AmbientTemperature:F1} °C" ;
}
// ========== 新增命令: 系统校准( 章节A3) ==========
[RelayCommand]
private async Task PerformSystemCalibrationAsync ( )
@@ -494,9 +439,4 @@ public partial class D7896ViewModel : ObservableObject
}
}