This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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~Stage7,Stages[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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user