This commit is contained in:
xyy
2026-06-16 21:18:46 +08:00
parent 8c0af19f02
commit 4489514b5d
7 changed files with 163 additions and 47 deletions

View File

@@ -1,20 +1,38 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace AciTester.Models;
public partial class StageData : ObservableObject
namespace AciTester.Models
{
[ObservableProperty]
private string stageName = string.Empty;
public partial class StageData : ObservableObject
{
[ObservableProperty]
private string stageName;
[ObservableProperty]
private double cutoffDiameter; // 截止直径 (μm)
[ObservableProperty]
private double cutoffDiameter;
[ObservableProperty]
private double initialWeight; // 测前质量 (g)
private double _initialWeight;
public double InitialWeight
{
get => _initialWeight;
set
{
if (SetProperty(ref _initialWeight, value))
OnPropertyChanged(nameof(NetWeight)); // 关键:通知净重变化
}
}
[ObservableProperty]
private double finalWeight; // 测后质量 (g)
private double _finalWeight;
public double FinalWeight
{
get => _finalWeight;
set
{
if (SetProperty(ref _finalWeight, value))
OnPropertyChanged(nameof(NetWeight)); // 关键:通知净重变化
}
}
public double NetWeight => finalWeight - initialWeight;
// 计算属性,不存储
public double NetWeight => FinalWeight - InitialWeight;
}
}

View File

@@ -11,4 +11,10 @@ public class TestResult
public float Temperature { get; set; }
public float DifferentialPressure { get; set; }
// 新增粒径参数
public double D10 { get; set; }
public double D50 { get; set; } // 即 MMAD
public double D90 { get; set; }
public double GSD { get; set; }
}

View File

