更新20260518

This commit is contained in:
GukSang.Jin
2026-05-18 18:54:32 +08:00
parent 514673f16d
commit 96338de73f
11 changed files with 224 additions and 30 deletions

View File

@@ -33,6 +33,7 @@ namespace TabletTester2025.ViewModels
private bool _isLoadingDissolution2SampleInterval;
private bool _isLoadingDisintegrationTime;
private bool _isLoadingDisintegrationSpeed;
private bool _isLoadingFriabilityTime;
private bool _isUpdatingFriabilityWeightFromPlc;
private readonly List<double> _dissolution1Times = new();
@@ -123,7 +124,8 @@ namespace TabletTester2025.ViewModels
// 脆碎度新增
[ObservableProperty] private double _friabilityTargetRpm = 25;
[ObservableProperty] private int _friabilityTargetTimeSec = 4;
[ObservableProperty] private double _friabilityTargetTimeMin = 4;
[ObservableProperty] private int _friabilityTargetTimeSec = 240;
[ObservableProperty] private int _friabilityTargetRounds = 100;
[ObservableProperty] private double _friabilityMaxLossPercent = 1.0;
[ObservableProperty] private bool _friabilityClockwise = true;
@@ -311,7 +313,7 @@ namespace TabletTester2025.ViewModels
ResetDisintegrationCommand = new AsyncRelayCommand(ResetDisintegrationAsync);
PrintDisintegrationCommand = new AsyncRelayCommand(async () => await PrintReport("崩解"));
_ = LoadFriabilityWeightsAsync();
_ = LoadFriabilitySettingsAsync();
}
public void ApplyPharmaDefaults()
@@ -323,13 +325,18 @@ namespace TabletTester2025.ViewModels
_isLoadingDissolution2Time = true;
_isLoadingDissolution1SampleInterval = true;
_isLoadingDissolution2SampleInterval = true;
_isLoadingFriabilityTime = true;
try
{
HardnessInternalMin = p.HardnessMin_N;
HardnessInternalMax = p.HardnessMax_N;
HardnessTestCount = Math.Max(1, p.HardnessTestCount);
FriabilityTargetRpm = p.FriabilityTargetRpm > 0 ? p.FriabilityTargetRpm : 25;
FriabilityTargetRounds = p.FriabilityTargetRounds > 0 ? p.FriabilityTargetRounds : 100;
double defaultRounds = p.FriabilityTargetRounds > 0 ? p.FriabilityTargetRounds : 100;
FriabilityTargetTimeMin = p.FriabilityTargetTimeMin > 0
? p.FriabilityTargetTimeMin
: defaultRounds / FriabilityTargetRpm;
UpdateFriabilityTimingFromTime();
FriabilityMaxLossPercent = p.FriabilityMaxLossPercent;
FriabilityRemainingRounds = FriabilityTargetRounds;
DisintegrationDosageForm = string.IsNullOrWhiteSpace(p.DisintegrationDosageForm) ? "普通片" : p.DisintegrationDosageForm;
@@ -353,7 +360,10 @@ namespace TabletTester2025.ViewModels
_isLoadingDissolution2Time = false;
_isLoadingDissolution1SampleInterval = false;
_isLoadingDissolution2SampleInterval = false;
_isLoadingFriabilityTime = false;
}
_ = WriteFriabilityTimeAsync(FriabilityTargetTimeMin);
}
private void LoadPharmaDefaults()
@@ -975,7 +985,7 @@ namespace TabletTester2025.ViewModels
if (_isUpdatingFriabilityWeightFromPlc)
return;
_ = WriteFriabilityWeightAsync(_plcConfig.WeightBefore, value);
_ = WriteFriabilityWeightAsync(ResolveFriabilityWeightBeforeRegister(), value);
}
partial void OnWeightAfterChanged(double value)
@@ -983,7 +993,72 @@ namespace TabletTester2025.ViewModels
if (_isUpdatingFriabilityWeightFromPlc)
return;
_ = WriteFriabilityWeightAsync(_plcConfig.WeightAfter, value);
_ = WriteFriabilityWeightAsync(ResolveFriabilityWeightAfterRegister(), value);
}
partial void OnFriabilityTargetTimeMinChanged(double value)
{
UpdateFriabilityTimingFromTime();
if (_isLoadingFriabilityTime)
return;
_ = WriteFriabilityTimeAsync(value);
}
partial void OnFriabilityTargetRpmChanged(double value)
{
UpdateFriabilityTimingFromTime();
}
private void UpdateFriabilityTimingFromTime()
{
if (!double.IsFinite(FriabilityTargetTimeMin) || FriabilityTargetTimeMin <= 0)
return;
double rpm = FriabilityTargetRpm > 0 ? FriabilityTargetRpm : 25;
FriabilityTargetTimeSec = (int)Math.Ceiling(FriabilityTargetTimeMin * 60);
FriabilityTargetRounds = Math.Max(1, (int)Math.Round(FriabilityTargetTimeMin * rpm, MidpointRounding.AwayFromZero));
if (Phase != TestPhase.Running)
FriabilityRemainingRounds = FriabilityTargetRounds;
}
private async Task LoadFriabilitySettingsAsync()
{
await LoadFriabilityTimeAsync();
await LoadFriabilityWeightsAsync();
}
private async Task LoadFriabilityTimeAsync()
{
ushort registerAddress = ResolveFriabilityTestTimeRegister();
if (registerAddress == 0)
return;
try
{
_isLoadingFriabilityTime = true;
float value = await _plc.ReadFloatAsync(registerAddress);
if (float.IsFinite(value) && value > 0)
{
FriabilityTargetTimeMin = value;
}
else
{
await WriteFriabilityTimeAsync(FriabilityTargetTimeMin);
}
}
catch
{
try { await WriteFriabilityTimeAsync(FriabilityTargetTimeMin); }
catch { }
}
finally
{
_isLoadingFriabilityTime = false;
UpdateFriabilityTimingFromTime();
}
}
private async Task LoadFriabilityWeightsAsync()
@@ -992,15 +1067,17 @@ namespace TabletTester2025.ViewModels
{
_isUpdatingFriabilityWeightFromPlc = true;
if (_plcConfig.WeightBefore != 0)
ushort beforeRegister = ResolveFriabilityWeightBeforeRegister();
if (beforeRegister != 0)
{
double before = await ReadFriabilityWeightAsync(_plcConfig.WeightBefore, "脆碎前重量");
double before = await ReadFriabilityWeightAsync(beforeRegister, "脆碎前重量");
WeightBefore = before;
}
if (_plcConfig.WeightAfter != 0)
ushort afterRegister = ResolveFriabilityWeightAfterRegister();
if (afterRegister != 0)
{
double after = await ReadFriabilityWeightAsync(_plcConfig.WeightAfter, "脆碎后重量");
double after = await ReadFriabilityWeightAsync(afterRegister, "脆碎后重量");
WeightAfter = after;
}
}
@@ -1023,6 +1100,38 @@ namespace TabletTester2025.ViewModels
catch { }
}
private async Task WriteFriabilityTimeAsync(double value)
{
ushort registerAddress = ResolveFriabilityTestTimeRegister();
if (registerAddress == 0 || !double.IsFinite(value) || value <= 0)
return;
try
{
await _plc.WriteFloatAsync(registerAddress, (float)value);
}
catch { }
}
private ushort ResolveFriabilityTestTimeRegister()
{
return _plcConfig.FriabilityTestTime;
}
private ushort ResolveFriabilityWeightBeforeRegister()
{
return _plcConfig.FriabilityWeightBefore != 0
? _plcConfig.FriabilityWeightBefore
: _plcConfig.WeightBefore;
}
private ushort ResolveFriabilityWeightAfterRegister()
{
return _plcConfig.FriabilityWeightAfter != 0
? _plcConfig.FriabilityWeightAfter
: _plcConfig.WeightAfter;
}
private void SetFriabilityWeightFromPlc(double? weightBefore = null, double? weightAfter = null)
{
_isUpdatingFriabilityWeightFromPlc = true;
@@ -1289,18 +1398,24 @@ namespace TabletTester2025.ViewModels
{
throw new InvalidOperationException("未配置脆碎度启动线圈地址");
}
double weightBefore = await ReadFriabilityWeightAsync(_plcConfig.WeightBefore, "脆碎前重量");
if (!double.IsFinite(FriabilityTargetTimeMin) || FriabilityTargetTimeMin <= 0)
throw new InvalidOperationException("脆碎试验时间必须大于0");
await WriteFriabilityTimeAsync(FriabilityTargetTimeMin);
double weightBefore = await ReadFriabilityWeightAsync(ResolveFriabilityWeightBeforeRegister(), "脆碎前重量");
SetFriabilityWeightFromPlc(weightBefore: weightBefore);
if (WeightBefore <= 0)
throw new InvalidOperationException("脆碎前重量必须大于0");
int totalRounds = Math.Max(1, FriabilityTargetRounds);
UpdateFriabilityTimingFromTime();
double rpm = FriabilityTargetRpm > 0 ? FriabilityTargetRpm : 25;
FriabilityTargetTimeSec = (int)Math.Ceiling(totalRounds / rpm * 60);
double testTimeMin = FriabilityTargetTimeMin > 0 ? FriabilityTargetTimeMin : 4;
int totalRounds = Math.Max(1, FriabilityTargetRounds);
FriabilityRemainingRounds = totalRounds;
FriabilityCurrentRpm = rpm;
await PulseCoilAsync(startCoil);
int durationMs = (int)((totalRounds / rpm) * 60 * 1000); // 总运行时间(毫秒)
int durationMs = (int)Math.Ceiling(testTimeMin * 60 * 1000); // 总运行时间(毫秒)
for (int i = 0; i < durationMs; i += 100)
{
@@ -1322,7 +1437,7 @@ namespace TabletTester2025.ViewModels
if (Phase != TestPhase.Running)
throw new InvalidOperationException("脆碎度测试已停止,未保存结果");
double weightAfter = await ReadFriabilityWeightAsync(_plcConfig.WeightAfter, "脆碎后重量");
double weightAfter = await ReadFriabilityWeightAsync(ResolveFriabilityWeightAfterRegister(), "脆碎后重量");
SetFriabilityWeightFromPlc(weightAfter: weightAfter);
FriabilityCurrentRpm = rpm;
LossPercent = TestCalculationService.CalculateFriabilityLossPercent(WeightBefore, WeightAfter);