This commit is contained in:
xyy
2026-05-27 14:04:14 +08:00
parent 5bbbddf509
commit 8332fa0531
4 changed files with 187 additions and 89 deletions

View File

@@ -52,6 +52,11 @@ public partial class ConfigViewModel : ObservableObject
}
}
//public IAsyncRelayCommand SaveCommand => new AsyncRelayCommand(Save);
[RelayCommand]
private async Task Save()
{

View File

@@ -141,16 +141,16 @@ public partial class D7896ViewModel : ObservableObject
catch { }
}
private async Task<double> GetInitialResistanceAsync()
{
if (!await _plcService.IsConnectedAsync()) return 0;
try
{
float rawResistance = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Resistance);
return rawResistance;
}
catch { return 0; }
}
//private async Task<double> GetInitialResistanceAsync()
//{
// if (!await _plcService.IsConnectedAsync()) return 0;
// try
// {
// float rawResistance = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Resistance);
// return rawResistance;
// }
// catch { return 0; }
//}
[RelayCommand]
private async Task StartTestAsync()
@@ -194,7 +194,7 @@ public partial class D7896ViewModel : ObservableObject
await _th1963Ustd.ConnectAsync("192.168.1.12", 45454); // 改为实际IP
await _th1963Ustd.ConfigureForHighSpeedDcvAsync();
await _th1953Ustd.ConnectAsync("192.168.1.12", 45454); // 改为实际IP
await _th1953Ustd.ConnectAsync("192.168.1.13", 45454); // 改为实际IP
await _th1953Ustd.ConfigureForHighSpeedDcvAsync();
}
catch (Exception ex)
@@ -207,15 +207,39 @@ public partial class D7896ViewModel : ObservableObject
{
StatusMessage = "正在加压...";
await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.InletValveCoil, true);
await Task.Delay(3000);
await UpdateRealTimeParametersAsync();
if (ChamberPressure < PressureValue - 5)
MessageBox.Show($"压力未达到设定值 {PressureValue} kPa", "警告");
const int pressureStableTimeoutMs = 10000; // 30秒超时
const double pressureTolerance = 5.0; // 允许误差 ±5 kPa
var startTime = DateTime.Now;
bool pressureReached = false;
while ((DateTime.Now - startTime).TotalMilliseconds < pressureStableTimeoutMs)
{
await Task.Delay(500); // 每0.5秒检测一次
await UpdateRealTimeParametersAsync();
if (ChamberPressure >= PressureValue - pressureTolerance)
{
pressureReached = true;
break;
}
}
if (!pressureReached)
{
// 加压失败,关闭进气阀,中止测试
await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.InletValveCoil, false);
MessageBox.Show($"加压超时,压力未能达到 {PressureValue} kPa当前 {ChamberPressure:F1} kPa", "错误");
return;
}
// 压力已达到,可关闭进气阀(或保持,看系统需求)
await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.InletValveCoil, false);
StatusMessage = $"压力已稳定在 {ChamberPressure:F1} kPa";
}
double initialResistance = await GetInitialResistanceAsync();
if (initialResistance > 0)
StatusMessage = $"初始电阻: {initialResistance:F4} Ω";
//double initialResistance = await GetInitialResistanceAsync();
//if (initialResistance > 0)
// StatusMessage = $"初始电阻: {initialResistance:F4} Ω";
Measurements.Clear();
IsTesting = true;
@@ -248,12 +272,7 @@ public partial class D7896ViewModel : ObservableObject
StatusMessage = $"正在执行第 {i} 次测量...";
// 准备批量采集参数每通道采样点数采样率1000点/秒加热时间1秒 -> 1000点
int samples = 800; // 1秒 * 1000点/秒
int samples = 200; // 1秒 * 1000点/秒
// 预配置两台表:进入等待触发状态
await _th1963Ustd.PrepareBatchAsync(samples);
@@ -262,24 +281,33 @@ public partial class D7896ViewModel : ObservableObject
// 启动加热脉冲 (PLC)
await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.StartCommand, true);
// 等待极短时间确保电流稳定(如 5ms
await Task.Delay(5);
try { await Task.Delay(5, _testCts.Token); } catch (OperationCanceledException) { break; }
// 同时发送触发信号给两台电压表
await Task.WhenAll(_th1963Ustd.TriggerAsync(), _th1953Ustd.TriggerAsync());
// 等待加热结束
await Task.Delay((int)(heatingDuration * 1000));
try { await Task.Delay((int)(heatingDuration * 1000), _testCts.Token); } catch (OperationCanceledException) { break; }
// 停止加热
await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.StartCommand, false);
// 等待采集完成(剩余时间)
int remainingMs = (int)((totalDuration - heatingDuration) * 1000) + 100;
await Task.Delay(remainingMs);
try { await Task.Delay(remainingMs, _testCts.Token); } catch (OperationCanceledException) { break; }
// 获取采集数据
double[] ustd = await _th1963Ustd.FetchBatchAsync();
double[] upt = await _th1953Ustd.FetchBatchAsync();
for (int j = 0; j < 20; j++)
{
Logger.Log($"第{j}点: U_std={ustd[j]:F6} V, U_pt={upt[j]:F6} V");
}
StandardResistorVoltage = ustd.Average();
PlatinumVoltage = upt.Average();
@@ -292,9 +320,23 @@ public partial class D7896ViewModel : ObservableObject
{
timeArray[idx] = idx * totalDuration / samples;
}
// 计算本次测量的 λ 和 α
var (lambda, alpha, deltaT, coolingPoints) = ComputeThermalProperties(upt, ustd, timeArray, initialResistance, CurrentTestTemperature);
// 动态计算初始电阻 R0取前 10 个点的平均值,这期间温升很小)
int warmupPoints = Math.Min(10, ustd.Length);
double sumR0 = 0;
for (int j = 0; j < warmupPoints; j++)
{
double current = ustd[j] / StandardResistor;
double resistance = upt[j] / current;
sumR0 += resistance;
}
double dynamicR0 = sumR0 / warmupPoints;
Logger.Log($"动态计算 R0 = {dynamicR0:F6} Ω");
// 计算本次测量的 λ 和 α
var (lambda, alpha, deltaT, coolingPoints) = ComputeThermalProperties(upt, ustd, timeArray, dynamicR0, CurrentTestTemperature);
// 添加结果日志
Logger.Log($"测量 {i} 结果: λ={lambda:F6} W/(m·K), α={alpha:E6} m²/s");
@@ -318,14 +360,16 @@ public partial class D7896ViewModel : ObservableObject
Logger.Log($"热扩散率 α: {alpha:E6} m²/s");
Logger.Log($"体积热容 VHC: {result.VolumetricHeatCapacity:F2} kJ/(m³·K)");
Logger.Log($"比热容 Cp: {result.SpecificHeatCapacity:F2} J/(kg·K) (密度 = {SampleDensity:F1} kg/m³)");
Logger.Log($"初始电阻 R0: {initialResistance:F6} Ω");
Logger.Log($"初始电阻 R0: {dynamicR0:F6} Ω");
Logger.Log($"测试温度: {CurrentTestTemperature:F2} °C");
Logger.Log($"铂丝平均电阻: {PlatinumResistance:F6} Ω");
Logger.Log($"样品池压力: {ChamberPressure:F2} kPa");
Logger.Log("===========================================");
if (i < _config.TestParameters.MeasurementCount && !_stopRequested)
await Task.Delay(_config.TestParameters.IntervalSeconds * 1000);
{
try { await Task.Delay(_config.TestParameters.IntervalSeconds * 1000, _testCts.Token); } catch (OperationCanceledException) { break; }
}
}
CalculateAverages();
@@ -552,47 +596,47 @@ public partial class D7896ViewModel : ObservableObject
return timeArray.Length - 1;
}
/// <summary>
/// 最小二乘法拟合斜率 (X轴为横坐标Y轴为纵坐标) — 用于加热段 ln(t) vs ΔT
/// </summary>
private double LeastSquaresSlope(List<DataPoint> points)
{
if (points.Count < 2) return 0.001;
double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
foreach (var p in points)
{
sumX += p.X;
sumY += p.Y;
sumXY += p.X * p.Y;
sumX2 += p.X * p.X;
}
double n = points.Count;
double denominator = n * sumX2 - sumX * sumX;
if (Math.Abs(denominator) < 1e-10) return 0.001;
double slope = (n * sumXY - sumX * sumY) / denominator;
return slope;
}
///// <summary>
///// 最小二乘法拟合斜率 (X轴为横坐标Y轴为纵坐标) — 用于加热段 ln(t) vs ΔT
///// </summary>
//private double LeastSquaresSlope(List<DataPoint> points)
//{
// if (points.Count < 2) return 0.001;
// double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
// foreach (var p in points)
// {
// sumX += p.X;
// sumY += p.Y;
// sumXY += p.X * p.Y;
// sumX2 += p.X * p.X;
// }
// double n = points.Count;
// double denominator = n * sumX2 - sumX * sumX;
// if (Math.Abs(denominator) < 1e-10) return 0.001;
// double slope = (n * sumXY - sumX * sumY) / denominator;
// return slope;
//}
/// <summary>
/// 最小二乘法拟合斜率 (X轴为时间tY轴为 ln(ΔT)) — 用于冷却段
/// </summary>
private double LeastSquaresSlopeOnTime(List<DataPoint> points)
{
if (points.Count < 2) return -1.0;
double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
foreach (var p in points)
{
sumX += p.X;
sumY += p.Y;
sumXY += p.X * p.Y;
sumX2 += p.X * p.X;
}
double n = points.Count;
double denominator = n * sumX2 - sumX * sumX;
if (Math.Abs(denominator) < 1e-10) return -1.0;
double slope = (n * sumXY - sumX * sumY) / denominator;
return slope;
}
///// <summary>
///// 最小二乘法拟合斜率 (X轴为时间tY轴为 ln(ΔT)) — 用于冷却段
///// </summary>
//private double LeastSquaresSlopeOnTime(List<DataPoint> points)
//{
// if (points.Count < 2) return -1.0;
// double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
// foreach (var p in points)
// {
// sumX += p.X;
// sumY += p.Y;
// sumXY += p.X * p.Y;
// sumX2 += p.X * p.X;
// }
// double n = points.Count;
// double denominator = n * sumX2 - sumX * sumX;
// if (Math.Abs(denominator) < 1e-10) return -1.0;
// double slope = (n * sumXY - sumX * sumY) / denominator;
// return slope;
//}
private void GenerateTemperatureCurveFromData(double[] time, double[] deltaT, List<DataPoint> coolingPoints)
{
@@ -692,16 +736,14 @@ public partial class D7896ViewModel : ObservableObject
}
}
[RelayCommand]
private async Task StopTestCommandAsync()
private async Task StopTest()
{
if (!IsTesting)
{
MessageBox.Show("没有正在进行的测试", "提示");
return;
}
if (!IsTesting) return;
_stopRequested = true;
_testCts?.Cancel();
_testCts?.Cancel(); // 取消所有等待的 Delay
StatusMessage = "正在停止测试...";
await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.StartCommand, false);
if (UsePressure)
@@ -714,7 +756,6 @@ public partial class D7896ViewModel : ObservableObject
IsTesting = false;
StatusMessage = "测试已停止。";
}
[RelayCommand] private async Task PressureCalibrationAsync() => await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.PressureCalibrationCoil, true);
[RelayCommand] private async Task ResistanceZeroAsync() => await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.ResistanceZeroCoil, true);
[RelayCommand]