@@ -28,7 +28,7 @@ namespace AciTester.Services
sheet.Cells["A5"].Value = "总质量F(g):";
sheet.Cells["B5"].Value = result.TotalMass;
// 在报告生成时添加
// 测试环境
sheet.Cells["A6"].Value = "测试环境:";
sheet.Cells["B6"].Value = $"流量: {result.FlowRate:F2} L/min, 温度: {result.Temperature:F1}℃, 压差: {result.DifferentialPressure:F2} kPa";
@@ -38,14 +38,28 @@ namespace AciTester.Services
sheet.Cells["A8"].Value = "微细粒子分数(FPF)";
sheet.Cells["B8"].Value = $"{result.FineParticleFraction:F2}%";
// 各级数据表
sheet.Cells["A10"].Value = "层级";
sheet.Cells["B10"].Value = "截止直径(μm)";
sheet.Cells["C10"].Value = "净重(g)";
sheet.Cells["D10"].Value = "占比(%)";
sheet.Cells["A10:D10"].Style.Font.Bold = true;
// ============ 新增:粒径分布参数 ============
sheet.Cells["A9"].Value = "粒径分布参数";
sheet.Cells["A9"].Style.Font.Bold = true;
int row = 11;
sheet.Cells["A10"].Value = "D10 (μm)";
sheet.Cells["B10"].Value = result.D10;
sheet.Cells["A11"].Value = "D50 (μm) (MMAD)";
sheet.Cells["B11"].Value = result.D50;
sheet.Cells["A12"].Value = "D90 (μm)";
sheet.Cells["B12"].Value = result.D90;
sheet.Cells["A13"].Value = "GSD (几何标准偏差)";
sheet.Cells["B13"].Value = result.GSD;
// 各级数据表起始行号调整为15
int dataStartRow = 15;
sheet.Cells[dataStartRow, 1].Value = "层级";
sheet.Cells[dataStartRow, 2].Value = "截止直径(μm)";
sheet.Cells[dataStartRow, 3].Value = "净重(g)";
sheet.Cells[dataStartRow, 4].Value = "占比(%)";
sheet.Cells[dataStartRow, 1, dataStartRow, 4].Style.Font.Bold = true;
int row = dataStartRow + 1;
double total = result.TotalMass;
foreach (var stage in result.Stages)
{

View File

@@ -88,10 +88,14 @@ namespace AciTester.Services
public async Task<bool> ReadCoilAsync(ushort coilAddress)
{
await EnsureConnectedAsync();
await Task.Delay(100);
bool[] result = await _master?.ReadCoilsAsync(_config.SlaveId, coilAddress, 1);
return result[0];
try
{
await EnsureConnectedAsync();
await Task.Delay(100);
bool[] result = await _master?.ReadCoilsAsync(_config.SlaveId, coilAddress, 1);
return result[0];
}
catch { return false; }
}
public bool IsConnected => _tcpClient != null && _tcpClient.Connected;

View File

@@ -140,6 +140,7 @@ namespace AciTester.ViewModels
};
}
public IAsyncRelayCommand StopTestCommand { get; }
public IAsyncRelayCommand ConnectCommand { get; }
public IRelayCommand DisconnectCommand { get; }
@@ -403,7 +404,8 @@ namespace AciTester.ViewModels
IsTesting = true;
_testCts = new CancellationTokenSource();
//StopTestCommand.NotifyCanExecuteChanged();
StopTestCommand.NotifyCanExecuteChanged();
try
{
await _plcService.WriteCoilAsync(_config.PumpCoil, true);
@@ -448,17 +450,68 @@ namespace AciTester.ViewModels
return;
}
// 1. 计算各级占比和累积分布
// 注意Stages[0] ~ Stages[7] 对应 Stage0~Stage7Stages[8] 是 Filter
// 截止直径数组(与 Stages 的顺序一致)
double[] diamArray = new double[9];
for (int i = 0; i < 9; i++)
diamArray[i] = Stages[i].CutoffDiameter;
// 占比和累积分布
double[] percentages = new double[9];
double[] cumulatives = new double[9];
double sum = 0;
for (int i = 0; i < 9; i++)
{
percentages[i] = Stages[i].NetWeight / totalMass * 100;
sum += percentages[i];
cumulatives[i] = sum;
}
// 2. 插值函数:给定累积百分比,返回对应的粒径(对数线性插值)
double Interpolate(double targetCum)
{
if (targetCum <= cumulatives[0]) return diamArray[0];
if (targetCum >= cumulatives[8]) return diamArray[8];
for (int i = 0; i < 8; i++)
{
if (cumulatives[i] <= targetCum && cumulatives[i + 1] >= targetCum)
{
double d1 = diamArray[i];
double d2 = diamArray[i + 1];
double c1 = cumulatives[i];
double c2 = cumulatives[i + 1];
double logD1 = Math.Log(d1);
double logD2 = Math.Log(d2);
double logD = logD1 + (targetCum - c1) * (logD2 - logD1) / (c2 - c1);
return Math.Exp(logD);
}
}
return diamArray[8];
}
double d10 = Interpolate(10);
double d50 = Interpolate(50);
double d90 = Interpolate(90);
// 3. 计算 GSD几何标准偏差GSD = D84 / D16如果可用
double d16 = Interpolate(16);
double d84 = Interpolate(84);
double gsd = (d16 > 0 && d84 > 0) ? d84 / d16 : 0;
// 4. 计算微细粒子剂量和分数(原有逻辑)
double fineMass = 0;
foreach (var stage in Stages)
{
if (stage.CutoffDiameter <= 5.0 && stage.CutoffDiameter > 0)
fineMass += stage.NetWeight;
}
fineMass += Stages[8].NetWeight;
fineMass += Stages[8].NetWeight; // Filter
double fpd = fineMass * 1000;
double fpd = fineMass * 1000; // mg
double fpf = (fineMass / totalMass) * 100;
// 5. 赋值给 CurrentResult
CurrentResult = new TestResult
{
TestTime = DateTime.Now,
@@ -468,10 +521,15 @@ namespace AciTester.ViewModels
Stages = Stages.ToList(),
FlowRate = CurrentFlow,
Temperature = RealTime.Temperature,
DifferentialPressure = RealTime.DifferentialPressure
DifferentialPressure = RealTime.DifferentialPressure,
// 新增粒径参数
D10 = d10,
D50 = d50,
D90 = d90,
GSD = gsd
};
MessageBox.Show($"计算完成\n总质量: {totalMass:F4} g\n微细粒子剂量: {fpd:F2} mg\n微细粒子分数: {fpf:F2}%",
MessageBox.Show($"计算完成\n总质量: {totalMass:F4} g\n微细粒子剂量: {fpd:F2} mg\n微细粒子分数: {fpf:F2}%\nD50: {d50:F2} μm",
"计算结果", MessageBoxButton.OK, MessageBoxImage.Information);
}

View File

@@ -18,10 +18,10 @@
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="流量系数:" Width="80" VerticalAlignment="Center"/>
<TextBox Text="{Binding Calibration.FlowCalibration}" Width="100"/>
<TextBlock Text=" 保护低限:" Margin="20,0,0,0"/>
<!--<TextBlock Text="保护低限:" Margin="20,0,0,0"/>
<TextBox Text="{Binding Calibration.FlowLowLimit}" Width="80"/>
<TextBlock Text="高限:" Margin="5,0,0,0"/>
<TextBox Text="{Binding Calibration.FlowHighLimit}" Width="80"/>
<TextBox Text="{Binding Calibration.FlowHighLimit}" Width="80"/>-->
</StackPanel>
</GroupBox>
<GroupBox Header="温度校准" Grid.Row="1" Margin="0,10">

