|
|
|
|
@ -104,8 +104,8 @@ static inline bool isFiniteNumber(double value)
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 两个 Huber RMS 的差不能直接解释为被消除的独立误差。RMS 的平方才对应
|
|
|
|
|
// 稳健能量,因此先计算 reduced^2-full^2,再开方恢复原量纲。这里用于分别
|
|
|
|
|
// 两个 RMSE 的差不能直接解释为被消除的独立误差。RMSE 的平方才对应
|
|
|
|
|
// 均方能量,因此先计算 reduced^2-full^2,再开方恢复原量纲。这里用于分别
|
|
|
|
|
// 提取“消除公共上下偏差”和“消除水平位移”实际减少的误差贡献。
|
|
|
|
|
static double nestedRmsContribution(double reducedModelLoss,
|
|
|
|
|
double fullModelLoss)
|
|
|
|
|
@ -3900,7 +3900,7 @@ struct TrustRegionEvaluation
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// LM 只使用固定长度、全部有限的稳健残差。代理路径不会进入本搜索器。
|
|
|
|
|
// LM 只使用固定长度、全部有限的普通残差。代理路径不会进入本搜索器。
|
|
|
|
|
static bool trustRegionResidualsValid(
|
|
|
|
|
const AutoFitObjectiveBreakdown& breakdown)
|
|
|
|
|
{
|
|
|
|
|
@ -4216,7 +4216,7 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
|
bool modelRebuiltAtMinimumRadius = false;
|
|
|
|
|
StopReasonPSO stopReason = PSO_MAX_ITERATIONS;
|
|
|
|
|
|
|
|
|
|
// jacobian 的行对应固定 100 维稳健残差,列对应用户勾选的参数。
|
|
|
|
|
// jacobian 的行对应固定 100 维残差,列对应用户勾选的参数。
|
|
|
|
|
// 三个 gradient 单独描述诊断分量对参数的局部变化,只用于本轮选参。
|
|
|
|
|
QVector<QVector<double> > jacobian;
|
|
|
|
|
QVector<double> verticalGradient(dimensions, 0.0);
|
|
|
|
|
@ -4803,7 +4803,7 @@ StopReasonPSO nmCalculationAutoFitPSO::runTrustRegionFitting()
|
|
|
|
|
}
|
|
|
|
|
stepNorm = qSqrt(trustRegionSquaredNorm(coordinateStep));
|
|
|
|
|
|
|
|
|
|
// 用线性模型 r_new ~= r_current + J*step 预测稳健残差,再用平方能量
|
|
|
|
|
// 用线性模型 r_new ~= r_current + J*step 预测残差,再用平方能量
|
|
|
|
|
// 的下降量与真实候选下降量比较,作为调整阻尼和半径的依据。
|
|
|
|
|
QVector<double> predictedResidual =
|
|
|
|
|
current.breakdown.residualVector;
|
|
|
|
|
@ -6462,9 +6462,6 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
// 位于 log(time)-log(value) 坐标,因此得到的是相对尺度偏差而非原始压力量纲。
|
|
|
|
|
const double invalidLoss = 1.0e10;
|
|
|
|
|
const double valueFloor = 1.0e-12;
|
|
|
|
|
// Huber 转折点 qLn(1.2) 对应约 20% 的倍率偏差;小偏差保持平方惩罚,
|
|
|
|
|
// 更大的局部尖峰改为近似线性惩罚,避免单点支配整条曲线。
|
|
|
|
|
const double huberDelta = qLn(1.2);
|
|
|
|
|
const double minimumCoverage = 0.95;
|
|
|
|
|
const int numPoints = 50;
|
|
|
|
|
m_lastObjectiveBreakdown = AutoFitObjectiveBreakdown();
|
|
|
|
|
@ -6704,7 +6701,7 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 通过门槛后最多只缺少首尾少量目标点。按模拟曲线端点趋势补齐后,
|
|
|
|
|
// 每个候选仍在固定 50 点上计算 Huber 均值,不能靠少算难拟合端点获益。
|
|
|
|
|
// 每个候选仍在固定 50 点上计算均方根误差,不能靠少算难拟合端点获益。
|
|
|
|
|
for(int i = 0; i < numPoints; ++i) {
|
|
|
|
|
if(isFiniteNumber(pressureResidual[i]) &&
|
|
|
|
|
isFiniteNumber(derivativeResidual[i])) {
|
|
|
|
|
@ -6726,8 +6723,8 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
resultLogDerivative - targetLogDerivative[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Huber RMS 在小残差处保持平方损失,在异常点处转为线性增长。
|
|
|
|
|
auto huberRmsAround = [huberDelta](
|
|
|
|
|
// 在指定中心附近计算普通均方根误差。
|
|
|
|
|
auto rmseAround = [](
|
|
|
|
|
const QVector<double>& values,
|
|
|
|
|
int begin,
|
|
|
|
|
int end,
|
|
|
|
|
@ -6744,12 +6741,7 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double difference = values[i] - center;
|
|
|
|
|
double absoluteValue = qAbs(difference);
|
|
|
|
|
double rho = absoluteValue <= huberDelta
|
|
|
|
|
? difference * difference
|
|
|
|
|
: 2.0 * huberDelta * absoluteValue -
|
|
|
|
|
huberDelta * huberDelta;
|
|
|
|
|
sum += rho;
|
|
|
|
|
sum += difference * difference;
|
|
|
|
|
++count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -6758,27 +6750,15 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
: std::numeric_limits<double>::quiet_NaN();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto huberRms = [&huberRmsAround](
|
|
|
|
|
auto rmse = [&rmseAround](
|
|
|
|
|
const QVector<double>& values,
|
|
|
|
|
int begin,
|
|
|
|
|
int end) -> double {
|
|
|
|
|
return huberRmsAround(values, begin, end, 0.0);
|
|
|
|
|
return rmseAround(values, begin, end, 0.0);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 将 Huber 能量转换成带符号的等效残差,使向量平方和与稳健损失一致。
|
|
|
|
|
// 非代理 LM 直接对该固定长度向量建立 Jacobian。
|
|
|
|
|
auto huberEquivalentResidual = [huberDelta](double value) -> double {
|
|
|
|
|
double absoluteValue = qAbs(value);
|
|
|
|
|
double rho = absoluteValue <= huberDelta
|
|
|
|
|
? value * value
|
|
|
|
|
: 2.0 * huberDelta * absoluteValue -
|
|
|
|
|
huberDelta * huberDelta;
|
|
|
|
|
double magnitude = qSqrt(qMax(0.0, rho));
|
|
|
|
|
return value < 0.0 ? -magnitude : magnitude;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Huber 加权中心保留上下偏差的符号,并降低局部尖峰的影响。
|
|
|
|
|
auto huberCenterRange = [huberDelta](
|
|
|
|
|
// 普通算术平均中心保留上下偏差的符号。
|
|
|
|
|
auto meanCenterRange = [](
|
|
|
|
|
const QVector<double>& values,
|
|
|
|
|
int begin,
|
|
|
|
|
int end) -> double {
|
|
|
|
|
@ -6797,42 +6777,12 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
if(count == 0) {
|
|
|
|
|
return std::numeric_limits<double>::quiet_NaN();
|
|
|
|
|
}
|
|
|
|
|
center /= count;
|
|
|
|
|
|
|
|
|
|
for(int iteration = 0; iteration < 8; ++iteration) {
|
|
|
|
|
double weightedSum = 0.0;
|
|
|
|
|
double weightTotal = 0.0;
|
|
|
|
|
for(int i = validBegin; i < validEnd; ++i) {
|
|
|
|
|
if(!isFiniteNumber(values[i])) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double distance = qAbs(values[i] - center);
|
|
|
|
|
double weight =
|
|
|
|
|
distance <= huberDelta ||
|
|
|
|
|
distance < 1.0e-12
|
|
|
|
|
? 1.0
|
|
|
|
|
: huberDelta / distance;
|
|
|
|
|
weightedSum += weight * values[i];
|
|
|
|
|
weightTotal += weight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(weightTotal <= 1.0e-12) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
double nextCenter = weightedSum / weightTotal;
|
|
|
|
|
if(qAbs(nextCenter - center) <= 1.0e-12) {
|
|
|
|
|
center = nextCenter;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
center = nextCenter;
|
|
|
|
|
}
|
|
|
|
|
return center;
|
|
|
|
|
return center / count;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 压力和导数合并后只求一个公共中心,表示两条曲线共同的上下位移。
|
|
|
|
|
// 分别去中心会把压力与导数之间真实的相对形状差异一并消除。
|
|
|
|
|
auto huberCommonCenterRange = [&huberCenterRange](
|
|
|
|
|
auto commonMeanCenterRange = [&meanCenterRange](
|
|
|
|
|
const QVector<double>& pressureValues,
|
|
|
|
|
const QVector<double>& derivativeValues,
|
|
|
|
|
int begin,
|
|
|
|
|
@ -6853,19 +6803,19 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
combined.append(derivativeValues[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return huberCenterRange(combined, 0, combined.size());
|
|
|
|
|
return meanCenterRange(combined, 0, combined.size());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 两个通道按能量等权合并,返回值与单通道 Huber RMS 保持同一量纲。
|
|
|
|
|
auto jointHuberRmsAround = [&huberRmsAround](
|
|
|
|
|
// 两个通道按能量等权合并,返回值与单通道 RMSE 保持同一量纲。
|
|
|
|
|
auto jointRmseAround = [&rmseAround](
|
|
|
|
|
const QVector<double>& pressureValues,
|
|
|
|
|
const QVector<double>& derivativeValues,
|
|
|
|
|
int begin,
|
|
|
|
|
int end,
|
|
|
|
|
double center) -> double {
|
|
|
|
|
double pressureLoss = huberRmsAround(
|
|
|
|
|
double pressureLoss = rmseAround(
|
|
|
|
|
pressureValues, begin, end, center);
|
|
|
|
|
double derivativeLoss = huberRmsAround(
|
|
|
|
|
double derivativeLoss = rmseAround(
|
|
|
|
|
derivativeValues, begin, end, center);
|
|
|
|
|
if(!isFiniteNumber(pressureLoss) ||
|
|
|
|
|
!isFiniteNumber(derivativeLoss)) {
|
|
|
|
|
@ -6878,9 +6828,9 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
|
|
|
|
|
// 主目标始终使用未做上下或左右校正的完整曲线误差。
|
|
|
|
|
breakdown.pressureLoss =
|
|
|
|
|
huberRms(pressureResidual, 0, numPoints);
|
|
|
|
|
rmse(pressureResidual, 0, numPoints);
|
|
|
|
|
breakdown.derivativeLoss =
|
|
|
|
|
huberRms(derivativeResidual, 0, numPoints);
|
|
|
|
|
rmse(derivativeResidual, 0, numPoints);
|
|
|
|
|
|
|
|
|
|
// 压力和导数各占一半权重。缩放后 residualVector 的二范数就是
|
|
|
|
|
// sqrt(0.5 * pressureLoss^2 + 0.5 * derivativeLoss^2)。
|
|
|
|
|
@ -6889,12 +6839,12 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
for(int i = 0; i < numPoints; ++i) {
|
|
|
|
|
breakdown.residualVector.append(
|
|
|
|
|
residualScale *
|
|
|
|
|
huberEquivalentResidual(pressureResidual[i]));
|
|
|
|
|
pressureResidual[i]);
|
|
|
|
|
}
|
|
|
|
|
for(int i = 0; i < numPoints; ++i) {
|
|
|
|
|
breakdown.residualVector.append(
|
|
|
|
|
residualScale *
|
|
|
|
|
huberEquivalentResidual(derivativeResidual[i]));
|
|
|
|
|
derivativeResidual[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const double logGridStep =
|
|
|
|
|
@ -7049,31 +6999,31 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double commonBias = huberCommonCenterRange(
|
|
|
|
|
double commonBias = commonMeanCenterRange(
|
|
|
|
|
shiftedPressureResidual,
|
|
|
|
|
shiftedDerivativeResidual,
|
|
|
|
|
registrationBegin,
|
|
|
|
|
registrationEnd);
|
|
|
|
|
double centeredLoss = jointHuberRmsAround(
|
|
|
|
|
double centeredLoss = jointRmseAround(
|
|
|
|
|
shiftedPressureResidual,
|
|
|
|
|
shiftedDerivativeResidual,
|
|
|
|
|
registrationBegin,
|
|
|
|
|
registrationEnd,
|
|
|
|
|
commonBias);
|
|
|
|
|
double pressureBias = huberCenterRange(
|
|
|
|
|
double pressureBias = meanCenterRange(
|
|
|
|
|
shiftedPressureResidual,
|
|
|
|
|
registrationBegin,
|
|
|
|
|
registrationEnd);
|
|
|
|
|
double derivativeBias = huberCenterRange(
|
|
|
|
|
double derivativeBias = meanCenterRange(
|
|
|
|
|
shiftedDerivativeResidual,
|
|
|
|
|
registrationBegin,
|
|
|
|
|
registrationEnd);
|
|
|
|
|
double pressureLoss = huberRmsAround(
|
|
|
|
|
double pressureLoss = rmseAround(
|
|
|
|
|
shiftedPressureResidual,
|
|
|
|
|
registrationBegin,
|
|
|
|
|
registrationEnd,
|
|
|
|
|
pressureBias);
|
|
|
|
|
double derivativeLoss = huberRmsAround(
|
|
|
|
|
double derivativeLoss = rmseAround(
|
|
|
|
|
shiftedDerivativeResidual,
|
|
|
|
|
registrationBegin,
|
|
|
|
|
registrationEnd,
|
|
|
|
|
@ -7124,7 +7074,7 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
return invalidLoss;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// horizontalGain 是“允许水平位移”相对“固定零位移”减少的稳健能量。
|
|
|
|
|
// horizontalGain 是“允许水平位移”相对“固定零位移”减少的均方能量。
|
|
|
|
|
// 只有改善足够明显且最优点不是边界,才把位移解释为可靠左右偏差。
|
|
|
|
|
double horizontalGain = nestedRmsContribution(
|
|
|
|
|
zeroShiftCenteredLoss, bestCenteredLoss);
|
|
|
|
|
@ -7183,8 +7133,7 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
isFiniteNumber(maximumNearOptimalBias)
|
|
|
|
|
? maximumNearOptimalBias - minimumNearOptimalBias
|
|
|
|
|
: std::numeric_limits<double>::infinity();
|
|
|
|
|
bool commonBiasStable = nearOptimalBiasSpread <=
|
|
|
|
|
qMax(1.0e-4, huberDelta * 0.05);
|
|
|
|
|
bool commonBiasStable = nearOptimalBiasSpread <= 1.0e-2;
|
|
|
|
|
bool horizontalAtBoundary =
|
|
|
|
|
halfShiftStepCount > 0 &&
|
|
|
|
|
qAbs(bestShiftStep) == halfShiftStepCount;
|
|
|
|
|
@ -7249,18 +7198,18 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
return invalidLoss;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double commonBias = huberCommonCenterRange(
|
|
|
|
|
double commonBias = commonMeanCenterRange(
|
|
|
|
|
shiftedPressureResidual,
|
|
|
|
|
shiftedDerivativeResidual,
|
|
|
|
|
diagnosticBegin,
|
|
|
|
|
diagnosticEnd);
|
|
|
|
|
double rawAlignedLoss = jointHuberRmsAround(
|
|
|
|
|
double rawAlignedLoss = jointRmseAround(
|
|
|
|
|
shiftedPressureResidual,
|
|
|
|
|
shiftedDerivativeResidual,
|
|
|
|
|
diagnosticBegin,
|
|
|
|
|
diagnosticEnd,
|
|
|
|
|
0.0);
|
|
|
|
|
double centeredAlignedLoss = jointHuberRmsAround(
|
|
|
|
|
double centeredAlignedLoss = jointRmseAround(
|
|
|
|
|
shiftedPressureResidual,
|
|
|
|
|
shiftedDerivativeResidual,
|
|
|
|
|
diagnosticBegin,
|
|
|
|
|
@ -7297,10 +7246,10 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// shapeLoss 是去除可信左右位移和稳健公共中心后的剩余误差。
|
|
|
|
|
double shapePressureLoss = huberRms(
|
|
|
|
|
// shapeLoss 是去除可信左右位移和公共均值中心后的剩余误差。
|
|
|
|
|
double shapePressureLoss = rmse(
|
|
|
|
|
shapePressure, diagnosticBegin, diagnosticEnd);
|
|
|
|
|
double shapeDerivativeLoss = huberRms(
|
|
|
|
|
double shapeDerivativeLoss = rmse(
|
|
|
|
|
shapeDerivative, diagnosticBegin, diagnosticEnd);
|
|
|
|
|
if(!isFiniteNumber(shapePressureLoss) ||
|
|
|
|
|
!isFiniteNumber(shapeDerivativeLoss)) {
|
|
|
|
|
@ -7333,7 +7282,7 @@ double nmCalculationAutoFitPSO::calculateLogLogCurveError(
|
|
|
|
|
0.5 * breakdown.pressureLoss +
|
|
|
|
|
0.5 * breakdown.derivativeLoss;
|
|
|
|
|
} else {
|
|
|
|
|
// 非代理总目标等于固定 100 维 Huber 等效残差的二范数;压力和
|
|
|
|
|
// 非代理总目标等于固定 100 维普通残差的二范数;压力和
|
|
|
|
|
// 导数各占一半能量。上下、左右和形状分量不参与候选排序与接受。
|
|
|
|
|
breakdown.total = qSqrt(
|
|
|
|
|
0.5 * breakdown.pressureLoss * breakdown.pressureLoss +
|
|
|
|
|
|