protected override void DoModifyStator(TransientStepArgs args, FEMM femm) { // run script to update IA,IB,IC NLua.Lua lua_state = LuaHelper.GetLuaState(); String[] currentFormulas = { IA, IB, IC }; String[] circuitNames = { "A", "B", "C" }; lock (lockLua) { try { lua_state["step"] = args.step; lua_state["time"] = args.time; lua_state["omega"] = RotorSpeedRadSecond; for (int i = 0; i < currentFormulas.Length; i++) { double Ix = (double)lua_state.DoString("return " + currentFormulas[i])[0]; args.currents[circuitNames[i]] = Ix; } } catch (Exception ex) { log.Error("Lua error :" + ex.Message); } } base.DoModifyStator(args, femm); }
private void runAllTransientAnalysis_Sync() { // make sure femm file is created if (!Motor.isFEMModelReady(CurrentFEMMFile)) { Motor.BuildFEMModel(CurrentFEMMFile); } // run static first runStaticAnalysis(); sw = new Stopwatch(); sw.Start(); // now run the transient analysis foreach (String name in TransAnalysisGroup.Keys) { // un-subcribe event TransAnalysisGroup[name].OnFinishedAnalysis -= OnFinishAnalysis_internal; // run in sync TransAnalysisGroup[name].RunAnalysis(); // close all opened FEMM.CloseFemm(); } sw.Stop(); log.Info("Analysis time :" + sw.Elapsed.TotalSeconds + "s"); refreshAnalysisResults(); OnMotorAnalysisResultsUpdate(this, null); }
protected override void analyze() { FEMM femm = FEMM.DefaultFEMM; // open original femm file femm.open(Path_OriginalFEMFile); // modify current, freq femm.mi_probdef(Freq, FEMM.UnitsType.millimeters, FEMM.ProblemType.planar, 1e-8, Motor.GeneralParams.MotorLength, 7, FEMM.ACSolverType.Succ_Approx); string ia = string.Format("{0}", Current); string ib = string.Format("{0}+I*{1}", Current * Math.Cos(-2 * Math.PI / 3), Current * Math.Sin(-2 * Math.PI / 3)); string ic = string.Format("{0}+I*{1}", Current * Math.Cos(2 * Math.PI / 3), Current * Math.Sin(2 * Math.PI / 3)); femm.mi_modifycircuitCurrent("A", ia); femm.mi_modifycircuitCurrent("B", ib); femm.mi_modifycircuitCurrent("C", ic); // save as new file and analyze femm.mi_saveas(WorkingFEMFile); femm.mi_analyze(true); femm.mi_close(); femm.open(WorkingANSFile); measureData(femm); femm.mo_close(); }
public void runStaticAnalysis() { // load from disk first staticAnalyser.LoadResultsFromDisk(); if (staticAnalyser.Results == null) { FEMM.CloseFemm(); // make sure ans file is created if (!Motor.isFEMModelReady(CurrentFEMMFile)) { Motor.BuildFEMModel(CurrentFEMMFile); } staticAnalyser.OnFinishedAnalysis -= staticAnalyser_OnFinishedAnalysis; staticAnalyser.OnFinishedAnalysis += staticAnalyser_OnFinishedAnalysis; // do measure staticAnalyser.RunAnalysis(); FEMM.CloseFemm(); } else { staticAnalyser_OnFinishedAnalysis(this, staticAnalyser.Results); } }
protected override void analyze() { // steps numbering are put in queue for multi-thread Queue <int> steps = new Queue <int>(); Queue <double> currents = new Queue <double>(); for (int i = 0; i < ResultCount; i++) { steps.Enqueue(i); } // for multi-thread config int threadCount = 4; if (FEMMToUse != null && FEMMToUse.Count > 0) { threadCount = FEMMToUse.Count; } if (threadCount > steps.Count) { threadCount = steps.Count; } ManualResetEvent[] MREs = new ManualResetEvent[threadCount]; FEMM[] femms = new FEMM[threadCount]; for (int i = 0; i < threadCount; i++) { MREs[i] = new ManualResetEvent(false); if (FEMMToUse != null && FEMMToUse.Count > 0) { femms[i] = FEMMToUse[i]; } else { femms[i] = new FEMM(); } } // start all threads for (int i = 0; i < threadCount; i++) { ManualResetEvent mre = MREs[i]; FEMM femm = femms[i]; new Thread(delegate() { while (steps.Count > 0) { AnalyzeOne(steps.Dequeue(), femm); } mre.Set(); }).Start(); } // wait for all thread to finish for (int i = 0; i < threadCount; i++) { MREs[i].WaitOne(); } }
private void mmAnalysis_OnFinishedAnalysis(object sender, AbstractResults e) { sw.Stop(); FEMM.CloseFemm(); refreshAnalysisResults(); OnMotorAnalysisResultsUpdate(this, null); }
protected virtual void DoMeasureData(TransientStepArgs args, FEMM femm) { Dictionary <String, FEMM.CircuitProperties> cps = Motor.Stator.getCircuitsPropertiesInAns(femm); double torque = Motor.Rotor.getTorqueInAns(femm); args.Torque = torque; args.RotorAngle = args.RotorAngle; args.CircuitProperties = cps; }
private void dqcurrentAnalyser_OnFinishedAnalysis(object sender, AbstractResults e) { sw.Stop(); log.Info("Analysis time :" + sw.Elapsed.TotalSeconds + "s"); FEMM.CloseFemm(); refreshAnalysisResults(); OnMotorAnalysisResultsUpdate(this, null); }
private void bt_sweep_Click(object sender, EventArgs e) { sweeper.OnFinishSweep -= new EventHandler <ParamSweeperResults>(sweeper_OnFinishSweep); sweeper.OnFinishSweep += new EventHandler <ParamSweeperResults>(sweeper_OnFinishSweep); FEMM.CloseFemm(); new Thread(new ThreadStart(sweeper.doSweep)).Start(); }
/// <summary> /// Call this function on each step analysis to gather Bx,By data /// </summary> /// <param name="args"></param> /// <param name="femm"></param> public void GatherData(TransientStepArgs args, FEMM femm) { //rotate double xRotorAngle = args.RotorAngle; if (isRotor) { // normalize, make rotorAngle inside (-2alpha,2alpha) xRotorAngle = analyser.Motor.GetNormalizedRotorAngle(args.RotorAngle); //convert to radian xRotorAngle *= Math.PI / 180; } // get flux density of all elements in stator for 1 step for (int i = 0; i < elements.Count; i++) { var e = elements[i]; double x = e.center.X; double y = e.center.Y; //rotate if (isRotor) { double xx = x * Math.Cos(xRotorAngle) - y * Math.Sin(xRotorAngle); double yy = x * Math.Sin(xRotorAngle) + y * Math.Cos(xRotorAngle); x = xx; y = yy; } var pv = femm.mo_getpointvalues(x, y); if (isRotor) { double xx = pv.B1 * Math.Cos(-xRotorAngle) - pv.B2 * Math.Sin(-xRotorAngle); double yy = pv.B1 * Math.Sin(-xRotorAngle) + pv.B2 * Math.Cos(-xRotorAngle); pv.B1 = xx; pv.B2 = yy; xx = pv.H1 * Math.Cos(-xRotorAngle) - pv.H2 * Math.Sin(-xRotorAngle); yy = pv.H1 * Math.Sin(-xRotorAngle) + pv.H2 * Math.Cos(-xRotorAngle); pv.H1 = xx; pv.H2 = yy; } Bx[i][args.step] = pv.B1; By[i][args.step] = pv.B2; Hx[i][args.step] = pv.H1; Hy[i][args.step] = pv.H2; } }
void sweeper_OnFinishSweep(object sender, ParamSweeperResults e) { if (InvokeRequired) { BeginInvoke((Action) delegate() { sweeper_OnFinishSweep(sender, e); }); return; } FEMM.CloseFemm(); showResultsInDGV(e.ResultsTable); }
public override void RotateRotorInFEMM(double rotorAngle, FEMM femm = null) { if (femm == null) { femm = FEMM.DefaultFEMM; } femm.mi_selectgroup(Group_Lines_Rotor); femm.mi_selectgroup(Group_BlockLabel_Magnet_Air); femm.mi_selectgroup(Group_BlockLabel_Steel); femm.mi_moverotate(0, 0, rotorAngle, FEMM.EditMode.group); }
protected virtual void DoModifyRotor(TransientStepArgs args, FEMM femm) { // clear the way (line-boundary conditional in airgap) Motor.Airgap.RemoveBoundary(femm); // normalize, make rotorAngle inside (-2alpha,2alpha) double xRotorAngle = Motor.GetNormalizedRotorAngle(args.RotorAngle); // rotate rotor Motor.Rotor.RotateRotorInFEMM(xRotorAngle, femm); // modify airgap (in case partial build) Motor.Airgap.AddBoundaryAtAngle(xRotorAngle, femm); }
public override double getTorqueInAns(FEMM femm) { femm.mo_clearblock(); femm.mo_groupselectblock(Group_BlockLabel_Magnet_Air); femm.mo_groupselectblock(Group_BlockLabel_Steel); double torque = femm.mo_blockintegral(FEMM.BlockIntegralType.Steady_state_weighted_stress_tensor_torque); if (!Motor.GeneralParams.FullBuildFEMModel) { torque *= 2 * p; } return(torque); }
public bool isFEMModelReady(String fn) { // check if FEMM and ANS file existed or not if (File.Exists(fn)) { // check if FEMM was built using which parameters (use md5 to check) String md5 = FEMM.mi_getFEMMComment(fn); if (md5 == GetMD5String()) { //log.Info("No Action needed. File existed and analyzed: " + Path_FEMMFile); return(true); } } return(false); }
/// <summary> /// Call this BEFORE rotating rotor /// </summary> public override void RemoveBoundary(FEMM femm = null) { if (femm == null) { femm = FEMM.DefaultFEMM; } if (Motor.GeneralParams.FullBuildFEMModel) { return; } femm.mi_clearselected(); femm.mi_selectgroup(Group_Lines_Airgap); femm.mi_deleteselectedsegments(); base.RemoveBoundary(femm); }
protected override void analyze() { DQCurrentMap map = Results as DQCurrentMap; generateListCurrents(map); int n = map.results.Count; int k = 0; foreach (var p in map.results) { k++; log.DebugFormat("Transient Analyzing {0}/{1}: id={2},iq={3}", k, n, p.idq.d, p.idq.q); analyzeOne(p); FEMM.CloseFemm(); } }
/// <summary> /// analyze will be sealed here, the child class can only do the measure action /// </summary> protected sealed override void analyze() { FEMM femm = null; if (FEMMToUse != null && FEMMToUse.Count > 0) { femm = FEMMToUse[0]; } else { femm = FEMM.DefaultFEMM; } // open original femm file femm.open(Path_OriginalFEMFile); // no modification (if other like transient will need to rotate rotor) // save as new file and analyze if (!DoAnalysisOnOriginalFEMFile) { femm.mi_saveas(WorkingFEMFile); } femm.mi_analyze(true); femm.mi_close(); if (!File.Exists(WorkingANSFile)) { log.Error(WorkingANSFile + " not exists, there may be something wrong with Femm file " + WorkingFEMFile); return; } femm.open(WorkingANSFile); try { measureInOpenedFem(femm); } catch (Exception ex) { log.Error(ex.Message); } femm.mo_close(); }
/// <summary> /// Actual run, all hard works here /// </summary> private void actualRunOptimization() { sw = new Stopwatch(); sw.Start(); individualCount = 0; // new FEMM windows if (lua["useFEM"] != null) { FEMMToUse = new List <FEMM>(); // 1 windows for now for (int i = 0; i < 1; i++) { FEMMToUse.Add(new FEMM()); } } try { ga.Go(); //results: Ga_AllFinish(ga); } catch (Exception ex) { MessageBox.Show("Genetic algorithm simulation failed: " + ex.Message); ga.Cancelled = true; } sw.Stop(); // close FEMM if (FEMMToUse != null) { FEMMToUse.Clear(); FEMMToUse = null; FEMM.CloseFemm(); } optimizationIsRunning = false; }
protected sealed override void analyze() { // for multi-thread config int threadCount = 4; ManualResetEvent[] MREs = new ManualResetEvent[threadCount]; Queue <int> steps = new Queue <int>(); for (int i = 0; i < StepCount + 1; i++) { steps.Enqueue(i); } // start all threads for (int i = 0; i < threadCount; i++) { MREs[i] = new ManualResetEvent(false); ManualResetEvent mre = MREs[i]; new Thread(delegate() { FEMM femm = new FEMM(); while (steps.Count > 0) { int step = steps.Dequeue(); AnalyzeOne(step, femm); } mre.Set(); }).Start(); } // wait for all thread to finish for (int i = 0; i < threadCount; i++) { MREs[i].WaitOne(); } // combine .bmp images to gif if (ExportGif) { combineBmpAsGif(); } }
/// <summary> /// Make a femm model using parameters /// This will check if file existed and use parameters the same to this one or not. /// If not, build new one /// </summary> /// <param name="outfile">Output femm model</param> /// <param name="original">The original femm model to insert into</param> /// <param name="forcebuild">True if build even file existed</param> /// <returns>0-OK,1-File existed, analyzed,-1-ERROR</returns> public virtual void BuildFEMModel(String outfile, FEMM femm = null) { // make sure coordinates were calculated if (!isPointsCoordCalculated) { throw new InvalidOperationException("Points must be calculated before make FEM model."); } if (femm == null) { femm = FEMM.DefaultFEMM; } femm.newdocument(FEMM.DocumentType.Magnetic); // setup problems params femm.mi_probdef(0, FEMM.UnitsType.millimeters, FEMM.ProblemType.planar, 1e-8, GeneralParams.MotorLength, 7, FEMM.ACSolverType.Succ_Approx); // build a rotor in femm Rotor.BuildInFEMM(femm); // build a stator in femm Stator.BuildInFEMM(femm); // build airgap (put label) Airgap.BuildInFEMM(femm); // clear selected, refresh, and go to natural zoom femm.mi_clearselected(); femm.mi_zoomnatural(); femm.mi_saveas(outfile); femm.mi_close(); // write md5 to it FEMM.mi_modifyFEMMComment(outfile, GetMD5String()); }
public override void BuildInFEMM(FEMM femm = null) { if (femm == null) { femm = FEMM.DefaultFEMM; } var Rotor = Motor.Rotor; var Stator = Motor.Stator; // create material femm.mi_addmaterialAir(AirMaterialName); femm.mi_addBlockLabelEx(Rotor.RGap + delta * 0.8, 0, AirMaterialName, Group_Fixed_BlockLabel_Airgap); if (!Motor.GeneralParams.FullBuildFEMModel) { //build boundary of motor: 2 lines, anti-periodic String boundaryName = "airgap-apb-0"; int Group_Lines = Group_Lines_Airgap; double x1 = Rotor.RGap * Math.Cos(Rotor.alpha); double y1 = Rotor.RGap * Math.Sin(Rotor.alpha); double x2 = Stator.RGap * Math.Cos(Rotor.alpha); double y2 = Stator.RGap * Math.Sin(Rotor.alpha); femm.mi_addSegmentEx(x1, y1, x2, y2, Group_Lines); femm.mi_addSegmentEx(x1, -y1, x2, -y2, Group_Lines); femm.mi_addboundprop_AntiPeriodic(boundaryName); femm.mi_clearselected(); femm.mi_selectgroup(Group_Lines); femm.mi_setsegmentprop(boundaryName, 0, true, false, Group_Lines); } base.BuildInFEMM(femm); }
void ta_OnFinishedAnalysis(object sender, AbstractResults e) { if (InvokeRequired) { BeginInvoke((Action) delegate() { ta_OnFinishedAnalysis(sender, e); }); } FEMM.CloseFemm(); var tr = e as Transient3PhaseMotorResults; GraphWindow gw = new GraphWindow(); IDictionary <string, object> dict = tr.BuildResultsForDisplay(); foreach (String name in dict.Keys) { var graphdata = dict[name] as ListPointD; if (graphdata != null) { gw.addData(name, graphdata.ToZedGraphPointPairList()); } } gw.Show(); }
private void measureData(FEMM femm) { Stator3Phase stator = Motor.Stator as Stator3Phase; PM_ACAnalysisResults Results = this.Results as PM_ACAnalysisResults; //select block double r = (stator.xD + stator.xE) / 2; foreach (Stator3Phase.Coil sci in stator.coils) { int i = stator.coils.IndexOf(sci); //angle go clockwise from 3 o'clock (=0 degree in decarter), shift +pi/Q (to match rotor) int nn = stator.Q / (2 * Motor.Rotor.p); double aa = -2 * Math.PI * i / stator.Q + (nn % 2 == 0 ? Math.PI / stator.Q : 0); double x = r * Math.Cos(aa); double y = r * Math.Sin(aa); if (aa > -Motor.Rotor.alpha || aa < -2 * Math.PI + Motor.Rotor.alpha) { femm.mo_selectblock(x, y); } } double r2 = (stator.xF2 + stator.RGap) / 2; femm.mo_selectblock(r2, 0); // measure data double lossMagnetic = femm.mo_blockintegral(FEMM.BlockIntegralType.Losses_Hysteresis); double lossResistive = femm.mo_blockintegral(FEMM.BlockIntegralType.Losses_Resistive); Results.coefficient_lossMagnetic = lossMagnetic / (Current * Current * Freq * Freq); Results.coefficient_lossResistive = lossResistive / (Current * Current);//=3/2*R Results.freq = Freq; Results.current = Current; }
/// <summary> /// Assuming a FEMM window is opened, build rotor into that /// </summary> /// <param name="MaterialParams"></param> public override void BuildInFEMM(FEMM femm = null) { if (femm == null) { femm = FEMM.DefaultFEMM; } bool fullbuild = Motor.GeneralParams.FullBuildFEMModel; // create material data femm.mi_addmaterialAir(AirMaterialName); femm.mi_addmaterialMagnet(MagnetMaterialName, mu_M, Hc, 0); 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()); // create boundary data femm.mi_addboundprop_Prescribed_A(BoundaryProperty, 0, 0, 0, 0); /////// Build 1 poles ////Half one // segments (magnet) femm.mi_addSegmentEx(xA, yA, xB, yB, Group_Lines_Rotor); //AB femm.mi_addSegmentEx(xB, yB, xE, yE, Group_Lines_Rotor); //BE femm.mi_addSegmentEx(xD, yD, xE, yE, Group_Lines_Rotor); //DE femm.mi_addSegmentEx(xE, yE, xF, yF, Group_Lines_Rotor); //EF femm.mi_addSegmentEx(xF, yF, xC, yC, Group_Lines_Rotor); //FC femm.mi_addSegmentEx(xD, yD, xG, yG, Group_Lines_Rotor); //DG femm.mi_addSegmentEx(xH, yH, xG, yG, Group_Lines_Rotor); //HG femm.mi_addSegmentEx(xH, yH, xI, yI, Group_Lines_Rotor); //HI femm.mi_addSegmentEx(xI, yI, xF, yF, Group_Lines_Rotor); //IF femm.mi_addSegmentEx(xH, yH, xJ, yJ, Group_Lines_Rotor); //HJ femm.mi_addSegmentEx(xI, yI, xK, yK, Group_Lines_Rotor); //IK if (Poletype == PoleType.MiddleAir) { femm.mi_addSegmentEx(xJ, yJ, xJ, 0, Group_Lines_Rotor);//JJ1 } else { femm.mi_addSegmentEx(xJ, yJ, xK, yK, Group_Lines_Rotor); //JK } // arcsegments AC double a = (Math.Atan(yA / xA) - Math.Atan(yC / xC)) * 180 / Math.PI; femm.mi_addArcEx(xC, yC, xA, yA, a, 1, Group_Lines_Rotor); // arcsegment RS femm.mi_addArcEx(xR, yR, xS, yS, alphaDegree, 1, Group_Lines_Rotor); // blocks // air block label double air1X = (xA + xB + xC) / 3; double air1Y = (yA + yB + yC) / 3; femm.mi_addBlockLabelEx(air1X, air1Y, AirMaterialName, Group_BlockLabel_Magnet_Air); //FEMM.mi_addBlockLabelEx(air1X, -air1Y, AirBlockName, Group_Label); if (Poletype != PoleType.MiddleAir) { double air2X = (xJ + xK + xI + xH) / 4; double air2Y = (yJ + yK + yI + yH) / 4; femm.mi_addBlockLabelEx(air2X, air2Y, AirMaterialName, Group_BlockLabel_Magnet_Air); // femm.mi_addBlockLabelEx(air2X, -air2Y, AirBlockName, Group_Label); } // magnet block label double magBlockLabelX = (xD + xI) / 2; double magBlockLabelY = (yD + yI) / 2; femm.mi_addBlockLabelEx(magBlockLabelX, magBlockLabelY, MagnetMaterialName, Group_BlockLabel_Magnet_Air, alphaM * 180 / Math.PI - 90 + 180);//+180 but set back later //femm.mi_addBlockLabelEx(magBlockLabelX, -magBlockLabelY, MagnetBlockName, Group_Label, 90 - alphaM * 180 / Math.PI + 180); ///// mirrored all femm.mi_clearselected(); femm.mi_selectgroup(Group_Lines_Rotor); femm.mi_selectgroup(Group_BlockLabel_Magnet_Air); femm.mi_mirror(0, 0, 1, 0, FEMM.EditMode.group); //// the remainings: not symmetrical if (Poletype == PoleType.MiddleAir) { femm.mi_addBlockLabelEx((xJ + xK0) / 2, 0, AirMaterialName, Group_BlockLabel_Magnet_Air); } ////////// Build 2 poles // copy pole if full build if (fullbuild) { femm.mi_clearselected(); femm.mi_selectgroup(Group_Lines_Rotor); femm.mi_selectgroup(Group_BlockLabel_Magnet_Air); femm.mi_copyrotate(0, 0, 360 / (2 * p), 1, FEMM.EditMode.group); } // rotate the magnet direction (of the first pole) femm.mi_clearselected(); femm.mi_selectlabel(magBlockLabelX, magBlockLabelY); femm.mi_setblockprop(MagnetMaterialName, true, 0, "", alphaM * 180 / Math.PI - 90, Group_BlockLabel_Magnet_Air, 0); femm.mi_clearselected(); femm.mi_selectlabel(magBlockLabelX, -magBlockLabelY); femm.mi_setblockprop(MagnetMaterialName, true, 0, "", 90 - alphaM * 180 / Math.PI, Group_BlockLabel_Magnet_Air, 0); if (fullbuild) { //////// Build p-1 pair of poles remaining femm.mi_clearselected(); femm.mi_selectgroup(Group_Lines_Rotor); femm.mi_selectgroup(Group_BlockLabel_Magnet_Air); femm.mi_copyrotate(0, 0, 360 / p, p - 1, FEMM.EditMode.group); } /////// The remaining: not symmetrical: add label for rotor steel femm.mi_addBlockLabelEx((DiaYoke / 2 + O2 / 2), 0, SteelMaterialName, Group_BlockLabel_Steel); if (fullbuild) { // pre-rotate rotor (only in fullbuild) femm.mi_clearselected(); femm.mi_selectgroup(Group_Lines_Rotor); femm.mi_selectgroup(Group_BlockLabel_Magnet_Air); femm.mi_selectgroup(Group_BlockLabel_Steel); femm.mi_moverotate(0, 0, PreviewRotateAngle, FEMM.EditMode.group); } if (!fullbuild) { //build boundary of motor: 2 lines, anti-periodic String boundaryName = "rotor-apb-1"; femm.mi_addSegmentEx(0, 0, xS, yS, Group_Lines_Rotor); femm.mi_addSegmentEx(0, 0, xS, -yS, Group_Lines_Rotor); femm.mi_addboundprop_AntiPeriodic(boundaryName); femm.mi_clearselected(); femm.mi_selectsegment(xS, yS); femm.mi_selectsegment(xS, -yS); femm.mi_setsegmentprop(boundaryName, 0, true, false, Group_Lines_Rotor); } }
protected override void measureInOpenedFem(FEMM femm) { // Begin to measure FEMM.LineIntegralResult lir = new FEMM.LineIntegralResult(); VPMMotor Motor = this.Motor as VPMMotor; VPMRotor Rotor = Motor.Rotor; Stator3Phase Stator = Motor.Stator; GeneralParameters GeneralParams = Motor.GeneralParams; AirgapNormal Airgap = Motor.Airgap; PMStaticResults Results = this.Results as PMStaticResults; double xS = Rotor.Rrotor * Math.Cos(Rotor.alpha * 0.9999); double yS = Rotor.Rrotor * Math.Sin(Rotor.alpha * 0.9999); // get phiD femm.mo_addcontour(xS, yS); //femm.mo_selectpoint(Rotor.xR, Rotor.yR); femm.mo_addcontour(xS, -yS); femm.mo_bendcontour(-360 / (2 * Rotor.p), 1); lir = femm.mo_lineintegral_full(); Results.phiD = Math.Abs(lir.totalBn); // get phiM femm.mo_clearcontour(); femm.mo_selectpoint(Rotor.xD, Rotor.yD); femm.mo_selectpoint(Rotor.xG, Rotor.yG); FEMM.LineIntegralResult rr = femm.mo_lineintegral(FEMM.LineIntegralType.Bn); Results.phiM = Math.Abs(rr.totalBn * 2); // get phib femm.mo_clearcontour(); femm.mo_selectpoint(Rotor.xH, Rotor.yH); femm.mo_selectpoint(Rotor.xH, -Rotor.yH); rr = femm.mo_lineintegral(FEMM.LineIntegralType.Bn); Results.phib = Math.Abs(rr.totalBn); femm.mo_clearcontour(); femm.mo_selectpoint(Rotor.xE, Rotor.yE); femm.mo_selectpoint(Rotor.xA, Rotor.yA); rr = femm.mo_lineintegral(FEMM.LineIntegralType.Bn); Results.phib += Math.Abs(rr.totalBn * 2); // get phisigmaFe femm.mo_clearcontour(); femm.mo_addcontour(Rotor.xA, Rotor.yA); femm.mo_addcontour(xS, yS); rr = femm.mo_lineintegral(FEMM.LineIntegralType.Bn); Results.phiFe = Math.Abs(rr.totalBn * 2); // get phisigmaS double xZ = (Stator.Rinstator + 5) * Math.Cos(2 * Math.PI / (4 * Rotor.p) - 2 * Math.PI / 180); double yZ = (Stator.Rinstator + 5) * Math.Sin(2 * Math.PI / (4 * Rotor.p) - 2 * Math.PI / 180); femm.mo_clearcontour(); femm.mo_selectpoint(Rotor.xS, Rotor.yS); femm.mo_selectpoint(xZ, yZ); rr = femm.mo_lineintegral(FEMM.LineIntegralType.Bn); Results.phisigmaS = Math.Abs(rr.totalBn * 2); // get FM femm.mo_clearcontour(); femm.mo_addcontour((Rotor.xI + Rotor.xF) / 2, (Rotor.yI + Rotor.yF) / 2); femm.mo_addcontour((Rotor.xD + Rotor.xG) / 2, (Rotor.yD + Rotor.yG) / 2); rr = femm.mo_lineintegral(FEMM.LineIntegralType.Ht); Results.FM = Math.Abs(rr.totalHt); // get B_airgap int n = 128; Results.Bairgap = new PointD[n * 2]; double RR = (Rotor.Rrotor + Stator.Rinstator) / 2; for (int i = 0; i < n; i++) { double a = -(i - n / 2.0) / n * 2 * Rotor.alpha; double px = RR * Math.Cos(a); double py = RR * Math.Sin(a); FEMM.PointValues pv = femm.mo_getpointvalues(px, py); Results.Bairgap[i].X = 2 * Rotor.alpha * RR * i / n; Results.Bairgap[i].Y = pv.B1 * Math.Cos(a) + pv.B2 * Math.Sin(a); if (double.IsNaN(Results.Bairgap[i].Y)) { Results.Bairgap[i].Y = 0; } if (Results.Bdelta_max < Math.Abs(Results.Bairgap[i].Y)) { Results.Bdelta_max = Math.Abs(Results.Bairgap[i].Y); } } // make a mirror (odd function) double dd = 2 * Rotor.alpha * RR; for (int i = 0; i < n; i++) { Results.Bairgap[i + n].X = Results.Bairgap[i].X + dd; Results.Bairgap[i + n].Y = -Results.Bairgap[i].Y; } double wd = Rotor.gammaMedeg / 180 * (Rotor.Rrotor + Airgap.delta / 2) * 2 * Math.PI / (2 * Rotor.p); Results.Bdelta = Results.phiD / (GeneralParams.MotorLength * wd * 1e-6); // psiM Dictionary <String, FEMM.CircuitProperties> cps = Stator.getCircuitsPropertiesInAns(femm); if (cps.ContainsKey("A") && cps.ContainsKey("B") && cps.ContainsKey("C")) { Fdq fdq = ParkTransform.abc_dq(cps["A"].fluxlinkage, cps["B"].fluxlinkage, cps["C"].fluxlinkage, 0); Results.psiM = fdq.Magnitude; } else { Results.psiM = double.NaN; } femm.mo_close(); }
protected override void DoMeasureData(TransientStepArgs args, FEMM femm) { // measure base data base.DoMeasureData(args, femm); // measure only one, not all those for skew angle if (args.skewAngleAdded != 0) { return; } // measure loss // other processes need to wait for the first to finish this block of code lock (lock_first) { if (allElements == null) { Stator3Phase stator = Motor.Stator as Stator3Phase; int rotor_steel_group = -1; int rotor_magnet_group = -1; double rotor_Keddy = 0; double rotor_Kh = 0; double rotor_ro = 0; if (Motor.Rotor is SPMRotor) { var rotor = Motor.Rotor as SPMRotor; rotor_steel_group = rotor.Group_BlockLabel_Steel; rotor_magnet_group = rotor.Group_BlockLabel_Magnet_Air; rotor_Keddy = rotor.P_eddy_10_50; rotor_Kh = rotor.P_hysteresis_10_50; rotor_ro = rotor.Steel_ro; } else if (Motor.Rotor is VPMRotor) { var rotor = Motor.Rotor as VPMRotor; rotor_steel_group = rotor.Group_BlockLabel_Steel; rotor_magnet_group = rotor.Group_BlockLabel_Magnet_Air; rotor_Keddy = rotor.P_eddy_10_50; rotor_Kh = rotor.P_hysteresis_10_50; rotor_ro = rotor.Steel_ro; } List <PointD> nodes = new List <PointD>(); int n = femm.mo_numnodes(); for (int i = 1; i <= n; i++) { var p = femm.mo_getnode(i); nodes.Add(p); } allElements = new List <FEMM.Element>(); n = femm.mo_numelements(); for (int i = 1; i <= n; i++) // start from 1 { var e = femm.mo_getelement(i); for (int j = 0; j < e.nodes.Length; j++) { e.nodes[j]--;//convert from 1-base index to 0-base index } allElements.Add(e); } var statorElements = allElements.Where(e => e.group == stator.Group_BlockLabel_Steel).ToList(); statorLoss = new CoreLoss(this, nodes, statorElements); statorLoss.name = "Stator_"; statorLoss.ro = stator.Steel_ro; statorLoss.Keddy = stator.P_eddy_10_50; statorLoss.Kh = stator.P_hysteresis_10_50; var rotorElements = allElements.Where(e => e.group == rotor_steel_group || e.group == rotor_magnet_group).ToList(); // convert coordinates of elements back to 0 degree rotor angle // hashset of node to mark rotated node HashSet <int> rotatedNodes = new HashSet <int>(); // angle to rotate back double a = Motor.GetNormalizedRotorAngle(args.RotorAngle) * Math.PI / 180; // for each element foreach (var e in rotorElements) { double xx = e.center.X; double yy = e.center.Y; e.center.X = xx * Math.Cos(-a) - yy * Math.Sin(-a); e.center.Y = xx * Math.Sin(-a) + yy * Math.Cos(-a); // rotate nodes of this element also for (int i = 0; i < e.nodes.Length; i++) { int node_index = e.nodes[i]; // if already rotated if (rotatedNodes.Contains(node_index)) { continue; } xx = nodes[node_index].X; yy = nodes[node_index].Y; nodes[node_index] = new PointD() { X = xx * Math.Cos(-a) - yy * Math.Sin(-a), Y = xx * Math.Sin(-a) + yy * Math.Cos(-a), }; // mark as rotated rotatedNodes.Add(node_index); } } rotorLoss = new CoreLoss(this, nodes, rotorElements); rotorLoss.name = "Rotor_"; rotorLoss.isRotor = true; rotorLoss.Keddy = rotor_Keddy; rotorLoss.Kh = rotor_Kh; rotorLoss.ro = rotor_ro; } }// lock(..) statorLoss.GatherData(args, femm); rotorLoss.GatherData(args, femm); }
protected virtual void measureInOpenedFem(FEMM femm) { }
public void RunAnalysis() { if (Motor == null) { throw new InvalidOperationException("Motor hasn't been assigned"); } if (!File.Exists(Motor.Path_FEMMFile)) { log.Error("File doesn't exist: " + Motor.Path_FEMMFile); return; } // gen output path generateOutputPath(); // create directory Directory.CreateDirectory(OutDir); // load results from disk MMAnalysisResults existedResults = MMAnalysisResults.loadResultsFromFile(Path_resultsFile); log.Info("Output results file:" + Path_resultsFile); // if has if (existedResults != null) { if (GetMD5String() == existedResults.MD5String) { log.Info("M analysis already been done."); Results = existedResults; //OnFinishedAnalysis(this, Results); return; } log.Info("M analysis exists but different. New analysis will be done."); } // create new Results = new MMAnalysisResults(2 * StepCount + 1); Results.MD5String = GetMD5String();//assign md5 (signature of this) // steps numbering are put in queue for multi-thread Queue <int> steps = new Queue <int>(); Queue <double> currents = new Queue <double>(); for (int i = 0; i <= 2 * StepCount; i++) { if (i != StepCount)// meaning I=0 { steps.Enqueue(i); } } // for multi-thread config int threadCount = 4; ManualResetEvent[] MREs = new ManualResetEvent[threadCount]; FEMM[] femms = new FEMM[threadCount]; for (int i = 0; i < threadCount; i++) { MREs[i] = new ManualResetEvent(false); femms[i] = new FEMM(); } // calculate the first (I=0), to get FluxLinkageM AnalyzeOne(StepCount, femms[0]); // start all threads for (int i = 0; i < threadCount; i++) { ManualResetEvent mre = MREs[i]; FEMM femm = femms[i]; new Thread(delegate() { while (steps.Count > 0) { AnalyzeOne(steps.Dequeue(), femm); } mre.Set(); }).Start(); } // wait for all thread to finish for (int i = 0; i < threadCount; i++) { MREs[i].WaitOne(); } //create folder if needed Directory.CreateDirectory(OutDir); // save results data to disk Results.saveResultsToFile(Path_resultsFile); // finished event OnFinishedAnalysis(this, Results); }
private void AnalyzeOne(int step, FEMM femm = null) { if (femm == null) { femm = FEMM.DefaultFEMM; } // open femm file femm.open(Motor.Path_FEMMFile); ///// Rotate rotor to an angle // clear the way (line-boundary conditional in airgap) Motor.Airgap.MakeWayInAirgapBeforeRotationInFEMM(femm); // normalize, make rotorAngle inside (-2alpha,2alpha) double xRotorAngle = RotorAngle; if (!Motor.GeneralParams.FullBuildFEMModel) { double alphax2 = 2 * Motor.Rotor.alphaDegree; if (xRotorAngle > alphax2 || xRotorAngle < -alphax2) { xRotorAngle = xRotorAngle - Math.Round(xRotorAngle / (2 * alphax2)) * 2 * alphax2; } } // rotate rotor Motor.Rotor.RotateRotorInFEMM(xRotorAngle, femm); // modify airgap (in case partial build) Motor.Airgap.ModifyAirgapAfterRotationInFEMM(xRotorAngle, femm); // modify stator currents double current = MaxCurrent / StepCount * (step - StepCount);//step can be -StepCount to +StepCount (total 2*StepCount+1), current=-Max->+Max double IA = current * Math.Cos(Beta * Math.PI / 180); double IB = current * Math.Cos(Beta * Math.PI / 180 - 2 * Math.PI / 3); double IC = current * Math.Cos(Beta * Math.PI / 180 + 2 * Math.PI / 3); Dictionary <String, double> currents = new Dictionary <string, double>() { { "A", IA }, { "B", IB }, { "C", IC } }; Motor.Stator.SetStatorCurrentsInFEMM(currents, femm); // save as new file fem (temp only) String stepfileFEM = OutDir + "\\" + String.Format("{0:D4}.FEM", step); femm.mi_saveas(stepfileFEM); // analyze femm.mi_analyze(true); // close femm.mi_close(); // delete temp file //File.Delete(stepfileFEM); // open ans file to measure ? String stepfileANS = Path.GetDirectoryName(stepfileFEM) + "\\" + Path.GetFileNameWithoutExtension(stepfileFEM) + ".ans"; femm.open(stepfileANS); Dictionary <String, FEMM.CircuitProperties> cps = Motor.Stator.getCircuitsPropertiesInAns(femm); MMAnalysisOneStepResult result = new MMAnalysisOneStepResult(); result.Iabc = new Fabc { a = cps["A"].current, b = cps["B"].current, c = cps["C"].current }; result.FluxLinkage_abc = new Fabc { a = cps["A"].fluxlinkage, b = cps["B"].fluxlinkage, c = cps["C"].fluxlinkage }; result.Vabc = new Fabc { a = cps["A"].volts, b = cps["B"].volts, c = cps["C"].volts }; // no currents, then save the fluxlinkageM, which is importance to calculate Ld if (current == 0) { Results.FluxLinkageM = result.FluxLinkage_dq.d; } result.FluxLinkage_M = Results.FluxLinkageM; Results[step] = result; femm.mo_close(); log.Info("Step " + step + " done."); }