/// <summary> y = (a / x) + b の形の関数として Rt の減衰を計算する </summary> /// <returns>計算された予測Rtの日数を返す</returns> public int CalcAndCopyPredictRt(double[] rts, int startIdx, double[] predRt, int realDays, int extensionDays) { if (extensionDays == 0) { extensionDays = Constants.EXTENSION_DAYS; } double rt0 = rts[startIdx]; if (Fourstep) { // 多段階モード double decayFactor = 10000; double rt1 = Rt1; int daysToRt1 = DaysToRt1; //if (daysToRt1 < 1) daysToRt1 = Constants.DAYS_TO_NEXT_RT; double a1 = 0, b1 = 0; if (daysToRt1 > 0) { a1 = (rt0 - rt1) * (decayFactor + daysToRt1) * decayFactor / daysToRt1; b1 = rt0 - (a1 / decayFactor); } else { daysToRt1 = 0; rt1 = rt0; } // Rt1に到達してから double rt2 = Rt2; int daysToRt2 = DaysToRt2; //if (daysToRt2 == 0) daysToRt2 = Constants.DAYS_TO_NEXT_RT; double a2 = 0, b2 = 0; if (daysToRt2 > 0) { a2 = (rt1 - rt2) * (decayFactor + daysToRt2) * decayFactor / daysToRt2; b2 = rt1 - (a2 / decayFactor); } else { daysToRt2 = 0; rt2 = rt1; } // Rt2に到達してから double rt3 = Rt3; int daysToRt3 = DaysToRt3; //if (daysToRt3 == 0) daysToRt3 = Constants.DAYS_TO_NEXT_RT; double a3 = 0, b3 = 0; if (daysToRt3 > 0) { a3 = (rt2 - rt3) * (decayFactor + daysToRt3) * decayFactor / daysToRt3; b3 = rt2 - (a3 / decayFactor); } else { daysToRt3 = 0; rt3 = rt2; } // Rt3に到達してから double rt4 = Rt4; int daysToRt4 = DaysToRt4; //if (daysToRt4 == 0) daysToRt4 = Constants.DAYS_TO_NEXT_RT; double a4 = 0, b4 = 0; if (daysToRt4 > 0) { a4 = (rt3 - rt4) * (decayFactor + daysToRt4) * decayFactor / daysToRt4; b4 = rt3 - (a4 / decayFactor); } else { daysToRt4 = 0; rt4 = rt3; } // Rt4に到達してから double rt5 = Rt5; int daysToRt5 = DaysToRt5; //if (daysToRt5 == 0) daysToRt5 = Constants.DAYS_TO_NEXT_RT; double a5 = 0, b5 = 0; if (daysToRt5 > 0) { a5 = (rt4 - rt5) * (decayFactor + daysToRt5) * decayFactor / daysToRt5; b5 = rt4 - (a5 / decayFactor); } else { daysToRt5 = 0; rt5 = rt4; } // Rt5に到達してから double rt6 = Rt6; int daysToRt6 = DaysToRt6; //if (daysToRt6 == 0) daysToRt6 = Constants.DAYS_TO_NEXT_RT; double a6 = 0, b6 = 0; if (daysToRt6 > 0) { a6 = (rt5 - rt6) * (decayFactor + daysToRt6) * decayFactor / daysToRt6; b6 = rt5 - (a6 / decayFactor); } else { daysToRt6 = 0; rt6 = rt5; } int copyLen = ((daysToRt1 + daysToRt2 + daysToRt3 + daysToRt4 + daysToRt5 + daysToRt6)._lowLimit(realDays - startIdx) + extensionDays)._highLimit(predRt.Length - startIdx); double rt = 0; for (int i = 0; i < copyLen; ++i) { if (i == 0) { rt = rt0; } else if (daysToRt1 + daysToRt2 + daysToRt3 + daysToRt4 + daysToRt5 + daysToRt6 == 0) { rt = 0; } else if (i <= daysToRt1) { rt = a1 / (decayFactor + i) + b1; } else if (i <= daysToRt1 + daysToRt2) { rt = a2 / (decayFactor + i - daysToRt1) + b2; if (rt1 > rt2) { if (rt < rt2) { rt = rt2; } } else { if (rt > rt2) { rt = rt2; } } } else if (i <= daysToRt1 + daysToRt2 + daysToRt3) { rt = a3 / (decayFactor + i - daysToRt1 - daysToRt2) + b3; if (rt2 > rt3) { if (rt < rt3) { rt = rt3; } } else { if (rt > rt3) { rt = rt3; } } } else if (i <= daysToRt1 + daysToRt2 + daysToRt3 + daysToRt4) { rt = a4 / (decayFactor + i - daysToRt1 - daysToRt2 - daysToRt3) + b4; if (rt3 > rt4) { if (rt < rt4) { rt = rt4; } } else { if (rt > rt4) { rt = rt4; } } } else if (i <= daysToRt1 + daysToRt2 + daysToRt3 + daysToRt4 + daysToRt5) { rt = a5 / (decayFactor + i - daysToRt1 - daysToRt2 - daysToRt3 - daysToRt4) + b5; if (rt4 > rt5) { if (rt < rt5) { rt = rt5; } } else { if (rt > rt5) { rt = rt5; } } } else if (i <= daysToRt1 + daysToRt2 + daysToRt3 + daysToRt4 + daysToRt5 + daysToRt6) { rt = a6 / (decayFactor + i - daysToRt1 - daysToRt2 - daysToRt3 - daysToRt4 - daysToRt5) + b6; if (rt5 > rt6) { if (rt < rt6) { rt = rt6; } } else { if (rt > rt6) { rt = rt6; } } } predRt[startIdx + i] = rt; } return(copyLen); } else { // 2段階モード // ここの extensionDays には、移動平均のための余分な4日分がすでに追加されているので、これを max としてよい int copyLen = Math.Min(realDays - startIdx + extensionDays, predRt.Length - startIdx); int toOneLen = Math.Min(DaysToOne, copyLen); // 1st Stage (rt = a1 * / (factor1 + x) + b1) double rt1 = EasyRt1; double factor1 = DecayFactor; //if (factor1 < 1) factor1 = 50; //double a1 = Constants.CalcCoefficientA1(rt0, rt1, factor1, DaysToOne); //double b1 = Constants.CalcCoefficientB1(rt0, a1, factor1); (double a1, double b1) = Constants.CalcCoefficient1(rt0, rt1, factor1, DaysToOne); for (int i = 0; i < toOneLen; ++i) { predRt[startIdx + i] = Constants.CalcRt1(a1, b1, factor1, i); } // 2nd Stage double tgtRt2 = EasyRt2; double factor2 = DecayFactorNext; (double a2, double b2) = Constants.CalcCoefficients2(rt0, rt1, tgtRt2, factor2, DaysToOne); int ph3StartIdx = -1; double rt2 = Math.Min(rts._nth(startIdx + DaysToOne), rts[^ 1]) * 0.9; // 減衰の下限