View File

@@ -1,7 +1,7 @@
<Window x:Class="ASTM_D7896_Tester.Views.ConfigWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="高级参数配置" Height="300" Width="400"
Title="高级参数配置" Height="300" Width="450"
WindowStartupLocation="CenterOwner">
<Grid Margin="20">
<Grid.RowDefinitions>
@@ -37,7 +37,7 @@
</StackPanel>
<StackPanel Grid.Row="5" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,20,0,0">
<Button Content="保存并关闭" Command="{Binding SaveAndCloseCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}" Width="100" Margin="5"/>
<Button Content="保存并关闭" Command="{Binding SaveCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}" Width="100" Margin="5"/>
<Button Content="取消" Click="CancelButton_Click" Width="100" Margin="5"/>
</StackPanel>
</Grid>

View File

@@ -214,15 +214,67 @@
<!-- 5. 测量数据表格(占用剩余高度) -->
<Border Grid.Row="4" Background="White" CornerRadius="6" Padding="8" Margin="0,5" Effect="{StaticResource CardShadow}">
<DataGrid ItemsSource="{Binding Measurements}" AutoGenerateColumns="False"
<DataGrid ItemsSource="{Binding Measurements}" AutoGenerateColumns="False" HorizontalAlignment="Center" VerticalAlignment="Center"
CanUserAddRows="False" IsReadOnly="True"
HeadersVisibility="Column" GridLinesVisibility="Horizontal"
RowHeight="28" MinHeight="150">
<DataGrid.Columns>
<DataGridTextColumn Header="序号" Binding="{Binding Index}" Width="60"/>
<DataGridTextColumn Header="热导率 (W/m·K)" Binding="{Binding ThermalConductivity, StringFormat=F5}" Width="*"/>
<DataGridTextColumn Header="热扩散率 (m²/s)" Binding="{Binding ThermalDiffusivity, StringFormat=F10}" Width="*"/>
<DataGridTextColumn Header="体积热容 (kJ/m³·K)" Binding="{Binding VolumetricHeatCapacity, StringFormat=F2}" Width="*"/>
<DataGridTextColumn Header="序号" Binding="{Binding Index}" Width="60">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="热导率 (W/m·K)" Binding="{Binding ThermalConductivity, StringFormat=F5}" Width="*">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="热扩散率 (m²/s)" Binding="{Binding ThermalDiffusivity, StringFormat=F10}" Width="*">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="体积热容 (kJ/m³·K)" Binding="{Binding VolumetricHeatCapacity, StringFormat=F2}" Width="*">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Border>
@@ -257,7 +309,7 @@
IsEnabled="{Binding IsTesting, Converter={StaticResource InverseBooleanConverter}}"
Background="{StaticResource PrimaryButtonBrush}"/>
<Button Content="■ 停止测试" Command="{Binding StopTestCommandAsync}" Width="130" Height="36" Margin="8" Background="Orange"/>
<Button Content="■ 停止测试" Command="{Binding StopTestCommand}" Width="130" Height="36" Margin="8" Background="Orange"/>
<Button Content="⟳ 重置" Command="{Binding ResetCommand}" Width="100" Height="36" Margin="8"/>
@@ -275,7 +327,7 @@
<ComboBox ItemsSource="{Binding ReferenceLiquids}" SelectedItem="{Binding SelectedReferenceLiquid}" Width="100" Margin="5,0"/>
<TextBlock Text="参考热导率 (W/m·K):" VerticalAlignment="Center" Margin="10,0,5,0"/>
<TextBox Text="{Binding ReferenceConductivity}" Width="70" Margin="0,0,10,0"/>
<Button Content="开始校准" Command="{Binding PerformSystemCalibrationCommand}" Width="100"/>
<!--<Button Content="开始校准" Command="{Binding PerformSystemCalibrationCommand}" Width="100"/>-->
</WrapPanel>
<TextBlock Text="{Binding CalibrationStatus}" FontSize="11" Foreground="Blue" Margin="0,5,0,0"/>
</StackPanel>