Compare commits

...

18 Commits

Author SHA1 Message Date
xyy
8419aaaccd 2026-06-05 19:20:01 +08:00
xyy
4764ca789b 2026-06-05 19:18:29 +08:00
xyy
9eb7c54ac8 2026-06-05 19:13:46 +08:00
xyy
abc3e186e2 2026-06-05 17:33:59 +08:00
xyy
8573f5c4e5 2026-06-05 15:37:05 +08:00
xyy
d3fdb6a288 2026-06-05 11:58:47 +08:00
xyy
2c20eaf323 2026-06-05 11:27:05 +08:00
xyy
915fbdaa11 2026-06-04 14:28:07 +08:00
xyy
fed8c9b6dd 2026-06-04 10:26:57 +08:00
xyy
9a3cfff6d8 2026-06-03 20:38:16 +08:00
xyy
70da9f7c6c 2026-06-03 19:53:11 +08:00
xyy
1c073df913 2026-06-03 19:52:57 +08:00
xyy
9cf9eb8558 2026-06-03 19:20:27 +08:00
xyy
0186146acc 2026-06-03 18:37:29 +08:00
xyy
6719a84f80 2026-06-03 17:10:40 +08:00
xyy
59713c6af9 2026-06-03 17:01:00 +08:00
xyy
218c0aa666 2026-06-03 14:04:49 +08:00
xyy
22cab5e36d 2026-06-02 21:11:45 +08:00
7 changed files with 279 additions and 102 deletions

View File

@@ -22,6 +22,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.8" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.8" />
<PackageReference Include="NModbus4.NetCore" Version="4.0.0" /> <PackageReference Include="NModbus4.NetCore" Version="4.0.0" />
<PackageReference Include="OxyPlot.Wpf" Version="2.2.0" /> <PackageReference Include="OxyPlot.Wpf" Version="2.2.0" />
<PackageReference Include="PdfSharpCore" Version="1.3.67" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

Binary file not shown.

View File

@@ -46,7 +46,7 @@ public class TestParameters
public int MeasurementCount { get; set; } = 10; public int MeasurementCount { get; set; } = 10;
[Range(5, 300)] [Range(5, 300)]
public int IntervalSeconds { get; set; } = 30; public int IntervalSeconds { get; set; } = 30;
public double PlatinumWireLength { get; set; } = 0.056; // 默认 5.6 cm public double PlatinumWireLength { get; set; } = 0.04; // 默认 5.6 cm
public double PlatinumWireDiameter { get; set; } = 0.00006; public double PlatinumWireDiameter { get; set; } = 0.00006;
public string ReportOutputPath { get; set; } = "Reports\\"; public string ReportOutputPath { get; set; } = "Reports\\";
@@ -71,7 +71,7 @@ public class TestParameters
//public double FitStartTime { get; set; } = 0.01; // 默认0.35秒,避开早期扰动 //public double FitStartTime { get; set; } = 0.01; // 默认0.35秒,避开早期扰动
//public double FitEndTime { get; set; } = 0.1; //public double FitEndTime { get; set; } = 0.1;
public double FitStartTime { get; set; } = 0.20; // 默认0.35秒,避开早期扰动 public double FitStartTime { get; set; } = 0.25; // 默认0.35秒,避开早期扰动
public double FitEndTime { get; set; } = 0.60; public double FitEndTime { get; set; } = 0.60;
@@ -91,7 +91,6 @@ public class CalibrationCoefficients
public ushort PressureProtection { get; set; } public ushort PressureProtection { get; set; }
public ushort TemperatureCoefficient { get; set; } public ushort TemperatureCoefficient { get; set; }
public ushort ResistanceCoefficient { get; set; } public ushort ResistanceCoefficient { get; set; }
public double ThermalConductivityCorrection { get; set; } = 37;//蒸馏水 比热率修正
public double ThermalConductivityCorrection { get; set; } = 36.8; public double ThermalDiffusivityCorrection { get; set; } = 0.45;//导热率修正
public double ThermalDiffusivityCorrection { get; set; } = 19.9;
} }

