public MinParams extendDaysAndCalcRt1(double rt0, int extendedDayIdx) { //double a = calcCoefficientA1(rt0); //double b = calcCoefficientB1(rt0, a); (double a, double b) = Constants.CalcCoefficient1(rt0, rt1, ft1, dayIdx); var rt = Constants.CalcRt1(a, b, ft1, extendedDayIdx); if (rt > 0) { rt1 = rt; dayIdx = extendedDayIdx; } return(this); }
/// <summary> /// Rt1, dasyTo1, factor1 を求める /// </summary> /// <param name="rts"></param> /// <param name="startIdx"></param> /// <returns></returns> private MinParams find_rt1(DateTime dt, double[] rts, int startIdx, int days) { MinParams minp = new MinParams() { startDt = dt }; if (rts._isEmpty() || startIdx < 0 || startIdx >= rts.Length) { return(minp); } int daysToEnd = rts.Length - startIdx - 1; if (days > 0 && days < daysToEnd) { return(minp); } int chgDtIdx = days < 1 ? daysToEnd : days._highLimit(100); // 変日化のインデックス minp.dayIdx = chgDtIdx; double calcSquareErr(double rt0, double rt1, double factor1) { //double a = Constants.CalcCoefficientA1(rt0, rt1, factor1, chgDtIdx); //double b = Constants.CalcCoefficientB1(rt0, a, factor1); (double a, double b) = Constants.CalcCoefficient1(rt0, rt1, factor1, chgDtIdx); return(rts.Skip(startIdx).Select((y, x) => Math.Pow(Constants.CalcRt1(a, b, factor1, x) - y, 2)).Sum()); } double rt0 = rts[startIdx]._highLimit(Constants.RT_THRESHOLD2); int[] decayFactors1 = Pages.MyChart._decayFactors; double delta = 0.05; double tail_rt = rts[^ 1]._highLimit(Constants.RT_THRESHOLD2);
/// <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; // 減衰の下限