/// <summary> /// Build Stator in FEMM /// </summary> /// <param name="MaterialParams"></param> public override void BuildInFEMM(FEMM femm = null) { if (femm == null) { femm = FEMM.DefaultFEMM; } AbstractRotor Rotor = Motor.Rotor; bool fullbuild = Motor.GeneralParams.FullBuildFEMModel; // create material femm.mi_addmaterialSteel(SteelMaterialName, 1, 1, Lam_d, Lam_fill, FEMM.LaminationType.NotLaminated, BH.Select(p => p.b).ToArray(), BH.Select(p => p.h).ToArray()); femm.mi_addmaterialCopper(WireMaterialName, WireConduct, WireType, 1, WireDiameter); // create boundary femm.mi_addboundprop_Prescribed_A(BoundaryProperty, 0, 0, 0, 0); /////// Build half slot ////segments - lines femm.mi_addSegmentEx(xB, yB, xC, yC, Group_Lines_Stator); //BC femm.mi_addSegmentEx(xD, yD, xE, yE, Group_Lines_Stator); //DE femm.mi_addSegmentEx(xF, yF, xF, 0, Group_Lines_Stator); //FF1 if (yC != yCC) { femm.mi_addSegmentEx(xC, yC, xCC, yCC, Group_Lines_Stator);//CC' } //// arcsegments //BA double a = (Math.Atan(yA / xA) - Math.Atan(yB / xB)) * 180 / Math.PI; femm.mi_addArcEx(xB, yB, xA, yA, a, 1, Group_Lines_Stator); //DC' femm.mi_addArcEx(xD, yD, xCC, yCC, 90, 30, Group_Lines_Stator); //EF femm.mi_addArcEx(xF, yF, xE, yE, 90, 30, Group_Lines_Stator); //// the coil femm.mi_addSegmentEx(xD2, yD2, xE2, yE2, Group_Lines_Stator); femm.mi_addSegmentEx(xF2, yF2, xF2, 0, Group_Lines_Stator); femm.mi_addSegmentEx(xCC2, yCC2, xCC2, 0, Group_Lines_Stator); //CC2-D2 femm.mi_addArcEx(xD2, yD2, xCC2, yCC2, 90, 30, Group_Lines_Stator); //EF femm.mi_addArcEx(xF2, yF2, xE2, yE2, 90, 30, Group_Lines_Stator); ////// mirrored half to one femm.mi_clearselected(); femm.mi_selectgroup(Group_Lines_Stator); femm.mi_mirror(0, 0, 1, 0, FEMM.EditMode.group); //////// Build Q slots (copy) femm.mi_clearselected(); femm.mi_selectgroup(Group_Lines_Stator); femm.mi_selectgroup(Group_BlockLabel_Wire); if (fullbuild) { femm.mi_copyrotate(0, 0, 360.0 / Q, Q - 1, FEMM.EditMode.group); } else { femm.mi_copyrotate(0, 0, 360.0 / Q, Q / (2 * Rotor.p) - 1, FEMM.EditMode.group); // rotate so they match with rotor femm.mi_clearselected(); femm.mi_selectgroup(Group_Lines_Stator); femm.mi_selectgroup(Group_BlockLabel_Wire); // rotate angle to double shiftangle = -Rotor.alphaDegree + 180.0 / Q; femm.mi_moverotate(0, 0, shiftangle, FEMM.EditMode.group); } ////// Block labels (steel) femm.mi_addBlockLabelEx((xF + Rstator) / 2, 0, SteelMaterialName, Group_BlockLabel_Steel); /////// Stator outer lines (2 arcs) if (fullbuild) { femm.mi_addArcEx(Rstator, 0, -Rstator, 0, 180, 10, Group_Lines_Stator); femm.mi_addArcEx(-Rstator, 0, Rstator, 0, 180, 10, Group_Lines_Stator); } else { femm.mi_addArcEx(Rstator * Math.Cos(Rotor.alpha), -Rstator * Math.Sin(Rotor.alpha), Rstator * Math.Cos(Rotor.alpha), Rstator * Math.Sin(Rotor.alpha), 2 * Rotor.alphaDegree, 10, Group_Lines_Stator); } // Set boundary condition for outline stator femm.mi_clearselected(); if (fullbuild) { femm.mi_selectarcsegment(0, Rstator); femm.mi_selectarcsegment(0, -Rstator); } else { femm.mi_selectarcsegment(Rstator, 0); } femm.mi_setarcsegmentprop(10, BoundaryProperty, false, Group_Lines_Stator); /////// Wire, circuits in slot foreach (Circuit c in circuits) { femm.mi_addcircprop(c.name, c.current, c.circuitType); } double r = (xD + xE) / 2; foreach (Coil sci in coils) { int i = coils.IndexOf(sci); if (fullbuild) { //angle go clockwise from 3 o'clock (=0 degree in decarter), double aa = -2 * Math.PI * i / Q; double x = r * Math.Cos(aa); double y = r * Math.Sin(aa); femm.mi_addBlockLabelEx(x, y, WireMaterialName, Group_BlockLabel_Wire, sci.inCircuit, sci.Nturns); } else { //angle go clockwise from 3 o'clock (=0 degree in decarter), shift +pi/Q (to match rotor) int nn = Q / (2 * Rotor.p); double aa = -2 * Math.PI * i / Q + (nn % 2 == 0 ? Math.PI / Q : 0); double x = r * Math.Cos(aa); double y = r * Math.Sin(aa); if (aa > -Rotor.alpha || aa < -2 * Math.PI + Rotor.alpha) { femm.mi_addBlockLabelEx(x, y, WireMaterialName, Group_BlockLabel_Wire, sci.inCircuit, sci.Nturns); } } } if (fullbuild) { //pre-rotate stator (fullbuild only) femm.mi_clearselected(); femm.mi_selectgroup(Group_Lines_Stator); femm.mi_selectgroup(Group_BlockLabel_Wire); femm.mi_selectgroup(Group_BlockLabel_Steel); femm.mi_moverotate(0, 0, PreRotateAngle, FEMM.EditMode.group); } if (!fullbuild) { //build boundary of motor: 2 lines, anti-periodic String boundaryName = "stator-apb-1"; double x1 = Rinstator * Math.Cos(Rotor.alpha); double y1 = Rinstator * Math.Sin(Rotor.alpha); double x2 = Rstator * Math.Cos(Rotor.alpha); double y2 = Rstator * Math.Sin(Rotor.alpha); femm.mi_addSegmentEx(x1, y1, x2, y2, Group_Lines_Stator); femm.mi_addSegmentEx(x1, -y1, x2, -y2, Group_Lines_Stator); femm.mi_addboundprop_AntiPeriodic(boundaryName); femm.mi_clearselected(); femm.mi_selectsegment(x2, y2); femm.mi_selectsegment(x2, -y2); femm.mi_setsegmentprop(boundaryName, 0, true, false, Group_Lines_Stator); } }
/// <summary> /// Calculate points' coordinate /// </summary> public override void CalculatePoints() { alpha = Math.PI / Q; xA = Rinstator * Math.Cos(alpha); yA = Rinstator * Math.Sin(alpha); yB = BS0 / 2; xB = Math.Sqrt(Rinstator * Rinstator - yB * yB); xC = xB + HS0; yC = yB; // check error and fix BS1 (minimum = BS0) if (BS1 < BS0) { log.Info("BS1 changed from " + BS1 + " to " + BS0); BS1 = BS0; } //check error and fix HS1 (maximum =(BS1-BS0)/2) if (HS1 > (BS1 - BS0) / 2) { log.Info("HS1 changed from " + HS1 + " to " + ((BS1 - BS0) / 2)); HS1 = (BS1 - BS0) / 2; } xCC = xC; yCC = yC + (BS1 - BS0) / 2 - HS1; xD = xC + HS1; yD = BS1 / 2; xE = HS2 + xD; yE = BS2 / 2; xF = xE + RS; yF = yE - RS; // Slot conductor points Sslot = Math.PI * HS1 * HS1 / 2 + Math.PI * RS * RS / 2 + 2 * HS1 * yCC + 2 * RS * yF + (yD + yE) * (xE - xD); double Scu_base = (yCC + yF) * (xE - xD); double c = Scu_base - Kfill * Sslot; if (c <= 0) { double a = Math.PI / 2 * (HS1 * HS1 + RS * RS); double b = 2 * HS1 * yCC + 2 * RS * yF + (HS1 + RS) * (xE - xD); double dd = b * b - 4 * a * c; double kk = (-b + Math.Sqrt(dd)) / (2 * a); kk = 1 - kk; xC2 = xC + HS1 * kk; yC2 = yC; xCC2 = xCC + HS1 * kk; yCC2 = yCC; xD2 = xD; yD2 = yD - HS1 * kk; xE2 = xE; yE2 = yE - RS * kk; xF2 = xF - RS * kk; yF2 = yF; } else { double kk = Math.Sqrt(Kfill * Sslot / Scu_base); double xKK = (xD * yF + xE * yCC) / (yF + yCC); xC2 = xKK - (xKK - xD) * kk; yC2 = yCC * kk; xD2 = xC2; yD2 = yC2; xCC2 = xC2; yCC2 = yC2; xE2 = xKK + (xE - xKK) * kk; yE2 = yF * kk; xF2 = xE2; yF2 = yE2; } // Slot circuit info coils = new List <Coil>(Q); for (int i = 0; i < Q; i++) { coils.Add(new Coil()); } circuits = new List <Circuit>(); int coil_step = -1;//coil step [slot] // wrap try-catch because // anything can go wrong when handle string, parse int try { String[] s1 = WindingsConfig.Replace(" ", "").Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (String wd in s1)//each coil (circuit) { //each one like this: A:1-7,8-9 String[] s2 = wd.Split(new char[] { ':', ',', '-' }, StringSplitOptions.RemoveEmptyEntries);//s2[0]=A, s2[i]=1,s[i+1]=7,... circuits.Add(new Circuit(s2[0], FEMM.CircuitType.series, 0)); int i = 1; while (i < s2.Length) { int inslot = int.Parse(s2[i]) - 1; int outslot = int.Parse(s2[i + 1]) - 1; i += 2; coils[inslot].inCircuit = s2[0]; coils[inslot].Nturns = -NStrands; coils[outslot].inCircuit = s2[0]; coils[outslot].Nturns = NStrands; // calc coil step to get actual length of wire if (coil_step < 0) { coil_step = outslot - inslot; if (coil_step < 0) { coil_step += Q; } } } } } catch (Exception e) { addValidationInfo("WindingsConfig", e.Message, ParamValidationInfo.MessageType.Error); } // other parameters AbstractRotor Rotor = Motor.Rotor; int PhaseCount = (circuits.Count > 0) ? circuits.Count : 3; q = Q / (PhaseCount * 2 * Rotor.p); double Swire = (WireDiameter / 2) * (WireDiameter / 2) * Math.PI;//mm^2 // length outside slot = 1span+up-down double l2 = coil_step * 2 * Math.PI * (Rinstator + HS0 + HS1 + HS2 / 2) / Q + 2 * Math.Sqrt(Swire * NStrands / Math.PI) * 2.5; wirelength_oneturn = 2 * Motor.GeneralParams.MotorLength + 2 * l2;//mm resistancePhase = 1 / WireConduct * Rotor.p * q * NStrands * wirelength_oneturn * 1e-3 / Swire; // call base method base.CalculatePoints(); }