/// <summary> /// Convert from abc to dq /// Theta is radian /// </summary> /// <param name="a">fa</param> /// <param name="b">fb</param> /// <param name="c">fc</param> /// <param name="theta">Angle (radian) from 0a to 0d (counter clockwise)</param> /// <returns></returns> public static Fdq abc_dq(double a, double b, double c, double theta) { Fdq fdq = new Fdq(); fdq.d = 2.0 / 3 * (Math.Cos(theta) * a + Math.Cos(theta - 2 * Math.PI / 3) * b + Math.Cos(theta + 2 * Math.PI / 3) * c); fdq.q = -2.0 / 3 * (Math.Sin(theta) * a + Math.Sin(theta - 2 * Math.PI / 3) * b + Math.Sin(theta + 2 * Math.PI / 3) * c); return(fdq); }
public static Fabc dq_abc(Fdq fdq, double theta) { return(dq_abc(fdq.d, fdq.q, theta)); }
private VoltageLimitEllipse buildVoltageLimitEllipse(double speed, int count = 50, double Imax = 55, double Umax = 140) { var vle = new VoltageLimitEllipse { speed = speed, Imax = Imax, Umax = Umax, curve = new List <Fdq>(), torques = new List <double>(), }; double maxt = 0; bool minfound = false; int index = 0; for (int j = 0; j < count + 1; j++) { double id = -Imax * j / count; double iq; double t = 0; bool bb = Brent.TryFindRoot(iq_ => { var d = calculatePointdata(id, iq_, speed); double u = Math.Sqrt(d.ud * d.ud + d.uq * d.uq); t = d.torque; return(u - Umax); }, 0, Imax, 1e-5, 100, out iq); if (bb) { var idq = new Fdq { d = id, q = iq }; if (maxt < t) { maxt = t; vle.maxtorque_point = index; } if (!minfound) { vle.minid_point = index; minfound = true; } vle.curve.Add(idq); vle.torques.Add(t); index++; } } if (vle.curve[0].d < 0) { Fdq idq1 = vle.curve[0]; Fdq idq2 = vle.curve[1]; Fdq idq0 = new Fdq { d = idq1.d + (Imax / count) * (idq1.q / idq2.q) / (1 - idq1.q / idq2.q), q = 0, }; vle.curve.Insert(0, idq0); vle.torques.Insert(0, 0); vle.maxtorque_point++; } return(vle); }
private EfficiencyMap buildEfficiencyMap(int torque_count, int speed_count, double Imax, double Umax, double max_speed) { MaxtorqueCapabilityCurve mtcc = buildMaxtorqueCapabilityCurve(speed_count, Imax, Umax, max_speed); VoltageLimitCurve vlc = buildVoltageLimitCurve(speed_count, Imax, Umax, max_speed); var em = new EfficiencyMap() { // input Imax = Imax, Umax = Umax, MaxSpeed = max_speed, // axis speed_points = new double[speed_count + 1], torque_points = new double[torque_count + 1], // value power = new double[speed_count + 1, torque_count + 1], windingloss = new double[speed_count + 1, torque_count + 1], rotor_coreloss = new double[speed_count + 1, torque_count + 1], stator_coreloss = new double[speed_count + 1, torque_count + 1], coreloss = new double[speed_count + 1, torque_count + 1], totalloss = new double[speed_count + 1, torque_count + 1], efficiency = new double[speed_count + 1, torque_count + 1], voltage = new double[speed_count + 1, torque_count + 1], current = new double[speed_count + 1, torque_count + 1], beta = new double[speed_count + 1, torque_count + 1], Ld = new double[speed_count + 1, torque_count + 1], Lq = new double[speed_count + 1, torque_count + 1], }; em.power.Fill2D(double.NaN); em.windingloss.Fill2D(double.NaN); em.rotor_coreloss.Fill2D(double.NaN); em.stator_coreloss.Fill2D(double.NaN); em.coreloss.Fill2D(double.NaN); em.totalloss.Fill2D(double.NaN); em.efficiency.Fill2D(double.NaN); em.voltage.Fill2D(double.NaN); em.current.Fill2D(double.NaN); em.beta.Fill2D(double.NaN); em.Ld.Fill2D(double.NaN); em.Lq.Fill2D(double.NaN); var mtpa = buildTableMaxtorquePerAmple(); double max_t = mtpa.GetMaxTorqueWithCurrentMagnitude(Imax); LinearSpline torqueCapabilityLimit = LinearSpline.Interpolate(mtcc.speeds, mtcc.maxtorques); for (int i = 0; i < speed_count + 1; i++) { for (int j = 0; j < torque_count + 1; j++) { // speed double speed = max_speed * i / speed_count; em.speed_points[i] = speed; // torque double t = max_t * j / torque_count; em.torque_points[j] = t; double max_possible_torque = torqueCapabilityLimit.Interpolate(speed); if (t > max_possible_torque) { continue; } // speed limit 1 double speed1 = vlc.GetMaxSpeedForTorque(t); APointData data = null; if (t == 0) { data = calculatePointdata(0, 0, speed); } // zone 1 else if (speed <= speed1) { Fdq idq = mtpa.GetCurrentForTorque(t); if (double.IsNaN(idq.d) || double.IsNaN(idq.q)) { data = null; } else { data = calculatePointdata(idq.d, idq.q, speed); } } else { Fdq idq = getCurrentForZone2(t, speed, Imax, Umax); if (double.IsNaN(idq.d) || double.IsNaN(idq.q)) { data = null; } else { data = calculatePointdata(idq.d, idq.q, speed); } } if (data != null) { em.rotor_coreloss[i, j] = data.rotorloss; em.stator_coreloss[i, j] = data.statorloss; em.coreloss[i, j] = data.rotorloss + data.statorloss; em.windingloss[i, j] = data.copperloss; em.totalloss[i, j] = data.copperloss + data.rotorloss + data.statorloss; em.power[i, j] = data.power; em.efficiency[i, j] = 100 * data.power / (data.power + em.totalloss[i, j]); em.voltage[i, j] = data.voltage; em.current[i, j] = data.current; em.beta[i, j] = data.beta; em.Ld[i, j] = double.IsNaN(data.Ld) || data.Ld < 0 ? -0.0001 : data.Ld * 1000; //to mH em.Lq[i, j] = double.IsNaN(data.Ld) || data.Ld < 0 ? -0.0001 : data.Lq * 1000; //to mH } } } return(em); }
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); }