From d0c0f70d8b65f4e8ce900a409fec88ae7d254f5e Mon Sep 17 00:00:00 2001 From: lvjunjie Date: Tue, 1 Sep 2026 22:38:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=B6=E9=97=B4=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E7=8E=87=E7=9A=84=E9=99=90=E5=88=B6=EF=BC=8C=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E8=A6=86=E7=9B=96=E7=8E=87=E4=B8=8D=E8=B6=B3=E8=80=8C?= =?UTF-8?q?=E6=8B=9F=E5=90=88=E5=A4=B1=E8=B4=A5=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nmCalculation/nmCalculationAutoFitLM.h | 2 - .../nmCalculation/nmCalculationAutoFitLM.cpp | 127 ++++-------------- 2 files changed, 23 insertions(+), 106 deletions(-) diff --git a/Include/nmNum/nmCalculation/nmCalculationAutoFitLM.h b/Include/nmNum/nmCalculation/nmCalculationAutoFitLM.h index 71e22de..b1b8b38 100644 --- a/Include/nmNum/nmCalculation/nmCalculationAutoFitLM.h +++ b/Include/nmNum/nmCalculation/nmCalculationAutoFitLM.h @@ -32,7 +32,6 @@ struct AutoFitObjectiveBreakdownLM { double lateDerivativeSlopeBias; double lateDerivativeTrendLoss; bool lateDerivativeTrendReliable; - double coverage; AutoFitObjectiveBreakdownLM() : valid(false) @@ -50,7 +49,6 @@ struct AutoFitObjectiveBreakdownLM { , lateDerivativeSlopeBias(std::numeric_limits::quiet_NaN()) , lateDerivativeTrendLoss(std::numeric_limits::quiet_NaN()) , lateDerivativeTrendReliable(false) - , coverage(std::numeric_limits::quiet_NaN()) {} }; diff --git a/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp b/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp index a3bac99..3505ed8 100644 --- a/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationAutoFitLM.cpp @@ -860,8 +860,7 @@ void nmCalculationAutoFitLM::writeTraceHeader() << "late_trend_loss" << "late_slope_bias" << "late_trend_reliable" - << "registration_ambiguous" - << "coverage"; + << "registration_ambiguous"; QTextStream out(&m_traceFile); out << cols.join(",") << "\n"; @@ -978,10 +977,9 @@ void nmCalculationAutoFitLM::writeTraceRow( << traceNumber(objectiveBreakdown->lateDerivativeTrendLoss) << traceNumber(objectiveBreakdown->lateDerivativeSlopeBias) << QString::number(objectiveBreakdown->lateDerivativeTrendReliable ? 1 : 0) - << QString::number(objectiveBreakdown->registrationAmbiguous ? 1 : 0) - << traceNumber(objectiveBreakdown->coverage); + << QString::number(objectiveBreakdown->registrationAmbiguous ? 1 : 0); } else { - for(int i = 0; i < 14; ++i) { + for(int i = 0; i < 13; ++i) { cols << QString(); } } @@ -3247,12 +3245,11 @@ double nmCalculationAutoFitLM::calculateLogLogCurveError( const QVector >& target, const QVector >& result) const { - // 主目标只比较固定网格上的压力和导数残差;上下、左右和形状只负责诊断 - // 误差来源和选择参数,避免同一残差在 total 中被重复计算。整个计算过程均 - // 位于 log(time)-log(value) 坐标,因此得到的是相对尺度偏差而非原始压力量纲。 + // 主目标在目标与模拟曲线的公共时间范围内比较压力和导数残差;上下、左右 + // 和形状只负责诊断误差来源和选择参数,避免同一残差在 total 中被重复计算。 + // 整个计算过程均位于 log(time)-log(value) 坐标。 const double invalidLoss = 1.0e10; const double valueFloor = 1.0e-12; - const double minimumCoverage = 0.95; const int numPoints = 80; m_lastObjectiveBreakdown = AutoFitObjectiveBreakdownLM(); @@ -3369,34 +3366,6 @@ double nmCalculationAutoFitLM::calculateLogLogCurveError( return isFiniteNumber(*value); }; - // 覆盖率通过后若只缺少首尾少量点,用模拟曲线自身的端点斜率作短距离 - // 双对数外推。该外推只用于主损失的固定网格,不参与水平配准搜索。 - auto extrapolateEndpointLogValue = [valueFloor]( - const QVector& curve, - double x, - double* value) -> bool { - if(!value || curve.size() < 2 || x <= 0.0) { - return false; - } - int left = x < curve.first().x() - ? 0 - : curve.size() - 2; - int right = left + 1; - double leftLogX = qLn(curve[left].x()); - double rightLogX = qLn(curve[right].x()); - double denominator = rightLogX - leftLogX; - if(qAbs(denominator) <= 1.0e-12) { - return false; - } - double leftLogY = - qLn(qMax(qAbs(curve[left].y()), valueFloor)); - double rightLogY = - qLn(qMax(qAbs(curve[right].y()), valueFloor)); - double ratio = (qLn(x) - leftLogX) / denominator; - *value = leftLogY + ratio * (rightLogY - leftLogY); - return isFiniteNumber(*value); - }; - const double targetMinX = targetPressure.first().x(); const double targetMaxX = targetPressure.last().x(); const double resultMinX = resultPressure.first().x(); @@ -3406,25 +3375,33 @@ double nmCalculationAutoFitLM::calculateLogLogCurveError( return invalidLoss; } + // 与 PSO 保持一致:只在目标与模拟曲线的时间交集内比较,不再设置 + // 覆盖率门槛,也不对交集之外的首尾数据做外推。 + const double overlapMinX = qMax(targetMinX, resultMinX); + const double overlapMaxX = qMin(targetMaxX, resultMaxX); + if(overlapMinX >= overlapMaxX) { + return invalidLoss; + } + QVector commonX(numPoints); QVector commonLogX(numPoints); QVector targetLogPressure(numPoints); QVector targetLogDerivative(numPoints); - const double targetLogMinX = qLn(targetMinX); - const double targetLogMaxX = qLn(targetMaxX); + const double comparisonLogMinX = qLn(overlapMinX); + const double comparisonLogMaxX = qLn(overlapMaxX); - // 固定使用目标曲线的完整 log-time 网格,候选之间不会因采样点不同而失去可比性。 + // 在公共时间范围内生成固定维度的 log-time 网格,保持 LM 残差向量为 160 维。 for(int i = 0; i < numPoints; ++i) { - double logX = targetLogMinX + + double logX = comparisonLogMinX + static_cast(i) * - (targetLogMaxX - targetLogMinX) / + (comparisonLogMaxX - comparisonLogMinX) / (numPoints - 1); commonLogX[i] = logX; // 首尾直接使用原始端点,避免 exp(log(t)) 的舍入误差越过严格插值边界。 if(i == 0) { - commonX[i] = targetMinX; + commonX[i] = overlapMinX; } else if(i == numPoints - 1) { - commonX[i] = targetMaxX; + commonX[i] = overlapMaxX; } else { commonX[i] = qExp(logX); } @@ -3443,16 +3420,9 @@ double nmCalculationAutoFitLM::calculateLogLogCurveError( numPoints, std::numeric_limits::quiet_NaN()); QVector derivativeResidual( numPoints, std::numeric_limits::quiet_NaN()); - int firstSupported = -1; - int lastSupported = -1; - int supportedCount = 0; // 残差定义为“模拟减目标”:正值表示模拟曲线偏高,负值表示偏低。 for(int i = 0; i < numPoints; ++i) { - if(commonX[i] < resultMinX || commonX[i] > resultMaxX) { - continue; - } - double resultLogPressure = 0.0; double resultLogDerivative = 0.0; if(!interpolateLogValue( @@ -3469,59 +3439,9 @@ double nmCalculationAutoFitLM::calculateLogLogCurveError( resultLogPressure - targetLogPressure[i]; derivativeResidual[i] = resultLogDerivative - targetLogDerivative[i]; - ++supportedCount; - if(firstSupported < 0) { - firstSupported = i; - } - lastSupported = i; } - // 覆盖率同时约束“有效点数量”和“连续时间跨度”。取两者较小值可避免 - // 点数很多但只集中在局部时段的候选被误认为覆盖充分。 AutoFitObjectiveBreakdownLM breakdown; - breakdown.coverage = supportedCount > 0 - ? static_cast(supportedCount) / - numPoints - : 0.0; - if(firstSupported >= 0 && lastSupported >= firstSupported) { - double targetSpan = - qMax(1.0e-12, targetLogMaxX - targetLogMinX); - double coveredSpan = - commonLogX[lastSupported] - commonLogX[firstSupported]; - breakdown.coverage = qMin( - breakdown.coverage, - qMax(0.0, coveredSpan / targetSpan)); - } - - // 覆盖率只判断候选是否有效,不再加入固定惩罚,避免所有误差被整体抬高。 - if(breakdown.coverage < minimumCoverage) { - breakdown.total = invalidLoss; - m_lastObjectiveBreakdown = breakdown; - return invalidLoss; - } - - // 通过门槛后最多只缺少首尾少量目标点。按模拟曲线端点趋势补齐后, - // 每个候选仍在固定 80 点上计算均方根误差,不能靠少算难拟合端点获益。 - for(int i = 0; i < numPoints; ++i) { - if(isFiniteNumber(pressureResidual[i]) && - isFiniteNumber(derivativeResidual[i])) { - continue; - } - double resultLogPressure = 0.0; - double resultLogDerivative = 0.0; - if(!extrapolateEndpointLogValue( - resultPressure, commonX[i], - &resultLogPressure) || - !extrapolateEndpointLogValue( - resultDerivative, commonX[i], - &resultLogDerivative)) { - return invalidLoss; - } - pressureResidual[i] = - resultLogPressure - targetLogPressure[i]; - derivativeResidual[i] = - resultLogDerivative - targetLogDerivative[i]; - } // 在指定中心附近计算普通均方根误差。 auto rmseAround = []( @@ -3648,7 +3568,7 @@ double nmCalculationAutoFitLM::calculateLogLogCurveError( } const double logGridStep = - (targetLogMaxX - targetLogMinX) / + (comparisonLogMaxX - comparisonLogMinX) / (numPoints - 1); const double resultLogMinX = qLn(resultMinX); const double resultLogMaxX = qLn(resultMaxX); @@ -4091,7 +4011,7 @@ double nmCalculationAutoFitLM::calculateLogLogCurveError( m_lastObjectiveBreakdown = breakdown; DEBUG_OUT( - QString("LogLog objective: pressure=%1, derivative=%2, vertical=%3, horizontal=%4, shape=%5, ambiguous=%6, shift=%7, coverage=%8, total=%9") + QString("LogLog objective: pressure=%1, derivative=%2, vertical=%3, horizontal=%4, shape=%5, ambiguous=%6, shift=%7, total=%8") .arg(breakdown.pressureLoss, 0, 'e', 4) .arg(breakdown.derivativeLoss, 0, 'e', 4) .arg(breakdown.verticalLoss, 0, 'e', 4) @@ -4099,7 +4019,6 @@ double nmCalculationAutoFitLM::calculateLogLogCurveError( .arg(breakdown.shapeLoss, 0, 'e', 4) .arg(breakdown.registrationAmbiguous) .arg(breakdown.horizontalPhysicalShift, 0, 'e', 4) - .arg(breakdown.coverage, 0, 'f', 4) .arg(breakdown.total, 0, 'e', 4)); return breakdown.valid