无塌陷
This commit is contained in:
@@ -274,6 +274,27 @@
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="填写说明" />
|
||||
<TextBlock Margin="0,0,0,6" Foreground="{StaticResource MutedTextBrush}" FontSize="13" Text="{Binding RealtimeMeasurementHint}" TextWrapping="Wrap" />
|
||||
<Border Margin="0,0,0,8" Padding="12" Background="#FFF8F4EA" CornerRadius="14">
|
||||
<StackPanel>
|
||||
<StackPanel.Style>
|
||||
<Style TargetType="StackPanel">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsAntiCollapseSelected}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</StackPanel.Style>
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="抗塌陷快速采样" />
|
||||
<TextBlock FontSize="13" Text="{Binding AntiCollapseBaselineDisplay}" TextWrapping="Wrap" />
|
||||
<TextBlock Margin="0,4,0,0" FontSize="13" Text="{Binding AntiCollapseComparisonDisplay}" TextWrapping="Wrap" />
|
||||
<WrapPanel Margin="0,8,0,0">
|
||||
<Button Command="{Binding CaptureAntiCollapseBaselineCommand}" Content="采集基线" Background="#FF6B8791" />
|
||||
<Button Command="{Binding CaptureAntiCollapseComparisonCommand}" Content="采集负压比较" Background="#FFE0A14A" />
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<TextBox Text="{Binding ResultValue, UpdateSourceTrigger=PropertyChanged}" MinHeight="104" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" IsReadOnly="{Binding SelectedItemUsesRealtimeValue}" />
|
||||
<TextBlock Style="{StaticResource CaptionStyle}" Text="判定" />
|
||||
<ComboBox ItemsSource="{Binding ResultStatusOptions}" SelectedItem="{Binding SelectedResultStatusText, Mode=TwoWay}" />
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
using Cardiopulmonarybypasssystems.Models;
|
||||
using System.Net.Sockets;
|
||||
using Cardiopulmonarybypasssystems.Models;
|
||||
using NModbus;
|
||||
|
||||
namespace Cardiopulmonarybypasssystems.Services;
|
||||
|
||||
public sealed class MockModbusTelemetryService : IModbusTelemetryService
|
||||
public sealed class MockModbusTelemetryService : IModbusTelemetryService, IDisposable
|
||||
{
|
||||
private const string IpAddress = "192.168.1.10";
|
||||
private const int Port = 502;
|
||||
private const byte SlaveId = 1;
|
||||
private const ushort ProximalPressureRegister = 1330;
|
||||
private const ushort DistalPressureRegister = 1380;
|
||||
|
||||
private readonly object _syncRoot = new();
|
||||
private readonly Random _random = new();
|
||||
private readonly ModbusFactory _factory = new();
|
||||
private readonly List<DeviceChannel> _channels =
|
||||
@@ -12,8 +20,8 @@ public sealed class MockModbusTelemetryService : IModbusTelemetryService
|
||||
new() { Name = "主泵流量", Unit = "L/min", Value = 4.82, Min = 0, Max = 7 },
|
||||
new() { Name = "静脉引流流量", Unit = "L/min", Value = 4.54, Min = 0, Max = 7 },
|
||||
new() { Name = "动脉回输流量", Unit = "L/min", Value = 4.86, Min = 0, Max = 7 },
|
||||
new() { Name = "入口压力", Unit = "mmHg", Value = 112, Min = 60, Max = 220 },
|
||||
new() { Name = "出口压力", Unit = "mmHg", Value = 94, Min = 40, Max = 180 },
|
||||
new() { Name = "远端压力", Unit = "mmHg", Value = 94, Min = 40, Max = 180 },
|
||||
new() { Name = "近端压力", Unit = "mmHg", Value = 112, Min = 60, Max = 220 },
|
||||
new() { Name = "负压辅助引流", Unit = "kPa", Value = -10.4, Min = -20, Max = 0 },
|
||||
new() { Name = "模拟血液温度", Unit = "°C", Value = 37.1, Min = 34, Max = 40 },
|
||||
new() { Name = "再循环率", Unit = "%", Value = 6.8, Min = 0, Max = 20 },
|
||||
@@ -21,29 +29,24 @@ public sealed class MockModbusTelemetryService : IModbusTelemetryService
|
||||
new() { Name = "白细胞减少率", Unit = "%", Value = 7.1, Min = 0, Max = 20 }
|
||||
];
|
||||
|
||||
public IReadOnlyList<DeviceChannel> GetChannels() => _channels;
|
||||
private TcpClient? _tcpClient;
|
||||
private IModbusMaster? _master;
|
||||
private bool _connectionInitialized;
|
||||
|
||||
public IReadOnlyList<DeviceChannel> GetChannels()
|
||||
{
|
||||
EnsureConnected();
|
||||
return _channels;
|
||||
}
|
||||
|
||||
public IReadOnlyList<AlarmMessage> UpdateChannels()
|
||||
{
|
||||
_ = _factory;
|
||||
EnsureConnected();
|
||||
|
||||
foreach (var channel in _channels)
|
||||
lock (_syncRoot)
|
||||
{
|
||||
var offset = channel.Name switch
|
||||
{
|
||||
"主泵流量" => Next(-0.08, 0.08),
|
||||
"静脉引流流量" => Next(-0.08, 0.08),
|
||||
"动脉回输流量" => Next(-0.06, 0.06),
|
||||
"入口压力" => Next(-3.0, 3.0),
|
||||
"出口压力" => Next(-2.5, 2.5),
|
||||
"负压辅助引流" => Next(-0.6, 0.6),
|
||||
"模拟血液温度" => Next(-0.15, 0.15),
|
||||
"游离血红蛋白" => Next(-0.003, 0.003),
|
||||
_ => Next(-0.5, 0.5)
|
||||
};
|
||||
|
||||
channel.Value = Math.Clamp(channel.Value + offset, channel.Min, channel.Max);
|
||||
}
|
||||
TryReadPressureChannels();
|
||||
SimulateAuxiliaryChannels();
|
||||
|
||||
var pumpFlow = Channel("主泵流量");
|
||||
var drainageFlow = Channel("静脉引流流量");
|
||||
@@ -63,16 +66,129 @@ public sealed class MockModbusTelemetryService : IModbusTelemetryService
|
||||
: Math.Clamp((returnFlow.Value - drainageFlow.Value) / returnFlow.Value * 100d, 0d, 100d);
|
||||
Channel("再循环率").Value = recirculationRate;
|
||||
|
||||
var alarms = new List<AlarmMessage>();
|
||||
return BuildAlarms();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_master?.Dispose();
|
||||
_tcpClient?.Dispose();
|
||||
_master = null;
|
||||
_tcpClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureConnected()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_master is not null && _tcpClient?.Connected == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Dispose();
|
||||
|
||||
try
|
||||
{
|
||||
_tcpClient = new TcpClient();
|
||||
_tcpClient.Connect(IpAddress, Port);
|
||||
_master = _factory.CreateMaster(_tcpClient);
|
||||
_connectionInitialized = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_master = null;
|
||||
_tcpClient?.Dispose();
|
||||
_tcpClient = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TryReadPressureChannels()
|
||||
{
|
||||
if (_master is null)
|
||||
{
|
||||
SimulatePressureChannels();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var proximalRaw = _master.ReadHoldingRegisters(SlaveId, ProximalPressureRegister, 1)[0];
|
||||
var distalRaw = _master.ReadHoldingRegisters(SlaveId, DistalPressureRegister, 1)[0];
|
||||
|
||||
Channel("近端压力").Value = ConvertRegisterToPressure(proximalRaw, Channel("近端压力"));
|
||||
Channel("远端压力").Value = ConvertRegisterToPressure(distalRaw, Channel("远端压力"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
SimulatePressureChannels();
|
||||
}
|
||||
}
|
||||
|
||||
private void SimulateAuxiliaryChannels()
|
||||
{
|
||||
foreach (var channel in _channels.Where(channel => channel.Name is not "近端压力" and not "远端压力"))
|
||||
{
|
||||
var offset = channel.Name switch
|
||||
{
|
||||
"主泵流量" => Next(-0.08, 0.08),
|
||||
"静脉引流流量" => Next(-0.08, 0.08),
|
||||
"动脉回输流量" => Next(-0.06, 0.06),
|
||||
"负压辅助引流" => Next(-0.6, 0.6),
|
||||
"模拟血液温度" => Next(-0.15, 0.15),
|
||||
"游离血红蛋白" => Next(-0.003, 0.003),
|
||||
_ => Next(-0.5, 0.5)
|
||||
};
|
||||
|
||||
channel.Value = Math.Clamp(channel.Value + offset, channel.Min, channel.Max);
|
||||
}
|
||||
}
|
||||
|
||||
private void SimulatePressureChannels()
|
||||
{
|
||||
var proximal = Channel("近端压力");
|
||||
var distal = Channel("远端压力");
|
||||
|
||||
proximal.Value = Math.Clamp(proximal.Value + Next(-3.0, 3.0), proximal.Min, proximal.Max);
|
||||
distal.Value = Math.Clamp(distal.Value + Next(-2.5, 2.5), distal.Min, distal.Max);
|
||||
|
||||
if (distal.Value > proximal.Value - 2)
|
||||
{
|
||||
distal.Value = Math.Max(distal.Min, proximal.Value - Next(6, 18));
|
||||
}
|
||||
}
|
||||
|
||||
private List<AlarmMessage> BuildAlarms()
|
||||
{
|
||||
var alarms = new List<AlarmMessage>();
|
||||
var deltaPressure = Channel("近端压力").Value - Channel("远端压力").Value;
|
||||
var recirculationRate = Channel("再循环率").Value;
|
||||
var pumpFlow = Channel("主泵流量").Value;
|
||||
var returnFlow = Channel("动脉回输流量").Value;
|
||||
|
||||
var deltaPressure = Channel("入口压力").Value - Channel("出口压力").Value;
|
||||
if (deltaPressure > 24)
|
||||
{
|
||||
alarms.Add(new AlarmMessage
|
||||
{
|
||||
Timestamp = DateTime.Now,
|
||||
Level = "高",
|
||||
Message = $"压差 {deltaPressure:F1} mmHg,接近 4.3.1 压力降上限"
|
||||
Message = $"压力降 ΔP {deltaPressure:F1} mmHg 偏高,请复核近端/远端压力与流量点"
|
||||
});
|
||||
}
|
||||
|
||||
if (!_connectionInitialized || _master is null)
|
||||
{
|
||||
alarms.Add(new AlarmMessage
|
||||
{
|
||||
Timestamp = DateTime.Now,
|
||||
Level = "中",
|
||||
Message = $"ModbusTcp 未连接,当前使用本地模拟压力数据。目标 {IpAddress}:{Port}"
|
||||
});
|
||||
}
|
||||
|
||||
@@ -86,13 +202,13 @@ public sealed class MockModbusTelemetryService : IModbusTelemetryService
|
||||
});
|
||||
}
|
||||
|
||||
if (Math.Abs(pumpFlow.Value - returnFlow.Value) > 0.35)
|
||||
if (Math.Abs(pumpFlow - returnFlow) > 0.35)
|
||||
{
|
||||
alarms.Add(new AlarmMessage
|
||||
{
|
||||
Timestamp = DateTime.Now,
|
||||
Level = "中",
|
||||
Message = $"主泵/回输流量差 {Math.Abs(pumpFlow.Value - returnFlow.Value):F2} L/min,建议检查流量传感器标定"
|
||||
Message = $"主泵/回输流量差 {Math.Abs(pumpFlow - returnFlow):F2} L/min,建议检查流量传感器标定"
|
||||
});
|
||||
}
|
||||
|
||||
@@ -109,6 +225,12 @@ public sealed class MockModbusTelemetryService : IModbusTelemetryService
|
||||
return alarms;
|
||||
}
|
||||
|
||||
private static double ConvertRegisterToPressure(ushort rawValue, DeviceChannel channel)
|
||||
{
|
||||
var signedValue = rawValue > short.MaxValue ? rawValue - 65536 : rawValue;
|
||||
return Math.Clamp(signedValue, channel.Min, channel.Max);
|
||||
}
|
||||
|
||||
private DeviceChannel Channel(string name) => _channels.First(channel => channel.Name == name);
|
||||
|
||||
private double Next(double min, double max) => min + (_random.NextDouble() * (max - min));
|
||||
|
||||
@@ -24,25 +24,25 @@ public sealed class StandardRepository : IStandardRepository
|
||||
Category = "性能特征",
|
||||
Item = "压力降",
|
||||
AcceptanceCriteria = "在模拟血液黏度 3.2 mPa·s ± 0.2 mPa·s、37 ℃ ± 2 ℃ 条件下,于最大标称流量的 50%、75%、100% 流量点测得的压力降应在制造商声明范围内。",
|
||||
TestMethod = "使用最终灭菌成品接入循环回路并排尽气泡;在模拟血液黏度 3.2 mPa·s ± 0.2 mPa·s、37 ℃ ± 2 ℃ 条件下,于 50%、75%、100% 最大标称流量分别测量入口和出口压力,计算压力降并评定。",
|
||||
RecordFocus = "记录试验条件、流量点、入口/出口压力、压力降 ΔP 及判定结果",
|
||||
TestMethod = "使用最终灭菌成品接入循环回路并排尽气泡;在模拟血液黏度 3.2 mPa·s ± 0.2 mPa·s、37 ℃ ± 2 ℃ 条件下,于 50%、75%、100% 最大标称流量分别测量近端和远端压力,计算压力降并评定。",
|
||||
RecordFocus = "记录试验条件、流量点、近端/远端压力、压力降 ΔP 及判定结果",
|
||||
CaptureMode = InspectionItemCaptureMode.RealtimeMonitor,
|
||||
MeasurementSource = "主泵流量、入口/出口压力、模拟血液温度传感器",
|
||||
MeasurementSource = "主泵流量、近端/远端压力、模拟血液温度传感器",
|
||||
ManualEntryHint = "该项目由实时压力信号自动采集,无需人工重复填写。",
|
||||
LiveDisplayHint = "实时显示试验温度、当前流量、50%/75%/100% 标称流量点及入口/出口压力,用于记录压力降试验。"
|
||||
LiveDisplayHint = "实时显示试验温度、当前流量、50%/75%/100% 标称流量点及近端/远端压力,用于记录压力降试验。"
|
||||
},
|
||||
new()
|
||||
{
|
||||
Clause = "4.3.2",
|
||||
Category = "性能特征",
|
||||
Item = "抗塌陷",
|
||||
AcceptanceCriteria = "负压后压降增量不超过 40%。",
|
||||
TestMethod = "施加负压后比较压差增量和流量变化;判定压降增量不超过限值。",
|
||||
RecordFocus = "记录负压与压差变化",
|
||||
AcceptanceCriteria = "对引流插管,在远端施加 -6.67 kPa 负压后,由插管引起的压力降增加值不应超过基线值的 50%。",
|
||||
TestMethod = "使用模拟血液(2.0~3.5 mPa·s)在 37 ℃ ± 2 ℃ 条件下,先于制造商规定的最大血流量测量基线压力降,再在相同流量条件下于远端施加 -6.67 kPa 负压,比较压力降增加值。",
|
||||
RecordFocus = "记录基线压力降、负压加载后压力降、增加值、增加率及比较结论",
|
||||
CaptureMode = InspectionItemCaptureMode.RealtimeAssist,
|
||||
MeasurementSource = "负压辅助引流、入口/出口压差趋势",
|
||||
ManualEntryHint = "系统实时显示负压与压差趋势,最终结论仍由检测员根据检测记录手动填写。",
|
||||
LiveDisplayHint = "建议结合负压、压差增量和流量变化综合判定是否塌陷。"
|
||||
MeasurementSource = "负压辅助引流、近端/远端压力、主泵流量、模拟血液温度",
|
||||
ManualEntryHint = "系统自动给出基线、负压后压力降和增幅比较建议,最终结论仍由检测员确认保存。",
|
||||
LiveDisplayHint = "建议先采集无负压基线,再施加 -6.67 kPa 负压比较压力降增幅。"
|
||||
},
|
||||
new()
|
||||
{
|
||||
|
||||
@@ -13,6 +13,12 @@ public partial class MainViewModel : ObservableObject
|
||||
{
|
||||
private readonly IModbusTelemetryService _telemetryService;
|
||||
private readonly DispatcherTimer _timer;
|
||||
private const double AntiCollapseTargetNegativePressure = -6.67;
|
||||
private double? _antiCollapseBaselinePressureDrop;
|
||||
private double? _antiCollapseBaselineFlow;
|
||||
private DateTime? _antiCollapseBaselineCapturedAt;
|
||||
private string _lastAutoAntiCollapseResult = string.Empty;
|
||||
private string _lastAutoAntiCollapseNote = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string pageTitle = "心肺转流系统一次性使用动静脉插管检测";
|
||||
@@ -152,6 +158,21 @@ public partial class MainViewModel : ObservableObject
|
||||
public string PressureDropConditionDisplay => $"模拟血液 3.2±0.2 mPa·s / {TemperatureDisplay} / 最终灭菌成品";
|
||||
public string PressureDropFlowPointDisplay =>
|
||||
$"50%={PressureDropFlowPoint(0.50):F2} L/min / 75%={PressureDropFlowPoint(0.75):F2} L/min / 100%={PressureDropFlowPoint(1.00):F2} L/min";
|
||||
public bool IsAntiCollapseSelected => SelectedItem?.Clause == "4.3.2";
|
||||
public bool HasAntiCollapseBaseline => _antiCollapseBaselinePressureDrop.HasValue && _antiCollapseBaselineFlow.HasValue;
|
||||
public string AntiCollapseBaselineDisplay => HasAntiCollapseBaseline
|
||||
? $"基线 ΔP {_antiCollapseBaselinePressureDrop:F1} mmHg / 流量 {_antiCollapseBaselineFlow:F2} L/min / 时间 {_antiCollapseBaselineCapturedAt:HH:mm:ss}"
|
||||
: "尚未采集基线";
|
||||
public string AntiCollapseComparisonDisplay
|
||||
{
|
||||
get
|
||||
{
|
||||
var comparison = GetAntiCollapseComparison();
|
||||
return comparison.HasBaseline
|
||||
? $"当前 ΔP {DeltaPressure:F1} mmHg,较基线增加 {comparison.Increase:F1} mmHg ({comparison.IncreaseRate:F1}%),{comparison.StatusText}"
|
||||
: "请先在无负压条件下采集基线,再进行负压比较";
|
||||
}
|
||||
}
|
||||
|
||||
public double PumpFlow => ChannelValue("主泵流量");
|
||||
public double DrainageFlow => ChannelValue("静脉引流流量");
|
||||
@@ -185,6 +206,10 @@ public partial class MainViewModel : ObservableObject
|
||||
OnPropertyChanged(nameof(SelectedItemCaptureModeText));
|
||||
OnPropertyChanged(nameof(SelectedItemMeasurementSource));
|
||||
OnPropertyChanged(nameof(SelectedItemUsesRealtimeValue));
|
||||
OnPropertyChanged(nameof(IsAntiCollapseSelected));
|
||||
OnPropertyChanged(nameof(HasAntiCollapseBaseline));
|
||||
OnPropertyChanged(nameof(AntiCollapseBaselineDisplay));
|
||||
OnPropertyChanged(nameof(AntiCollapseComparisonDisplay));
|
||||
OnPropertyChanged(nameof(RealtimeMeasurementHint));
|
||||
OnPropertyChanged(nameof(SelectedItemLiveDisplay));
|
||||
OnPropertyChanged(nameof(SelectedItemLiveHint));
|
||||
@@ -211,6 +236,65 @@ public partial class MainViewModel : ObservableObject
|
||||
ItemSearchText = string.Empty;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CaptureAntiCollapseBaseline()
|
||||
{
|
||||
if (!IsAntiCollapseSelected)
|
||||
{
|
||||
LatestAction = "当前选择的不是抗塌陷项目。";
|
||||
return;
|
||||
}
|
||||
|
||||
_antiCollapseBaselinePressureDrop = DeltaPressure;
|
||||
_antiCollapseBaselineFlow = PumpFlow;
|
||||
_antiCollapseBaselineCapturedAt = DateTime.Now;
|
||||
_lastAutoAntiCollapseResult = string.Empty;
|
||||
_lastAutoAntiCollapseNote = string.Empty;
|
||||
|
||||
var baselineText = BuildAntiCollapseMeasuredText();
|
||||
var noteText = BuildAntiCollapseRecordNote();
|
||||
ResultValue = baselineText;
|
||||
ResultNote = noteText;
|
||||
LatestAction = $"已采集抗塌陷基线:ΔP {DeltaPressure:F1} mmHg,流量 {PumpFlow:F2} L/min。";
|
||||
TraceEvents.Insert(0, NewTrace("抗塌陷基线", $"ΔP {DeltaPressure:F1} mmHg / 流量 {PumpFlow:F2} L/min"));
|
||||
|
||||
OnPropertyChanged(nameof(HasAntiCollapseBaseline));
|
||||
OnPropertyChanged(nameof(AntiCollapseBaselineDisplay));
|
||||
OnPropertyChanged(nameof(AntiCollapseComparisonDisplay));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CaptureAntiCollapseComparison()
|
||||
{
|
||||
if (!IsAntiCollapseSelected)
|
||||
{
|
||||
LatestAction = "当前选择的不是抗塌陷项目。";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasAntiCollapseBaseline)
|
||||
{
|
||||
LatestAction = "请先采集抗塌陷基线。";
|
||||
return;
|
||||
}
|
||||
|
||||
var resultText = BuildAntiCollapseMeasuredText();
|
||||
var noteText = BuildAntiCollapseRecordNote();
|
||||
var comparison = GetAntiCollapseComparison();
|
||||
|
||||
ResultValue = resultText;
|
||||
ResultNote = noteText;
|
||||
SelectedResultStatusText = comparison.StatusText.StartsWith("合格", StringComparison.Ordinal) ? "合格"
|
||||
: comparison.StatusText.StartsWith("预警", StringComparison.Ordinal) ? "预警"
|
||||
: "不合格";
|
||||
_lastAutoAntiCollapseResult = resultText;
|
||||
_lastAutoAntiCollapseNote = noteText;
|
||||
LatestAction = $"已采集抗塌陷负压比较:增幅 {comparison.IncreaseRate:F1}% ,{comparison.StatusText}。";
|
||||
TraceEvents.Insert(0, NewTrace("抗塌陷比较", $"增量 {comparison.Increase:F1} mmHg / 增幅 {comparison.IncreaseRate:F1}%"));
|
||||
|
||||
OnPropertyChanged(nameof(AntiCollapseComparisonDisplay));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ToggleAcquisition()
|
||||
{
|
||||
@@ -387,9 +471,9 @@ public partial class MainViewModel : ObservableObject
|
||||
|
||||
private void RefreshTelemetryPanel()
|
||||
{
|
||||
var inletPressure = Channels.First(c => c.Name == "入口压力").Value;
|
||||
var outletPressure = Channels.First(c => c.Name == "出口压力").Value;
|
||||
DeltaPressure = inletPressure - outletPressure;
|
||||
var distalPressure = Channels.First(c => c.Name == "远端压力").Value;
|
||||
var proximalPressure = Channels.First(c => c.Name == "近端压力").Value;
|
||||
DeltaPressure = proximalPressure - distalPressure;
|
||||
OnPropertyChanged(nameof(PumpFlow));
|
||||
OnPropertyChanged(nameof(DrainageFlow));
|
||||
OnPropertyChanged(nameof(ReturnFlow));
|
||||
@@ -405,6 +489,7 @@ public partial class MainViewModel : ObservableObject
|
||||
OnPropertyChanged(nameof(WhiteCellLossDisplay));
|
||||
OnPropertyChanged(nameof(PressureDropConditionDisplay));
|
||||
OnPropertyChanged(nameof(PressureDropFlowPointDisplay));
|
||||
OnPropertyChanged(nameof(AntiCollapseComparisonDisplay));
|
||||
OnPropertyChanged(nameof(PumpFlowLoadDisplay));
|
||||
OnPropertyChanged(nameof(DrainageFlowLoadDisplay));
|
||||
OnPropertyChanged(nameof(ReturnFlowLoadDisplay));
|
||||
@@ -489,6 +574,31 @@ public partial class MainViewModel : ObservableObject
|
||||
pressureItem.Status = pressureStatus;
|
||||
}
|
||||
|
||||
var antiCollapseItem = InspectionItems.FirstOrDefault(item => item.Clause == "4.3.2");
|
||||
if (antiCollapseItem is not null)
|
||||
{
|
||||
UpdateAntiCollapseBaseline();
|
||||
|
||||
if (SelectedItem == antiCollapseItem)
|
||||
{
|
||||
var suggestedResult = BuildAntiCollapseMeasuredText();
|
||||
var suggestedNote = BuildAntiCollapseRecordNote();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ResultValue) || ResultValue == _lastAutoAntiCollapseResult)
|
||||
{
|
||||
ResultValue = suggestedResult;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ResultNote) || ResultNote == _lastAutoAntiCollapseNote)
|
||||
{
|
||||
ResultNote = suggestedNote;
|
||||
}
|
||||
|
||||
_lastAutoAntiCollapseResult = suggestedResult;
|
||||
_lastAutoAntiCollapseNote = suggestedNote;
|
||||
}
|
||||
}
|
||||
|
||||
var recirculationItem = InspectionItems.FirstOrDefault(item => item.Clause == "4.3.3");
|
||||
if (recirculationItem is null)
|
||||
{
|
||||
@@ -601,7 +711,7 @@ public partial class MainViewModel : ObservableObject
|
||||
return (SelectedItem.Clause, SelectedItem.Item) switch
|
||||
{
|
||||
("4.3.1", _) => BuildPressureDropLiveDisplay(),
|
||||
("4.3.2", _) => $"负压 {ChannelValue("负压辅助引流"):F1} kPa / 压差 {DeltaPressure:F1} mmHg / 流量差 {Math.Abs(PumpFlow - ReturnFlow):F2} L/min",
|
||||
("4.3.2", _) => BuildAntiCollapseLiveDisplay(),
|
||||
("4.3.3", _) => $"再循环率 {RecirculationRate:F1}% / 引流 {DrainageFlow:F2} / 回输 {ReturnFlow:F2} L/min",
|
||||
("4.3.4", "血细胞破坏") => $"游离血红蛋白 {ChannelValue("游离血红蛋白"):F3} g/L / 温度 {ChannelValue("模拟血液温度"):F1} °C",
|
||||
("4.3.4", "血小板/白细胞减少率") => $"白细胞减少率 {ChannelValue("白细胞减少率"):F1}% / 温度 {ChannelValue("模拟血液温度"):F1} °C",
|
||||
@@ -611,13 +721,13 @@ public partial class MainViewModel : ObservableObject
|
||||
|
||||
private string BuildPressureDropMeasuredText()
|
||||
{
|
||||
var inletPressure = ChannelValue("入口压力");
|
||||
var outletPressure = ChannelValue("出口压力");
|
||||
var distalPressure = ChannelValue("远端压力");
|
||||
var proximalPressure = ChannelValue("近端压力");
|
||||
|
||||
return
|
||||
$"试验条件:{PressureDropConditionDisplay}\n" +
|
||||
$"流量点:{PressureDropFlowPointDisplay};当前 {PumpFlow:F2} L/min\n" +
|
||||
$"压力测量:入口 {inletPressure:F1} mmHg;出口 {outletPressure:F1} mmHg\n" +
|
||||
$"压力测量:近端 {proximalPressure:F1} mmHg;远端 {distalPressure:F1} mmHg\n" +
|
||||
$"压力降 ΔP:{DeltaPressure:F1} mmHg";
|
||||
}
|
||||
|
||||
@@ -641,9 +751,99 @@ public partial class MainViewModel : ObservableObject
|
||||
return
|
||||
$"条件:{PressureDropConditionDisplay}\n" +
|
||||
$"流量点:{PressureDropFlowPointDisplay}\n" +
|
||||
$"当前:主泵 {PumpFlow:F2} L/min / 入口 {ChannelValue("入口压力"):F1} mmHg / 出口 {ChannelValue("出口压力"):F1} mmHg / ΔP {DeltaPressure:F1} mmHg";
|
||||
$"当前:主泵 {PumpFlow:F2} L/min / 近端 {ChannelValue("近端压力"):F1} mmHg / 远端 {ChannelValue("远端压力"):F1} mmHg / ΔP {DeltaPressure:F1} mmHg";
|
||||
}
|
||||
|
||||
private void UpdateAntiCollapseBaseline()
|
||||
{
|
||||
var negativePressure = ChannelValue("负压辅助引流");
|
||||
|
||||
if (_antiCollapseBaselinePressureDrop is null || negativePressure >= -1.0)
|
||||
{
|
||||
_antiCollapseBaselinePressureDrop = DeltaPressure;
|
||||
_antiCollapseBaselineFlow = PumpFlow;
|
||||
_antiCollapseBaselineCapturedAt = DateTime.Now;
|
||||
OnPropertyChanged(nameof(HasAntiCollapseBaseline));
|
||||
OnPropertyChanged(nameof(AntiCollapseBaselineDisplay));
|
||||
OnPropertyChanged(nameof(AntiCollapseComparisonDisplay));
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildAntiCollapseLiveDisplay()
|
||||
{
|
||||
var comparison = GetAntiCollapseComparison();
|
||||
var baselineText = comparison.HasBaseline
|
||||
? $"基线 ΔP {comparison.BaselinePressureDrop:F1} mmHg @ {comparison.BaselineFlow:F2} L/min"
|
||||
: "基线待采集(请先在无负压条件下运行)";
|
||||
|
||||
var increaseText = comparison.HasBaseline
|
||||
? $"增量 {comparison.Increase:F1} mmHg / 增幅 {comparison.IncreaseRate:F1}% / 判定 {comparison.StatusText}"
|
||||
: "尚无法比较增幅";
|
||||
|
||||
return
|
||||
$"条件:模拟血液 2.0~3.5 mPa·s / {TemperatureDisplay} / 目标负压 {AntiCollapseTargetNegativePressure:F2} kPa\n" +
|
||||
$"当前:负压 {NegativeAssistPressureDisplay} / 主泵 {PumpFlow:F2} L/min / ΔP {DeltaPressure:F1} mmHg\n" +
|
||||
$"{baselineText}\n" +
|
||||
$"{increaseText}";
|
||||
}
|
||||
|
||||
private string BuildAntiCollapseMeasuredText()
|
||||
{
|
||||
var comparison = GetAntiCollapseComparison();
|
||||
var baselineText = comparison.HasBaseline
|
||||
? $"{comparison.BaselinePressureDrop:F1} mmHg"
|
||||
: "未采集";
|
||||
var increaseText = comparison.HasBaseline
|
||||
? $"{comparison.Increase:F1} mmHg ({comparison.IncreaseRate:F1}%)"
|
||||
: "无法比较";
|
||||
|
||||
return
|
||||
$"试验条件:模拟血液 2.0~3.5 mPa·s,{TemperatureDisplay},有效长度处于 37±2 ℃ 条件\n" +
|
||||
$"基线测量:最大血流量 {comparison.BaselineFlow:F2} L/min,压力降 {baselineText}\n" +
|
||||
$"负压加载:远端施加 {NegativeAssistPressureDisplay}(目标 {AntiCollapseTargetNegativePressure:F2} kPa)\n" +
|
||||
$"比较结果:当前压力降 {DeltaPressure:F1} mmHg,较基线增加 {increaseText}\n" +
|
||||
$"建议判定:{comparison.StatusText}";
|
||||
}
|
||||
|
||||
private string BuildAntiCollapseRecordNote()
|
||||
{
|
||||
var comparison = GetAntiCollapseComparison();
|
||||
var baselineCapturedText = _antiCollapseBaselineCapturedAt?.ToString("yyyy-MM-dd HH:mm:ss") ?? "未采集";
|
||||
|
||||
return
|
||||
$"录入建议:先在无负压条件下采集基线压力降,再在远端施加 -6.67 kPa 负压后记录比较值。\n" +
|
||||
$"当前基线时间:{baselineCapturedText};基线流量 {comparison.BaselineFlow:F2} L/min;当前流量 {PumpFlow:F2} L/min。\n" +
|
||||
$"判定规则:负压后压力降增幅不超过基线 50% 为合格;当前比较结果为 {comparison.StatusText}。";
|
||||
}
|
||||
|
||||
private AntiCollapseComparison GetAntiCollapseComparison()
|
||||
{
|
||||
if (_antiCollapseBaselinePressureDrop is null || _antiCollapseBaselineFlow is null)
|
||||
{
|
||||
return new AntiCollapseComparison(false, 0, 0, 0, 0, "等待基线");
|
||||
}
|
||||
|
||||
var baseline = _antiCollapseBaselinePressureDrop.Value;
|
||||
var increase = DeltaPressure - baseline;
|
||||
var increaseRate = baseline <= 0 ? 0 : increase / baseline * 100d;
|
||||
var statusText = increaseRate switch
|
||||
{
|
||||
<= 50 => "合格",
|
||||
<= 60 => "预警,建议复测",
|
||||
_ => "不合格,压降增幅超限"
|
||||
};
|
||||
|
||||
return new AntiCollapseComparison(true, baseline, _antiCollapseBaselineFlow.Value, increase, increaseRate, statusText);
|
||||
}
|
||||
|
||||
private double PressureDropFlowPoint(double ratio) =>
|
||||
Channels.First(channel => channel.Name == "主泵流量").Max * ratio;
|
||||
|
||||
private readonly record struct AntiCollapseComparison(
|
||||
bool HasBaseline,
|
||||
double BaselinePressureDrop,
|
||||
double BaselineFlow,
|
||||
double Increase,
|
||||
double IncreaseRate,
|
||||
string StatusText);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user