View File

@@ -94,7 +94,7 @@ namespace ASTM_D7896_Tester.Services
await SendCommandAsync($"VOLT:DC:RANG {DefaultVoltageRange}"); await SendCommandAsync($"VOLT:DC:RANG {DefaultVoltageRange}");
// 3. 设置积分时间 0.02PLC(最快速度) // 3. 设置积分时间 0.02PLC(最快速度)
await SendCommandAsync("VOLT:DC:NPLC 0.02"); await SendCommandAsync("VOLT:DC:NPLC 0.1");
// 4. 关闭自动归零(提高速度) // 4. 关闭自动归零(提高速度)
await SendCommandAsync("VOLT:DC:ZERO:AUTO OFF"); await SendCommandAsync("VOLT:DC:ZERO:AUTO OFF");

View File

@@ -6,6 +6,9 @@ using CommunityToolkit.Mvvm.Input;
using OxyPlot; using OxyPlot;
using OxyPlot.Axes; using OxyPlot.Axes;
using OxyPlot.Series; using OxyPlot.Series;
using OxyPlot.Wpf;
using PdfSharpCore.Drawing;
using PdfSharpCore.Pdf;
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.IO; using System.IO;
@@ -38,7 +41,7 @@ public partial class D7896ViewModel : ObservableObject
private const double StandardResistor = 1.0; private const double StandardResistor = 1.0;
// 铂丝电阻温度系数 (纯铂) // 铂丝电阻温度系数 (纯铂)
private const double AlphaPt = 0.00385; // /°C private const double AlphaPt = 0.0040; // /°C
// 加热功率 Q 计算相关 // 加热功率 Q 计算相关
private double _heatingCurrent; // 实际加热电流平均值 private double _heatingCurrent; // 实际加热电流平均值
@@ -49,7 +52,7 @@ public partial class D7896ViewModel : ObservableObject
[ObservableProperty] private PlotModel _temperatureCurveModel; [ObservableProperty] private PlotModel _temperatureCurveModel;
// UI 绑定属性 (与之前一致) // UI 绑定属性 (与之前一致)
public ObservableCollection<string> ReferenceLiquids { get; } = new() { "蒸馏水", "甲苯", "乙二醇" }; public ObservableCollection<string> ReferenceLiquids { get; } = new() { "蒸馏水" };
[ObservableProperty] private string _sampleId = "未命名样品"; [ObservableProperty] private string _sampleId = "未命名样品";
[ObservableProperty] private double _testTemperature = 25.0; [ObservableProperty] private double _testTemperature = 25.0;
[ObservableProperty] private string _testDateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); [ObservableProperty] private string _testDateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
@@ -91,7 +94,7 @@ public partial class D7896ViewModel : ObservableObject
private const double EulerGamma = 0.5772156649; // 欧拉常数 private const double EulerGamma = 0.5772156649; // 欧拉常数
//private const double WireRadius = 0.00003; // 铂丝半径 (0.03 mm) //private const double WireRadius = 0.00003; // 铂丝半径 (0.03 mm)
[ObservableProperty] private double _sampleDensity = 1000.0; // 新增密度默认值1000 kg/m³ [ObservableProperty] private double _sampleDensity = 1000.0; // 新增密度默认值1000 kg/m³
int samples = 800; // 1秒 * 1000点/秒 int samples = 200; // 1秒 * 1000点/秒
double heatingDuration = 1; // 加热时间 0.8 秒(需与您的加热脉冲宽度一致) double heatingDuration = 1; // 加热时间 0.8 秒(需与您的加热脉冲宽度一致)
double totalDuration = 2; // 总采样时间(加热 + 冷却) double totalDuration = 2; // 总采样时间(加热 + 冷却)
public D7896ViewModel() public D7896ViewModel()
@@ -140,6 +143,7 @@ public partial class D7896ViewModel : ObservableObject
Application.Current?.Dispatcher.Invoke(() => ChamberPressure = rawPressure); Application.Current?.Dispatcher.Invoke(() => ChamberPressure = rawPressure);
float rawTemp = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Temperature); float rawTemp = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Temperature);
rawTemp *= 1.0435f;
Application.Current?.Dispatcher.Invoke(() => CurrentTestTemperature = rawTemp); Application.Current?.Dispatcher.Invoke(() => CurrentTestTemperature = rawTemp);
} }
catch { } catch { }
@@ -195,6 +199,10 @@ public partial class D7896ViewModel : ObservableObject
try try
{ {
await _th1963Ustd.ConnectAsync("192.168.1.12", 45454); // 改为实际IP await _th1963Ustd.ConnectAsync("192.168.1.12", 45454); // 改为实际IP
await _th1963Ustd.ConfigureForHighSpeedDcvAsync(); await _th1963Ustd.ConfigureForHighSpeedDcvAsync();
@@ -268,14 +276,25 @@ public partial class D7896ViewModel : ObservableObject
await Task.Delay(100); await Task.Delay(100);
await _th1953Ustd.FetchBatchAsync(); // 丢弃结果 await _th1953Ustd.FetchBatchAsync(); // 丢弃结果
for (int i = 1; i <= _config.TestParameters.MeasurementCount; i++)
int requiredCount = _config.TestParameters.MeasurementCount; // 需要多少有效数据
int validCount = 0;
int attemptCount = 0;
int maxAttempts = requiredCount * 2; // 最多尝试次数,防止死循环
// 存储每次成功测量的结果(用于后续异常判断)
List<double> validLambdaList = new List<double>();
List<double> validAlphaList = new List<double>();
List<double> validCpList = new List<double>();
while (validCount < requiredCount && attemptCount < maxAttempts && !_stopRequested)
{ {
if (_stopRequested) break; attemptCount++;
CurrentMeasurementIndex = attemptCount; // 显示当前尝试次数(不是有效次数)
CurrentMeasurementIndex = i; StatusMessage = $"正在执行第 {attemptCount} 次测量(有效:{validCount}/{requiredCount}...";
StatusMessage = $"正在执行第 {i} 次测量...";
// --- 步骤1基线采集加热前--- // --- 步骤1基线采集加热前---
await _th1963Ustd.PrepareBatchAsync(50); await _th1963Ustd.PrepareBatchAsync(50);
@@ -285,7 +304,7 @@ public partial class D7896ViewModel : ObservableObject
double[] ustdBase = await _th1963Ustd.FetchBatchAsync(); double[] ustdBase = await _th1963Ustd.FetchBatchAsync();
double[] uptBase = await _th1953Ustd.FetchBatchAsync(); double[] uptBase = await _th1953Ustd.FetchBatchAsync();
double dynamicR0 = 2.45; // 默认值 double dynamicR0 = 1.476979; // 默认值
if (ustdBase != null && ustdBase.Length > 0 && uptBase != null && uptBase.Length > 0) if (ustdBase != null && ustdBase.Length > 0 && uptBase != null && uptBase.Length > 0)
{ {
double sumR0 = 0; int cnt = 0; double sumR0 = 0; int cnt = 0;
@@ -312,15 +331,6 @@ public partial class D7896ViewModel : ObservableObject
Logger.Log("基线采集未返回数据,将使用加热段早期点"); Logger.Log("基线采集未返回数据,将使用加热段早期点");
} }
// --- 步骤2正式加热采集 --- // --- 步骤2正式加热采集 ---
await _th1963Ustd.PrepareBatchAsync(samples); await _th1963Ustd.PrepareBatchAsync(samples);
await _th1953Ustd.PrepareBatchAsync(samples); await _th1953Ustd.PrepareBatchAsync(samples);
@@ -339,10 +349,9 @@ public partial class D7896ViewModel : ObservableObject
double[] ustd = await _th1963Ustd.FetchBatchAsync(); double[] ustd = await _th1963Ustd.FetchBatchAsync();
double[] upt = await _th1953Ustd.FetchBatchAsync(); double[] upt = await _th1953Ustd.FetchBatchAsync();
if (dynamicR0 == 2.45) // 仍为默认值,说明基线无效 if (dynamicR0 == 1.476979) // 基线无效
{ {
double sumR0 = 0; int cnt = 0; double sumR0 = 0; int cnt = 0;
// 改用第 2~5 点(索引 2,3,4,5
for (int j = 2; j < Math.Min(6, ustd.Length); j++) for (int j = 2; j < Math.Min(6, ustd.Length); j++)
{ {
if (ustd[j] > 0.01 && upt[j] > 0.01) if (ustd[j] > 0.01 && upt[j] > 0.01)
@@ -358,9 +367,7 @@ public partial class D7896ViewModel : ObservableObject
} }
} }
// 记录原始电压(调试用)
for (int j = 0; j < 20 && j < ustd.Length; j++) for (int j = 0; j < 20 && j < ustd.Length; j++)
{ {
Logger.Log($"第{j}点: U_std={ustd[j]:F6} V, U_pt={upt[j]:F6} V"); Logger.Log($"第{j}点: U_std={ustd[j]:F6} V, U_pt={upt[j]:F6} V");
@@ -368,53 +375,85 @@ public partial class D7896ViewModel : ObservableObject
StandardResistorVoltage = ustd.Average(); StandardResistorVoltage = ustd.Average();
PlatinumVoltage = upt.Average(); PlatinumVoltage = upt.Average();
Logger.Log($"测量 {i}: U_std 平均值={ustd.Average():F6} V, U_pt 平均值={upt.Average():F6} V"); Logger.Log($"测量 {attemptCount}: U_std 平均值={ustd.Average():F6} V, U_pt 平均值={upt.Average():F6} V");
double[] timeArray = new double[ustd.Length]; double[] timeArray = new double[ustd.Length];
for (int idx = 0; idx < timeArray.Length; idx++) for (int idx = 0; idx < timeArray.Length; idx++)
timeArray[idx] = idx * totalDuration / samples; timeArray[idx] = idx * totalDuration / samples;
// 计算本次测量的 λ 和 α (传入刚才测得的冷态 dynamicR0)
var (lambda, alpha, deltaT, coolingPoints) = ComputeThermalProperties(upt, ustd, timeArray, dynamicR0, CurrentTestTemperature); var (lambda, alpha, deltaT, coolingPoints) = ComputeThermalProperties(upt, ustd, timeArray, dynamicR0, CurrentTestTemperature);
// 计算比热容 Cp
double vhc = lambda / alpha; // kJ/(m³·K)
double cp = vhc / SampleDensity; // J/(kg·K)
//var lambdaCorr = _config.TestParameters.CalibrationCoefficients.ThermalConductivityCorrection; Logger.Log($"测量 {attemptCount} 结果: λ={lambda:F6} W/(m·K), α={alpha:E6} m²/s, Cp={cp:F2} J/(kg·K)");
//var alphaCorr = _config.TestParameters.CalibrationCoefficients.ThermalDiffusivityCorrection;
//lambda *= lambdaCorr; // ---- 异常值检测 ----
//alpha *= alphaCorr; bool isOutlier = false;
double deviationThreshold = 0.20; // 20% 偏差阈值
Logger.Log($"测量 {i} 结果: λ={lambda:F6} W/(m·K), α={alpha:E6} m²/s"); if (validCount >= 2) // 至少有两个有效数据后才开始剔除
{
double avgLambda = validLambdaList.Average();
double avgAlpha = validAlphaList.Average();
double avgCp = validCpList.Average();
if (Math.Abs(lambda - avgLambda) / avgLambda > deviationThreshold ||
Math.Abs(alpha - avgAlpha) / avgAlpha > deviationThreshold ||
Math.Abs(cp - avgCp) / avgCp > deviationThreshold)
{
isOutlier = true;
Logger.Log($"第 {attemptCount} 次测量结果异常(偏差过大),予以舍弃。λ={lambda:F4}, α={alpha:E4}, Cp={cp:F2}");
}
}
if (!isOutlier)
{
// 正常结果,添加到列表
validLambdaList.Add(lambda);
validAlphaList.Add(alpha);
validCpList.Add(cp);
validCount++;
GenerateTemperatureCurveFromData(timeArray, deltaT, coolingPoints); GenerateTemperatureCurveFromData(timeArray, deltaT, coolingPoints);
var result = new MeasurementResult var result = new MeasurementResult
{ {
Index = i, Index = validCount, // 使用有效次数编号
ThermalConductivity = lambda, ThermalConductivity = lambda,
ThermalDiffusivity = alpha ThermalDiffusivity = alpha
}; };
result.CalculateVhcAndCp(SampleDensity); result.CalculateVhcAndCp(SampleDensity);
Application.Current.Dispatcher.Invoke(() => Measurements.Add(result)); Application.Current.Dispatcher.Invoke(() => Measurements.Add(result));
StatusMessage = $"第 {i} 次测量完成,λ={lambda:F4} W/m·K"; StatusMessage = $"第 {validCount} 次测量完成,λ={lambda:F4} W/m·K";
Logger.Log($"========== 第 {i} 次测量详细数据 =========="); Logger.Log($"========== 第 {validCount} 次测量详细数据 ==========");
Logger.Log($"热导率 λ: {lambda:F6} W/(m·K)"); Logger.Log($"热导率 λ: {lambda:F6} W/(m·K)");
Logger.Log($"热扩散率 α: {alpha:E6} m²/s"); Logger.Log($"热扩散率 α: {alpha:E6} m²/s");
Logger.Log($"体积热容 VHC: {result.VolumetricHeatCapacity:F2} kJ/(m³·K)"); Logger.Log($"体积热容 VHC: {result.VolumetricHeatCapacity:F2} kJ/(m³·K)");
Logger.Log($"比热容 Cp: {result.SpecificHeatCapacity:F2} J/(kg·K)"); Logger.Log($"比热容 Cp: {cp:F2} J/(kg·K)");
Logger.Log($"初始电阻 R0: {dynamicR0:F6} Ω"); Logger.Log($"初始电阻 R0: {dynamicR0:F6} Ω");
Logger.Log("==========================================="); Logger.Log("===========================================");
}
if (i < _config.TestParameters.MeasurementCount && !_stopRequested) // 测量间隔(即使舍弃也等待,让样品恢复)
if (validCount < requiredCount && !_stopRequested && attemptCount < maxAttempts)
{ {
try { await Task.Delay(_config.TestParameters.IntervalSeconds * 500, _testCts.Token); } catch (OperationCanceledException) { break; } try { await Task.Delay(_config.TestParameters.IntervalSeconds * 100, _testCts.Token); } catch (OperationCanceledException) { break; }
} }
} }
if (validCount >= requiredCount)
{
CalculateAverages(); CalculateAverages();
StatusMessage = _stopRequested ? "测试已停止。" : "测试完成"; StatusMessage = "测试完成";
}
else
{
StatusMessage = $"测试中止。";
MessageBox.Show($"测试中止,未收集到足够有效数据({validCount}/{requiredCount})。请检查样品或仪器状态。", "提示");
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -544,6 +583,7 @@ public partial class D7896ViewModel : ObservableObject
lambda = _config.TestParameters.FixedLambda; lambda = _config.TestParameters.FixedLambda;
Logger.Log($"使用固定 lambda={lambda:F6} W/(m·K)"); Logger.Log($"使用固定 lambda={lambda:F6} W/(m·K)");
} }
lambda *= _config.TestParameters.CalibrationCoefficients.ThermalDiffusivityCorrection;
Logger.Log($"constantCurrent(avg)={avgCurrent:E6} A, avgResistance={avgResistance:F6} Ω, powerPerLength={powerPerLength:E6} W/m, 斜率 B = {slope:F5}"); Logger.Log($"constantCurrent(avg)={avgCurrent:E6} A, avgResistance={avgResistance:F6} Ω, powerPerLength={powerPerLength:E6} W/m, 斜率 B = {slope:F5}");
// 计算热扩散率 // 计算热扩散率
@@ -573,22 +613,22 @@ public partial class D7896ViewModel : ObservableObject
coolingPoints.Add(new DataPoint(time[i], deltaT[i])); coolingPoints.Add(new DataPoint(time[i], deltaT[i]));
// 导出CSV // 导出CSV
try //try
{ //{
string tmp = Path.GetTempPath(); // string tmp = Path.GetTempPath();
string baseName = $"measure_{SampleId}_{DateTime.Now:yyyyMMdd_HHmmss}_{CurrentMeasurementIndex}"; // string baseName = $"measure_{SampleId}_{DateTime.Now:yyyyMMdd_HHmmss}_{CurrentMeasurementIndex}";
string dataPath = Path.Combine(tmp, baseName + ".csv"); // string dataPath = Path.Combine(tmp, baseName + ".csv");
ExportMeasurementCsv(dataPath, time, ustd, upt, deltaT, startIdx, endIdx); // ExportMeasurementCsv(dataPath, time, ustd, upt, deltaT, startIdx, endIdx);
Logger.Log($"已导出测量数据 CSV: {dataPath}"); // Logger.Log($"已导出测量数据 CSV: {dataPath}");
string winPath = Path.Combine(tmp, baseName + "_windows.csv"); // string winPath = Path.Combine(tmp, baseName + "_windows.csv");
ExportCandidateWindowsCsv(winPath, time, deltaT, startIdx, endIdx); // ExportCandidateWindowsCsv(winPath, time, deltaT, startIdx, endIdx);
Logger.Log($"已导出候选拟合窗 CSV: {winPath}"); // Logger.Log($"已导出候选拟合窗 CSV: {winPath}");
} //}
catch (Exception ex) //catch (Exception ex)
{ //{
Logger.Log($"导出CSV失败: {ex.Message}"); // Logger.Log($"导出CSV失败: {ex.Message}");
} //}
return (lambda, alpha, deltaT, coolingPoints); return (lambda, alpha, deltaT, coolingPoints);
} }
@@ -770,6 +810,40 @@ public partial class D7896ViewModel : ObservableObject
TemperatureCurveModel = null; TemperatureCurveModel = null;
} }
//[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,
// ["InitialResistance"] = PlatinumResistance
// };
// 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] [RelayCommand]
private async Task GenerateReportAsync() private async Task GenerateReportAsync()
{ {
@@ -778,35 +852,136 @@ public partial class D7896ViewModel : ObservableObject
MessageBox.Show("没有测试数据", "提示"); MessageBox.Show("没有测试数据", "提示");
return; return;
} }
// 选择保存路径
var saveFileDialog = new Microsoft.Win32.SaveFileDialog
{
Filter = "PDF files (*.pdf)|*.pdf",
DefaultExt = ".pdf",
FileName = $"报告_{SampleId}_{DateTime.Now:yyyyMMdd_HHmmss}.pdf"
};
if (saveFileDialog.ShowDialog() != true)
return;
string pdfPath = saveFileDialog.FileName;
try try
{ {
var extraParams = new Dictionary<string, object> // 生成 PDF
{ await Task.Run(() => GeneratePdfReport(pdfPath));
["SampleVolume"] = SampleVolume, MessageBox.Show($"报表已生成: {pdfPath}", "成功");
["BubbleRemoved"] = BubbleRemoved,
["UsePressure"] = UsePressure,
["PressureValue"] = PressureValue,
["IsCleanConfirmed"] = IsCleanConfirmed,
["CleanerName"] = CleanerName,
["AmbientTemperature"] = AmbientTemperature,
["AmbientCalibrated"] = AmbientCalibrated,
["PlatinumCompatible"] = PlatinumCompatible,
["LiquidReactivityNote"] = LiquidReactivityNote,
["InitialResistance"] = PlatinumResistance
};
string reportPath = await _reportService.GenerateReportAsync(SampleId, TestTemperature, Measurements.ToList(),
AverageThermalConductivity, AverageThermalDiffusivity, AverageVolumetricHeatCapacity,
_config.TestParameters, extraParams);
MessageBox.Show($"报告已生成: {reportPath}", "成功");
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show($"生成报失败: {ex.Message}", "错误"); MessageBox.Show($"生成报失败: {ex.Message}", "错误");
} }
} }
private void GeneratePdfReport(string filePath)
{
// 1. 创建文档
using (var document = new PdfDocument())
{
// 2. 添加页面
var page = document.AddPage();
page.Width = XUnit.FromMillimeter(210);
page.Height = XUnit.FromMillimeter(297);
// 3. 开始绘制
using (var gfx = XGraphics.FromPdfPage(page))
{
// 创建字体
var titleFont = new XFont("Verdana", 16, XFontStyle.Bold);
var headerFont = new XFont("Verdana", 12, XFontStyle.Bold);
var normalFont = new XFont("Verdana", 10, XFontStyle.Regular);
double yPosition = 30;
// ---------- 4. 添加标题 ----------
gfx.DrawString("ASTM D7896-19 瞬态热线法测试报告", titleFont, XBrushes.Black,
new XRect(0, yPosition, page.Width, 30), XStringFormats.TopCenter);
yPosition += 40;
// ---------- 5. 添加基础信息 ----------
gfx.DrawString($"样品名称: {SampleId}", normalFont, XBrushes.Black, new XPoint(40, yPosition)); yPosition += 25;
gfx.DrawString($"测试温度: {TestTemperature:F1} °C", normalFont, XBrushes.Black, new XPoint(40, yPosition)); yPosition += 25;
// ... 所有需要显示的基础信息
yPosition += 10;
// ---------- 6. 插入温升曲线图 ----------
if (TemperatureCurveModel != null)
{
using (var stream = new MemoryStream())
{
var exporter = new PngExporter { Width = 600, Height = 400 };
exporter.Export(TemperatureCurveModel, stream);
stream.Position = 0;
var imgStream = new MemoryStream(stream.ToArray(), 0, (int)stream.Length, false, true);
var image = XImage.FromStream(() => imgStream);
gfx.DrawImage(image, 40, yPosition, 500, 330);
yPosition += 350;
}
}
// ---------- 7. 创建表格 ----------
gfx.DrawString("测量结果明细", headerFont, XBrushes.Black, new XPoint(40, yPosition)); yPosition += 25;
// 表头
string[] headers = { "序号", "热导率λ(W/(m·K))", "热扩散率α(10⁻⁷ m²/s)", "体积热容VHC(kJ/(m³·K))", "比热容Cp(J/(kg·K))" };
double[] colWidths = { 50, 100, 100, 120, 100 };
double startX = 40;
double currentRowY = yPosition;
// 绘制表头
for (int i = 0; i < headers.Length; i++)
{
double cellX = startX + colWidths.Take(i).Sum();
gfx.DrawRectangle(XPens.Black, cellX, currentRowY, colWidths[i], 20);
var textRect = new XRect(cellX, currentRowY, colWidths[i], 20);
gfx.DrawString(headers[i], normalFont, XBrushes.Black, textRect, XStringFormats.Center);
}
currentRowY += 20;
// 填充数据行 (假设 Measurements 是列表)
for (int i = 0; i < Measurements.Count; i++)
{
var m = Measurements[i];
string[] rowData = {
m.Index.ToString(),
m.ThermalConductivity.ToString("F6"),
(m.ThermalDiffusivity * 1e7).ToString("F3"),
m.VolumetricHeatCapacity.ToString("F2"),
m.SpecificHeatCapacity.ToString("F2")
};
for (int j = 0; j < rowData.Length; j++)
{
double cellX = startX + colWidths.Take(j).Sum();
gfx.DrawRectangle(XPens.Black, cellX, currentRowY, colWidths[j], 20);
var textRect = new XRect(cellX, currentRowY, colWidths[j], 20);
gfx.DrawString(rowData[j], normalFont, XBrushes.Black, textRect, XStringFormats.Center);
}
currentRowY += 20;
}
yPosition = currentRowY + 10;
// ---------- 8. 添加平均值 ----------
gfx.DrawString($"平均热导率: {AverageThermalConductivity:F6} W/(m·K)", normalFont, XBrushes.Black, new XPoint(40, yPosition)); yPosition += 20;
// ... 其他平均值
// ---------- 9. 添加生成时间和页脚 ----------
gfx.DrawString($"生成时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}", normalFont, XBrushes.Black, new XPoint(40, page.Height - 30));
}
// 10. 保存文档
document.Save(filePath);
}
}
[RelayCommand] [RelayCommand]
private async Task StopTest() private async Task StopTest()
{ {
@@ -874,7 +1049,7 @@ public partial class D7896ViewModel : ObservableObject
try try
{ {
float rawPressure = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Pressure); float rawPressure = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Pressure);
ChamberPressure = rawPressure / 10.0; ChamberPressure = rawPressure;
} }
catch { } catch { }
} }

