public void NoRoot() { Func <double, double> f1 = x => x * x + 4; Assert.Throws <NonConvergenceException>(() => Brent.FindRoot(f1, -5, 5, 1e-14, 50)); }
private MaxtorqueCapabilityCurve buildMaxtorqueCapabilityCurve(int count = 50, double Imax = 55, double Umax = 140, double max_speed = 6000) { var mtpa = buildTableMaxtorquePerAmple(); MaxtorqueCapabilityCurve mtcc = new MaxtorqueCapabilityCurve() { Imax = Imax, Umax = Umax, MaxSpeed = max_speed, }; // Look for beta to get max torque double max_t = mtpa.GetMaxTorqueWithCurrentMagnitude(Imax); Fdq idq = mtpa.GetCurrentForTorque(max_t); // Create PointPairList // look for speed1 var speed1 = Brent.FindRoot(s => { var data_ = calculatePointdata(idq.d, idq.q, s); var u_ = Math.Sqrt(data_.ud * data_.ud + data_.uq * data_.uq); return(u_ - Umax); }, 100, max_speed, 1e-3); // speed by speed int count1 = (int)(speed1 / max_speed * count) + 1; int count2 = count - count1; for (int i = 1; i < count1 + 1; i++) { double speed = speed1 * i / count1; var data = calculatePointdata(idq.d, idq.q, speed); mtcc.speeds.Add(speed); mtcc.maxtorques.Add(data.torque); mtcc.currents.Add(idq); mtcc.voltages.Add(new Fdq() { d = data.ud, q = data.uq }); mtcc.power.Add(data.power); mtcc.effs.Add(data.efficiency); } double t = max_t; for (int i = 1; i < count2 + 1; i++) { double speed = speed1 + (max_speed - speed1) * i / count2; // find beta which make U=Umax //double beta = 0; //bool success = Brent.TryFindRoot(b => //{ // var data_ = calculatePointdata(Imax * Math.Cos(b * Math.PI / 180), Imax * Math.Sin(b * Math.PI / 180), speed); // var u_ = Math.Sqrt(data_.ud * data_.ud + data_.uq * data_.uq); // return u_ - Umax; //}, 100, 180, 1e-5, 100, out beta); // Here: // Find Id,Iq that bring max torque at speed // it is intersect of circle Imax and ellipse Umax/w if Imax < ellipse center (-psiM/Ld) // or ellipse center itself if Imax > ellipse center Fdq idq2 = default(Fdq); bool found = false; var vle = buildVoltageLimitEllipse(speed, 1000, Imax, Umax); var maxtorque_point = vle.curve[vle.maxtorque_point]; var minid_point = vle.curve[vle.minid_point]; if (maxtorque_point.Magnitude <= Imax) { idq2 = new Fdq { d = maxtorque_point.d, q = maxtorque_point.q }; found = true; } else if (minid_point.Magnitude > Imax) //Imax out of ellipse { found = false; } else { var range = Enumerable.Range(0, vle.maxtorque_point); LinearSpline spline = LinearSpline.Interpolate(range.Select(k => vle.curve[k].Magnitude), range.Select(k => vle.curve[k].d)); double id = spline.Interpolate(Imax); double iq = Math.Sqrt(Imax * Imax - id * id); idq2 = new Fdq { d = id, q = iq }; found = true; } if (found) { //double id = idq2.d;//Imax * Math.Cos(beta * Math.PI / 180); //double iq = idq2.q;//Imax * Math.Sin(beta * Math.PI / 180); var data = calculatePointdata(idq2.d, idq2.q, speed); mtcc.speeds.Add(speed); mtcc.maxtorques.Add(data.torque); mtcc.currents.Add(idq2); mtcc.voltages.Add(new Fdq() { d = data.ud, q = data.uq }); mtcc.power.Add(data.power); mtcc.effs.Add(data.efficiency); } } return(mtcc); }
/// <summary> /// Compute the time duration for a <see cref="EbisuModel"/> to decay to /// a given percentile. /// </summary> /// <param name="model">Given model for the fact.</param> /// <param name="percentile">Target percentile for the decay.</param> /// <param name="coarse">If true, use an approximation for the duration returned.</param> /// <param name="tolerance">Allowed tolerance for the duration.</param> /// <returns>Duration in time units (of provided model) for the decay to given percentile.</returns> private static double ModelToPercentileDecay( this EbisuModel model, double percentile, bool coarse, double tolerance) { if (percentile < 0 || percentile > 1) { throw new ArgumentException( "Percentiles must be between (0, 1) exclusive", nameof(percentile)); } double alpha = model.Alpha; double beta = model.Beta; double t0 = model.Time; double logBab = BetaLn(alpha, beta); double logPercentile = Math.Log(percentile); Func <double, double> f = lndelta => { return((BetaLn(alpha + Math.Exp(lndelta), beta) - logBab) - logPercentile); }; double bracketWidth = coarse ? 1.0 : 6.0; double blow = -bracketWidth / 2.0; double bhigh = bracketWidth / 2.0; double flow = f(blow); double fhigh = f(bhigh); while (flow > 0 && fhigh > 0) { // Move the bracket up. blow = bhigh; flow = fhigh; bhigh += bracketWidth; fhigh = f(bhigh); } while (flow < 0 && fhigh < 0) { // Move the bracket down. bhigh = blow; fhigh = flow; blow -= bracketWidth; flow = f(blow); } if (!(flow > 0 && fhigh < 0)) { throw new EbisuConstraintViolationException($"Failed to bracket: flow={flow}, fhigh={fhigh}"); } if (coarse) { return((Math.Exp(blow) + Math.Exp(bhigh)) / 2 * t0); } // Similar to the `root_scalar` api with bracketing // See https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.root_scalar.html#scipy.optimize.root_scalar var sol = Brent.FindRoot(f, blow, bhigh); return(Math.Exp(sol) * t0); }