Compare commits
13 Commits
84df130973
...
915fbdaa11
| Author | SHA1 | Date | |
|---|---|---|---|
| 915fbdaa11 | |||
| fed8c9b6dd | |||
| 9a3cfff6d8 | |||
| 70da9f7c6c | |||
| 1c073df913 | |||
| 9cf9eb8558 | |||
| 0186146acc | |||
| 6719a84f80 | |||
| 59713c6af9 | |||
| 218c0aa666 | |||
| 22cab5e36d | |||
| 9d59b439eb | |||
| dea0d29d18 |
@@ -22,6 +22,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.8" />
|
||||
<PackageReference Include="NModbus4.NetCore" Version="4.0.0" />
|
||||
<PackageReference Include="OxyPlot.Wpf" Version="2.2.0" />
|
||||
<PackageReference Include="PdfSharpCore" Version="1.3.67" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -68,8 +68,11 @@ public class TestParameters
|
||||
|
||||
|
||||
|
||||
public double FitStartTime { get; set; } = 0.01; // 默认0.35秒,避开早期扰动
|
||||
public double FitEndTime { get; set; } = 0.3;
|
||||
//public double FitStartTime { get; set; } = 0.01; // 默认0.35秒,避开早期扰动
|
||||
//public double FitEndTime { get; set; } = 0.1;
|
||||
|
||||
public double FitStartTime { get; set; } = 0.25; // 默认0.35秒,避开早期扰动
|
||||
public double FitEndTime { get; set; } = 0.60;
|
||||
|
||||
|
||||
|
||||
@@ -88,7 +91,6 @@ public class CalibrationCoefficients
|
||||
public ushort PressureProtection { get; set; }
|
||||
public ushort TemperatureCoefficient { get; set; }
|
||||
public ushort ResistanceCoefficient { get; set; }
|
||||
|
||||
public double ThermalConductivityCorrection { get; set; } = 0.606;
|
||||
public double ThermalDiffusivityCorrection { get; set; } = 19.9;
|
||||
public double ThermalConductivityCorrection { get; set; } = 39;//蒸馏水 比热率修正
|
||||
public double ThermalDiffusivityCorrection { get; set; } = 0.5;//导热率修正
|
||||
}
|
||||
@@ -94,7 +94,7 @@ namespace ASTM_D7896_Tester.Services
|
||||
await SendCommandAsync($"VOLT:DC:RANG {DefaultVoltageRange}");
|
||||
|
||||
// 3. 设置积分时间 0.02PLC(最快速度)
|
||||
await SendCommandAsync("VOLT:DC:NPLC 0.02");
|
||||
await SendCommandAsync("VOLT:DC:NPLC 0.1");
|
||||
|
||||
// 4. 关闭自动归零(提高速度)
|
||||
await SendCommandAsync("VOLT:DC:ZERO:AUTO OFF");
|
||||
|
||||
@@ -6,6 +6,9 @@ using CommunityToolkit.Mvvm.Input;
|
||||
using OxyPlot;
|
||||
using OxyPlot.Axes;
|
||||
using OxyPlot.Series;
|
||||
using OxyPlot.Wpf;
|
||||
using PdfSharpCore.Drawing;
|
||||
using PdfSharpCore.Pdf;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
@@ -38,7 +41,7 @@ public partial class D7896ViewModel : ObservableObject
|
||||
private const double StandardResistor = 1.0;
|
||||
|
||||
// 铂丝电阻温度系数 (纯铂)
|
||||
private const double AlphaPt = 0.00385; // /°C
|
||||
private const double AlphaPt = 0.0040; // /°C
|
||||
|
||||
// 加热功率 Q 计算相关
|
||||
private double _heatingCurrent; // 实际加热电流平均值
|
||||
@@ -90,9 +93,8 @@ public partial class D7896ViewModel : ObservableObject
|
||||
|
||||
private const double EulerGamma = 0.5772156649; // 欧拉常数
|
||||
//private const double WireRadius = 0.00003; // 铂丝半径 (0.03 mm)
|
||||
private const double WireRadius = 0.00010; // 铂丝半径 (0.03 mm)
|
||||
[ObservableProperty] private double _sampleDensity = 1000.0; // 新增,密度默认值1000 kg/m³(水)
|
||||
int samples = 1000; // 1秒 * 1000点/秒
|
||||
int samples = 200; // 1秒 * 1000点/秒
|
||||
double heatingDuration = 1; // 加热时间 0.8 秒(需与您的加热脉冲宽度一致)
|
||||
double totalDuration = 2; // 总采样时间(加热 + 冷却)
|
||||
public D7896ViewModel()
|
||||
@@ -196,6 +198,10 @@ public partial class D7896ViewModel : ObservableObject
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
await _th1963Ustd.ConnectAsync("192.168.1.12", 45454); // 改为实际IP
|
||||
await _th1963Ustd.ConfigureForHighSpeedDcvAsync();
|
||||
|
||||
@@ -269,14 +275,25 @@ public partial class D7896ViewModel : ObservableObject
|
||||
await Task.Delay(100);
|
||||
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;
|
||||
|
||||
CurrentMeasurementIndex = i;
|
||||
StatusMessage = $"正在执行第 {i} 次测量...";
|
||||
|
||||
|
||||
attemptCount++;
|
||||
CurrentMeasurementIndex = attemptCount; // 显示当前尝试次数(不是有效次数)
|
||||
StatusMessage = $"正在执行第 {attemptCount} 次测量(有效:{validCount}/{requiredCount})...";
|
||||
|
||||
// --- 步骤1:基线采集(加热前)---
|
||||
await _th1963Ustd.PrepareBatchAsync(50);
|
||||
@@ -313,15 +330,6 @@ public partial class D7896ViewModel : ObservableObject
|
||||
Logger.Log("基线采集未返回数据,将使用加热段早期点");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --- 步骤2:正式加热采集 ---
|
||||
await _th1963Ustd.PrepareBatchAsync(samples);
|
||||
await _th1953Ustd.PrepareBatchAsync(samples);
|
||||
@@ -340,11 +348,10 @@ public partial class D7896ViewModel : ObservableObject
|
||||
double[] ustd = await _th1963Ustd.FetchBatchAsync();
|
||||
double[] upt = await _th1953Ustd.FetchBatchAsync();
|
||||
|
||||
if (dynamicR0 == 2.45) // 仍为默认值,说明基线无效
|
||||
if (dynamicR0 == 2.45) // 基线无效
|
||||
{
|
||||
double sumR0 = 0; int cnt = 0;
|
||||
// 改用第 10 到 19 点(共10个点),避开前10个点的干扰
|
||||
for (int j = 10; j < Math.Min(20, ustd.Length); j++)
|
||||
for (int j = 2; j < Math.Min(6, ustd.Length); j++)
|
||||
{
|
||||
if (ustd[j] > 0.01 && upt[j] > 0.01)
|
||||
{
|
||||
@@ -355,13 +362,11 @@ public partial class D7896ViewModel : ObservableObject
|
||||
if (cnt > 0)
|
||||
{
|
||||
dynamicR0 = sumR0 / cnt;
|
||||
Logger.Log($"使用加热段第10~19点计算 R0 = {dynamicR0:F6} Ω");
|
||||
Logger.Log($"使用加热段第2~5点计算 R0 = {dynamicR0:F6} Ω");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 记录原始电压(调试用)
|
||||
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");
|
||||
@@ -369,53 +374,85 @@ public partial class D7896ViewModel : ObservableObject
|
||||
|
||||
StandardResistorVoltage = ustd.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];
|
||||
for (int idx = 0; idx < timeArray.Length; idx++)
|
||||
timeArray[idx] = idx * totalDuration / samples;
|
||||
|
||||
// 计算本次测量的 λ 和 α (传入刚才测得的冷态 dynamicR0)
|
||||
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;
|
||||
//var alphaCorr = _config.TestParameters.CalibrationCoefficients.ThermalDiffusivityCorrection;
|
||||
Logger.Log($"测量 {attemptCount} 结果: λ={lambda:F6} W/(m·K), α={alpha:E6} m²/s, Cp={cp:F2} J/(kg·K)");
|
||||
|
||||
//lambda *= lambdaCorr;
|
||||
//alpha *= alphaCorr;
|
||||
// ---- 异常值检测 ----
|
||||
bool isOutlier = false;
|
||||
double deviationThreshold = 0.20; // 20% 偏差阈值
|
||||
|
||||
Logger.Log($"测量 {i} 结果: λ={lambda:F6} W/(m·K), α={alpha:E6} m²/s");
|
||||
|
||||
GenerateTemperatureCurveFromData(timeArray, deltaT, coolingPoints);
|
||||
|
||||
var result = new MeasurementResult
|
||||
if (validCount >= 2) // 至少有两个有效数据后才开始剔除
|
||||
{
|
||||
Index = i,
|
||||
ThermalConductivity = lambda,
|
||||
ThermalDiffusivity = alpha
|
||||
};
|
||||
result.CalculateVhcAndCp(SampleDensity);
|
||||
Application.Current.Dispatcher.Invoke(() => Measurements.Add(result));
|
||||
StatusMessage = $"第 {i} 次测量完成,λ={lambda:F4} W/m·K";
|
||||
double avgLambda = validLambdaList.Average();
|
||||
double avgAlpha = validAlphaList.Average();
|
||||
double avgCp = validCpList.Average();
|
||||
|
||||
Logger.Log($"========== 第 {i} 次测量详细数据 ==========");
|
||||
Logger.Log($"热导率 λ: {lambda:F6} W/(m·K)");
|
||||
Logger.Log($"热扩散率 α: {alpha:E6} m²/s");
|
||||
Logger.Log($"体积热容 VHC: {result.VolumetricHeatCapacity:F2} kJ/(m³·K)");
|
||||
Logger.Log($"比热容 Cp: {result.SpecificHeatCapacity:F2} J/(kg·K)");
|
||||
Logger.Log($"初始电阻 R0: {dynamicR0:F6} Ω");
|
||||
Logger.Log("===========================================");
|
||||
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 (i < _config.TestParameters.MeasurementCount && !_stopRequested)
|
||||
if (!isOutlier)
|
||||
{
|
||||
// 正常结果,添加到列表
|
||||
validLambdaList.Add(lambda);
|
||||
validAlphaList.Add(alpha);
|
||||
validCpList.Add(cp);
|
||||
validCount++;
|
||||
|
||||
GenerateTemperatureCurveFromData(timeArray, deltaT, coolingPoints);
|
||||
|
||||
var result = new MeasurementResult
|
||||
{
|
||||
Index = validCount, // 使用有效次数编号
|
||||
ThermalConductivity = lambda,
|
||||
ThermalDiffusivity = alpha
|
||||
};
|
||||
result.CalculateVhcAndCp(SampleDensity);
|
||||
Application.Current.Dispatcher.Invoke(() => Measurements.Add(result));
|
||||
StatusMessage = $"第 {validCount} 次测量完成,λ={lambda:F4} W/m·K";
|
||||
|
||||
Logger.Log($"========== 第 {validCount} 次测量详细数据 ==========");
|
||||
Logger.Log($"热导率 λ: {lambda:F6} W/(m·K)");
|
||||
Logger.Log($"热扩散率 α: {alpha:E6} m²/s");
|
||||
Logger.Log($"体积热容 VHC: {result.VolumetricHeatCapacity:F2} kJ/(m³·K)");
|
||||
Logger.Log($"比热容 Cp: {cp:F2} J/(kg·K)");
|
||||
Logger.Log($"初始电阻 R0: {dynamicR0:F6} Ω");
|
||||
Logger.Log("===========================================");
|
||||
}
|
||||
|
||||
// 测量间隔(即使舍弃也等待,让样品恢复)
|
||||
if (validCount < requiredCount && !_stopRequested && attemptCount < maxAttempts)
|
||||
{
|
||||
try { await Task.Delay(_config.TestParameters.IntervalSeconds * 1000, _testCts.Token); } catch (OperationCanceledException) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CalculateAverages();
|
||||
StatusMessage = _stopRequested ? "测试已停止。" : "测试完成。";
|
||||
if (validCount >= requiredCount)
|
||||
{
|
||||
CalculateAverages();
|
||||
StatusMessage = "测试完成";
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusMessage = $"测试中止。";
|
||||
MessageBox.Show($"测试中止,未收集到足够有效数据({validCount}/{requiredCount})。请检查样品或仪器状态。", "提示");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -545,12 +582,15 @@ public partial class D7896ViewModel : ObservableObject
|
||||
lambda = _config.TestParameters.FixedLambda;
|
||||
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}");
|
||||
|
||||
// 计算热扩散率
|
||||
double exponent = intercept / slope + EulerGamma;
|
||||
if (exponent > 30) exponent = 30;
|
||||
double alpha = (WireRadius * WireRadius / 4.0) * Math.Exp(exponent);
|
||||
double alpha = (_config.TestParameters.PlatinumWireDiameter / 2 * _config.TestParameters.PlatinumWireDiameter / 2 / 4.0) * Math.Exp(exponent);
|
||||
|
||||
alpha *= _config.TestParameters.CalibrationCoefficients.ThermalConductivityCorrection;
|
||||
if (_config.TestParameters.UseFixedAlpha)
|
||||
{
|
||||
alpha = _config.TestParameters.FixedAlpha;
|
||||
@@ -572,22 +612,22 @@ public partial class D7896ViewModel : ObservableObject
|
||||
coolingPoints.Add(new DataPoint(time[i], deltaT[i]));
|
||||
|
||||
// 导出CSV
|
||||
try
|
||||
{
|
||||
string tmp = Path.GetTempPath();
|
||||
string baseName = $"measure_{SampleId}_{DateTime.Now:yyyyMMdd_HHmmss}_{CurrentMeasurementIndex}";
|
||||
string dataPath = Path.Combine(tmp, baseName + ".csv");
|
||||
ExportMeasurementCsv(dataPath, time, ustd, upt, deltaT, startIdx, endIdx);
|
||||
Logger.Log($"已导出测量数据 CSV: {dataPath}");
|
||||
//try
|
||||
//{
|
||||
// string tmp = Path.GetTempPath();
|
||||
// string baseName = $"measure_{SampleId}_{DateTime.Now:yyyyMMdd_HHmmss}_{CurrentMeasurementIndex}";
|
||||
// string dataPath = Path.Combine(tmp, baseName + ".csv");
|
||||
// ExportMeasurementCsv(dataPath, time, ustd, upt, deltaT, startIdx, endIdx);
|
||||
// Logger.Log($"已导出测量数据 CSV: {dataPath}");
|
||||
|
||||
string winPath = Path.Combine(tmp, baseName + "_windows.csv");
|
||||
ExportCandidateWindowsCsv(winPath, time, deltaT, startIdx, endIdx);
|
||||
Logger.Log($"已导出候选拟合窗 CSV: {winPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"导出CSV失败: {ex.Message}");
|
||||
}
|
||||
// string winPath = Path.Combine(tmp, baseName + "_windows.csv");
|
||||
// ExportCandidateWindowsCsv(winPath, time, deltaT, startIdx, endIdx);
|
||||
// Logger.Log($"已导出候选拟合窗 CSV: {winPath}");
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// Logger.Log($"导出CSV失败: {ex.Message}");
|
||||
//}
|
||||
|
||||
return (lambda, alpha, deltaT, coolingPoints);
|
||||
}
|
||||
@@ -635,7 +675,7 @@ public partial class D7896ViewModel : ObservableObject
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
bool inFit = (i >= fitStart && i <= fitEnd);
|
||||
sw.WriteLine($"{i},{time[i]:F6},{ustd[i]:F6},{upt[i]:F6},{(double.IsNaN(deltaT[i])?0:deltaT[i]):F6},{(inFit?1:0)}");
|
||||
sw.WriteLine($"{i},{time[i]:F6},{ustd[i]:F6},{upt[i]:F6},{(double.IsNaN(deltaT[i]) ? 0 : deltaT[i]):F6},{(inFit ? 1 : 0)}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,6 +809,40 @@ public partial class D7896ViewModel : ObservableObject
|
||||
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]
|
||||
private async Task GenerateReportAsync()
|
||||
{
|
||||
@@ -777,35 +851,136 @@ public partial class D7896ViewModel : ObservableObject
|
||||
MessageBox.Show("没有测试数据", "提示");
|
||||
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
|
||||
{
|
||||
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}", "成功");
|
||||
// 生成 PDF
|
||||
await Task.Run(() => GeneratePdfReport(pdfPath));
|
||||
MessageBox.Show($"报表已生成: {pdfPath}", "成功");
|
||||
}
|
||||
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]
|
||||
private async Task StopTest()
|
||||
{
|
||||
|
||||
@@ -25,9 +25,12 @@
|
||||
"TestParameters": {
|
||||
"MeasurementCount": 10,
|
||||
"IntervalSeconds": 30,
|
||||
//"PlatinumWireLength": 0.110, //铂丝长度(单位:米)
|
||||
//"PlatinumWireDiameter": 0.000032,
|
||||
//"PlatinumWireLength": 0.056, //铂丝长度(单位:米)
|
||||
"PlatinumWireLength": 0.41, //铂丝长度(单位:米)
|
||||
"PlatinumWireDiameter": 0.000025,
|
||||
//"PlatinumWireDiameter": 0.00006,
|
||||
"PlatinumWireLength": 0.056, //铂丝长度(单位:米)
|
||||
"PlatinumWireDiameter": 0.00006,
|
||||
"ReportOutputPath": "Reports\\",
|
||||
"DefaultSampleVolume": 40.0,
|
||||
"DefaultPressure": 0.0,
|
||||
|
||||
Reference in New Issue
Block a user