View File

@@ -136,7 +136,7 @@
<CheckBox IsChecked="{Binding PlatinumCompatible}" Content="铂兼容性 (1.4)" Margin="0,0,15,0"/> <CheckBox IsChecked="{Binding PlatinumCompatible}" Content="铂兼容性 (1.4)" Margin="0,0,15,0"/>
<CheckBox IsChecked="{Binding AmbientCalibrated}" Content="环境温度校准 (8.1)" Margin="0,0,15,0"/> <CheckBox IsChecked="{Binding AmbientCalibrated}" Content="环境温度校准 (8.1)" Margin="0,0,15,0"/>
<TextBlock Text="状态:" VerticalAlignment="Center" Margin="20,0,5,0"/> <TextBlock Text="状态:" VerticalAlignment="Center" Margin="20,0,5,0"/>
<TextBox Text="{Binding StatusMessage}" Width="200" IsReadOnly="True" Background="#FFF7E6"/> <TextBox Text="{Binding StatusMessage}" Width="260" IsReadOnly="True" Background="#FFF7E6"/>
</WrapPanel> </WrapPanel>
</StackPanel> </StackPanel>
</Border> </Border>
@@ -324,7 +324,7 @@
<TextBlock Text="系统校准 (附录A3)" FontWeight="Bold" Margin="0,0,0,5"/> <TextBlock Text="系统校准 (附录A3)" FontWeight="Bold" Margin="0,0,0,5"/>
<WrapPanel> <WrapPanel>
<TextBlock Text="参考液:" VerticalAlignment="Center"/> <TextBlock Text="参考液:" VerticalAlignment="Center"/>
<ComboBox ItemsSource="{Binding ReferenceLiquids}" SelectedItem="{Binding SelectedReferenceLiquid}" Width="100" Margin="5,0"/> <ComboBox ItemsSource="{Binding ReferenceLiquids}" IsReadOnly="True" SelectedItem="{Binding SelectedReferenceLiquid}" Width="100" Margin="5,0"/>
<TextBlock Text="参考热导率 (W/m·K):" VerticalAlignment="Center" Margin="10,0,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"/> <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"/>-->

View File

@@ -25,10 +25,12 @@
"TestParameters": { "TestParameters": {
"MeasurementCount": 10, "MeasurementCount": 10,
"IntervalSeconds": 30, "IntervalSeconds": 30,
"PlatinumWireLength": 0.1250, //铂丝长度(单位:米) //"PlatinumWireLength": 0.110, //铂丝长度(单位:米)
//"PlatinumWireDiameter": 0.000032,
//"PlatinumWireLength": 0.056, //铂丝长度(单位:米)
//"PlatinumWireDiameter": 0.00006,
"PlatinumWireLength": 0.04, //铂丝长度(单位:米)
"PlatinumWireDiameter": 0.00006, "PlatinumWireDiameter": 0.00006,
//"PlatinumWireLength": 0.41, //铂丝长度(单位:米)
//"PlatinumWireDiameter": 0.00021,
"ReportOutputPath": "Reports\\", "ReportOutputPath": "Reports\\",
"DefaultSampleVolume": 40.0, "DefaultSampleVolume": 40.0,
"DefaultPressure": 0.0, "DefaultPressure": 0.0,