|
|
|
@ -4235,6 +4235,11 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
const double maximumTrustRadius = 0.30;
|
|
|
|
const double maximumTrustRadius = 0.30;
|
|
|
|
const double columnCorrelationLimit = 0.995;
|
|
|
|
const double columnCorrelationLimit = 0.995;
|
|
|
|
const double diagnosisThreshold = 1.0e-5;
|
|
|
|
const double diagnosisThreshold = 1.0e-5;
|
|
|
|
|
|
|
|
// 误差下降至少达到绝对 1e-5 且相对当前有效基准 0.2% 才算有效改善。
|
|
|
|
|
|
|
|
// 更小的下降仍保留为最佳解,但不能反复清除停滞状态、延长拟合时间。
|
|
|
|
|
|
|
|
const double effectiveRelativeImprovement = 2.0e-3;
|
|
|
|
|
|
|
|
const double effectiveAbsoluteImprovement = 1.0e-5;
|
|
|
|
|
|
|
|
const int maximumIneffectiveSteps = 3;
|
|
|
|
|
|
|
|
|
|
|
|
// damping 是 LM 阻尼;拒绝或预测失准时增大,真实下降与预测一致时减小。
|
|
|
|
// damping 是 LM 阻尼;拒绝或预测失准时增大,真实下降与预测一致时减小。
|
|
|
|
// 两组累计量控制 Jacobian 重建,避免长期使用已偏离当前工作点的局部模型。
|
|
|
|
// 两组累计量控制 Jacobian 重建,避免长期使用已偏离当前工作点的局部模型。
|
|
|
|
@ -4243,9 +4248,11 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
int consecutiveRejectedSteps = 0;
|
|
|
|
int consecutiveRejectedSteps = 0;
|
|
|
|
int consecutiveSolverFailures = 0;
|
|
|
|
int consecutiveSolverFailures = 0;
|
|
|
|
int acceptedSinceRebuild = 0;
|
|
|
|
int acceptedSinceRebuild = 0;
|
|
|
|
|
|
|
|
int consecutiveIneffectiveSteps = 0;
|
|
|
|
double movementSinceRebuild = 0.0;
|
|
|
|
double movementSinceRebuild = 0.0;
|
|
|
|
bool rebuildRequested = true;
|
|
|
|
bool rebuildRequested = true;
|
|
|
|
bool modelRebuiltAtMinimumRadius = false;
|
|
|
|
bool modelRebuiltAtMinimumRadius = false;
|
|
|
|
|
|
|
|
bool stagnationConfirmationRequested = false;
|
|
|
|
StopReasonPSO stopReason = PSO_MAX_ITERATIONS;
|
|
|
|
StopReasonPSO stopReason = PSO_MAX_ITERATIONS;
|
|
|
|
|
|
|
|
|
|
|
|
// jacobian 的行对应固定 160 维残差,列对应用户勾选的参数。
|
|
|
|
// jacobian 的行对应固定 160 维残差,列对应用户勾选的参数。
|
|
|
|
@ -4367,6 +4374,54 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
.arg(current.fitness, 0, 'e', 4)
|
|
|
|
.arg(current.fitness, 0, 'e', 4)
|
|
|
|
.arg(maximumEvaluations));
|
|
|
|
.arg(maximumEvaluations));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 有效改善始终相对“上一次有效改善后的误差”累计判断,避免一连串微小
|
|
|
|
|
|
|
|
// 下降每次都清零计数;累计达到门槛后才开始新的有效改善基准。
|
|
|
|
|
|
|
|
double effectiveImprovementBaseline = current.fitness;
|
|
|
|
|
|
|
|
auto registerEffectiveImprovement = [&](double fitness) -> bool {
|
|
|
|
|
|
|
|
const double requiredImprovement = qMax(
|
|
|
|
|
|
|
|
effectiveAbsoluteImprovement,
|
|
|
|
|
|
|
|
qAbs(effectiveImprovementBaseline) *
|
|
|
|
|
|
|
|
effectiveRelativeImprovement);
|
|
|
|
|
|
|
|
const double improvement = effectiveImprovementBaseline - fitness;
|
|
|
|
|
|
|
|
if(improvement < requiredImprovement) {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
effectiveImprovementBaseline = fitness;
|
|
|
|
|
|
|
|
consecutiveIneffectiveSteps = 0;
|
|
|
|
|
|
|
|
stagnationConfirmationRequested = false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 连续三次没有有效改善时只请求一次灵敏度重建。重建完成后由主循环
|
|
|
|
|
|
|
|
// 直接检查累计改善,仍达不到门槛就判定局部收敛,不再继续微小试探。
|
|
|
|
|
|
|
|
auto recordIneffectiveStep = [&]() -> bool {
|
|
|
|
|
|
|
|
++consecutiveIneffectiveSteps;
|
|
|
|
|
|
|
|
if(consecutiveIneffectiveSteps < maximumIneffectiveSteps) {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(stagnationConfirmationRequested) {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
consecutiveIneffectiveSteps = 0;
|
|
|
|
|
|
|
|
stagnationConfirmationRequested = true;
|
|
|
|
|
|
|
|
rebuildRequested = true;
|
|
|
|
|
|
|
|
emit logMessageGenerated(
|
|
|
|
|
|
|
|
tr("No effective improvement for %1 consecutive steps; "
|
|
|
|
|
|
|
|
"rebuilding sensitivity model for confirmation")
|
|
|
|
|
|
|
|
.arg(maximumIneffectiveSteps));
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
emit logMessageGenerated(
|
|
|
|
|
|
|
|
tr("Effective improvement threshold: max(%1, %2% of baseline error); "
|
|
|
|
|
|
|
|
"%3 consecutive ineffective steps trigger convergence confirmation")
|
|
|
|
|
|
|
|
.arg(effectiveAbsoluteImprovement, 0, 'e', 2)
|
|
|
|
|
|
|
|
.arg(effectiveRelativeImprovement * 100.0, 0, 'f', 2)
|
|
|
|
|
|
|
|
.arg(maximumIneffectiveSteps));
|
|
|
|
|
|
|
|
|
|
|
|
if(current.fitness < m_targetError) {
|
|
|
|
if(current.fitness < m_targetError) {
|
|
|
|
return PSO_TARGET_ACHIEVED;
|
|
|
|
return PSO_TARGET_ACHIEVED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -4603,6 +4658,8 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(rebuildRequested) {
|
|
|
|
if(rebuildRequested) {
|
|
|
|
|
|
|
|
const bool confirmingStagnation =
|
|
|
|
|
|
|
|
stagnationConfirmationRequested;
|
|
|
|
if(!rebuildSensitivity()) {
|
|
|
|
if(!rebuildSensitivity()) {
|
|
|
|
stopReason = m_shouldStop
|
|
|
|
stopReason = m_shouldStop
|
|
|
|
? PSO_USER_STOPPED
|
|
|
|
? PSO_USER_STOPPED
|
|
|
|
@ -4617,6 +4674,15 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
stopReason = PSO_MAX_ITERATIONS;
|
|
|
|
stopReason = PSO_MAX_ITERATIONS;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const bool rebuildEffective =
|
|
|
|
|
|
|
|
registerEffectiveImprovement(current.fitness);
|
|
|
|
|
|
|
|
if(confirmingStagnation && !rebuildEffective) {
|
|
|
|
|
|
|
|
emit logMessageGenerated(
|
|
|
|
|
|
|
|
tr("Sensitivity rebuild produced no effective improvement; "
|
|
|
|
|
|
|
|
"local convergence detected"));
|
|
|
|
|
|
|
|
stopReason = PSO_LOCAL_OPTIMUM;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 先确定当前最突出的可靠诊断误差,用其梯度回答“哪些参数最能改善
|
|
|
|
// 先确定当前最突出的可靠诊断误差,用其梯度回答“哪些参数最能改善
|
|
|
|
@ -4748,6 +4814,10 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
trustRadius = qMax(minimumTrustRadius, trustRadius * 0.5);
|
|
|
|
trustRadius = qMax(minimumTrustRadius, trustRadius * 0.5);
|
|
|
|
damping = qMin(1.0e8, damping * 4.0);
|
|
|
|
damping = qMin(1.0e8, damping * 4.0);
|
|
|
|
rebuildRequested = true;
|
|
|
|
rebuildRequested = true;
|
|
|
|
|
|
|
|
if(recordIneffectiveStep()) {
|
|
|
|
|
|
|
|
stopReason = PSO_LOCAL_OPTIMUM;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -4865,6 +4935,10 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rebuildRequested = true;
|
|
|
|
rebuildRequested = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(recordIneffectiveStep()) {
|
|
|
|
|
|
|
|
stopReason = PSO_LOCAL_OPTIMUM;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -4905,6 +4979,10 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
stopReason = PSO_CONSECUTIVE_FAILURES;
|
|
|
|
stopReason = PSO_CONSECUTIVE_FAILURES;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(recordIneffectiveStep()) {
|
|
|
|
|
|
|
|
stopReason = PSO_LOCAL_OPTIMUM;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -4994,6 +5072,14 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 候选只要更优就继续作为 current 保存;是否足以解除停滞,则统一
|
|
|
|
|
|
|
|
// 相对上一次有效改善基准判断。拒绝和微小改善都会累计无效次数。
|
|
|
|
|
|
|
|
const bool effectiveImprovement =
|
|
|
|
|
|
|
|
registerEffectiveImprovement(current.fitness);
|
|
|
|
|
|
|
|
if(!effectiveImprovement && recordIneffectiveStep()) {
|
|
|
|
|
|
|
|
stopReason = PSO_LOCAL_OPTIMUM;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
writeTraceRow(m_currentIteration,
|
|
|
|
writeTraceRow(m_currentIteration,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
"trust_region_candidate",
|
|
|
|
"trust_region_candidate",
|
|
|
|
@ -5018,6 +5104,10 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
.arg(accepted ? tr("accepted") : tr("rejected")));
|
|
|
|
.arg(accepted ? tr("accepted") : tr("rejected")));
|
|
|
|
emit progressUpdated(iteration + 1, m_globalBestFitness);
|
|
|
|
emit progressUpdated(iteration + 1, m_globalBestFitness);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(stopReason == PSO_LOCAL_OPTIMUM) {
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(current.fitness < m_targetError) {
|
|
|
|
if(current.fitness < m_targetError) {
|
|
|
|
stopReason = PSO_TARGET_ACHIEVED;
|
|
|
|
stopReason = PSO_TARGET_ACHIEVED;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|