View File

@@ -237,14 +237,14 @@
<Button Command="{Binding StartPumpCommand}" Content="启泵(M6)" Width="70" Height="30" Margin="2" Background="#2ECC71" Foreground="White"/>
<Button Command="{Binding StopPumpCommand}" Content="停泵(M6)" Width="70" Height="30" Margin="2" Background="#E67E22" Foreground="White"/>
</StackPanel>
</StackPanel>
</Border>
<!-- 自动测试按钮 -->
<Button Command="{Binding StartTestCommand}" Content="开始测试" Height="45" Margin="0,10,0,0" IsEnabled="{Binding IsTesting, Converter={StaticResource InverseBoolConverter}}"/>
<TextBlock Text="测试进行中..." Visibility="{Binding IsTesting, Converter={StaticResource BoolToVisibilityConverter}}" Foreground="Orange" FontWeight="Bold" FontSize="14" Margin="0,5,0,0" HorizontalAlignment="Center"/>
<Button Command="{Binding StopTestCommand}" Content="停止测试" Height="45" Margin="0,10,0,0" Background="#E74C3C" Foreground="White" />
<Button Visibility="Visible" IsEnabled="True" Command="{Binding StopTestCommand}" Content="停止测试" Height="45" Margin="0,10,0,0" Background="#E74C3C" />
</StackPanel>
</GroupBox>
<GroupBox Header="数据分析">
@@ -264,20 +264,12 @@
<DataGrid.Columns>
<DataGridTextColumn Header="层级" Binding="{Binding StageName}" Width="80" IsReadOnly="True"/>
<DataGridTextColumn Header="截止直径(μm)" Binding="{Binding CutoffDiameter, StringFormat='{}{0:F1}'}" Width="100" IsReadOnly="True"/>
<DataGridTextColumn Header="测前质量(g)" Binding="{Binding InitialWeight, StringFormat='{}{0:F4}'}" Width="120">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="测后质量(g)" Binding="{Binding FinalWeight, StringFormat='{}{0:F4}'}" Width="120">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="测前质量(g)"
Binding="{Binding InitialWeight, UpdateSourceTrigger=LostFocus, Delay=300, StringFormat='{}{0:F4}'}"
Width="120"/>
<DataGridTextColumn Header="测后质量(g)"
Binding="{Binding FinalWeight, UpdateSourceTrigger=LostFocus, Delay=300, StringFormat='{}{0:F4}'}"
Width="120"/>
<DataGridTextColumn Header="净重(g)" Binding="{Binding NetWeight, StringFormat='{}{0:F6}'}" Width="120" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
@@ -298,6 +290,30 @@
<TextBlock Text="{Binding CurrentResult.FineParticleDose, StringFormat='{}{0:F2} mg'}" FontSize="16" FontWeight="Bold" Foreground="#1565C0" Margin="5,0,30,0"/>
<TextBlock Text="微细粒子分数(FPF): " FontWeight="Bold" FontSize="16"/>
<TextBlock Text="{Binding CurrentResult.FineParticleFraction, StringFormat='{}{0:F2} %'}" FontSize="16" FontWeight="Bold" Foreground="#1565C0"/>
<TextBlock Text="FPD: " FontWeight="Bold" FontSize="14"/>
<TextBlock Text="{Binding CurrentResult.FineParticleDose, StringFormat='{}{0:F2} mg'}" FontSize="14" Margin="0,0,20,0"/>
<TextBlock Text="FPF: " FontWeight="Bold" FontSize="14"/>
<TextBlock Text="{Binding CurrentResult.FineParticleFraction, StringFormat='{}{0:F2} %'}" FontSize="14" Margin="0,0,20,0"/>
<TextBlock Text="D10: " FontWeight="Bold" FontSize="14"/>
<TextBlock Text="{Binding CurrentResult.D10, StringFormat='{}{0:F2} μm'}" FontSize="14" Margin="0,0,20,0"/>
<TextBlock Text="D50: " FontWeight="Bold" FontSize="14"/>
<TextBlock Text="{Binding CurrentResult.D50, StringFormat='{}{0:F2} μm'}" FontSize="14" Margin="0,0,20,0"/>
<TextBlock Text="D90: " FontWeight="Bold" FontSize="14"/>
<TextBlock Text="{Binding CurrentResult.D90, StringFormat='{}{0:F2} μm'}" FontSize="14" Margin="0,0,20,0"/>
<TextBlock Text="GSD: " FontWeight="Bold" FontSize="14"/>
<TextBlock Text="{Binding CurrentResult.GSD, StringFormat='{}{0:F3}'}" FontSize="14"/>
</StackPanel>
</Border>
</Grid>