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();
        }
Exemple #2
0
        /// <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>
        /// 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());
        }
Exemple #4
0
        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.");
        }
        /// <summary>
        /// Analyze 1 step, using femm window
        /// </summary>
        /// <param name="data"></param>
        /// <param name="step"></param>
        /// <param name="femm"></param>
        private void AnalyzeOne(int step, FEMM femm = null)
        {
            if (femm == null)
            {
                femm = FEMM.DefaultFEMM;
            }

            double t          = Results.Times[step];
            double rotorAngle = RotorSpeedDegreeSecond * t + StartAngle;

            // run script to update IA,IB,IC
            NLua.Lua lua_state                   = LuaHelper.GetLuaState();
            String[] currentFormulas             = { IA, IB, IC };
            String[] circuitNames                = { "A", "B", "C" };
            Dictionary <String, double> currents = new Dictionary <string, double>();

            try
            {
                lua_state["step"]  = step;
                lua_state["time"]  = t;
                lua_state["omega"] = RotorSpeedRadSecond;

                for (int i = 0; i < currentFormulas.Length; i++)
                {
                    double Ix = (double)lua_state.DoString("return " + currentFormulas[i])[0];
                    currents[circuitNames[i]] = Ix;
                }
            }
            catch (Exception ex)
            {
                log.Error("Lua error :" + ex.Message);
                //TODO: maybe halt analysis since there maybe big problem
            }

            // open femm file
            femm.open(Motor.Path_FEMMFile);

            // 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 using args passed from OnBeginAnalyzeOne
            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);

            //String bmpFile = config.OutDir + "\\bmp\\" + Path.GetFileNameWithoutExtension(stepfileFEM) + ".bmp";
            //femm.mo_savebitmap(bmpFile);

            // get circuits properties from stator
            TransientStepResult result = new TransientStepResult();

            Dictionary <String, FEMM.CircuitProperties> cps = Motor.Stator.getCircuitsPropertiesInAns(femm);
            double torque = Motor.Rotor.getTorqueInAns(femm);

            result.Torque            = torque;
            result.RotorAngle        = rotorAngle;
            result.CircuitProperties = cps;

            Results[step] = result;

            OnFinishAnalyzeOneStep(this, result);

            log.Info(String.Format("Time {0:F5}: {1}", t, torque));

            femm.mo_close();
        }
        private void AnalyzeOne(int step, FEMM femm = null)
        {
            if (femm == null)
            {
                femm = FEMM.DefaultFEMM;
            }

            // open femm file
            femm.open(Path_OriginalFEMFile);

            ///// Rotate rotor to an angle
            // clear the way (line-boundary conditional in airgap)
            Motor.Airgap.RemoveBoundary(femm);

            // normalize, make rotorAngle inside (-2alpha,2alpha) to build FEMM model
            double femmRotorAngle = Motor.GetNormalizedRotorAngle(RotorAngle);

            // rotate rotor
            Motor.Rotor.RotateRotorInFEMM(femmRotorAngle, femm);

            // modify airgap (in case partial build)
            Motor.Airgap.AddBoundaryAtAngle(femmRotorAngle, femm);

            // modify stator currents
            // testing iq=const, id change to see how inductance d,q change
            //double id = 80.0 / StepCount * (step - StepCount);
            //double iq = 40.0;
            //double current = Math.Sqrt(id * id + iq * iq);
            //double Beta = Math.Abs(id) > 1e-8 ? Math.Atan(iq / id) * 180 / Math.PI : 90.0;
            //if (Beta < 0)
            //    Beta += 180;

            // Test change beta, not current
            //double beta = (this.Beta - 100) / StepCount * step + 100;
            //double current = MaxCurrent;

            var stator = Motor.Stator as Stator3Phase;

            // Change current
            double current;

            if (Only2ndQuarter)
            {
                int c = NotIncludeCurrentZero ? 1 : 0;
                current = MaxCurrent * (step + c) / StepCount;
            }
            else
            {
                int c = NotIncludeCurrentZero ? (step < StepCount ? 0 : 1) : 0;
                current = MaxCurrent / StepCount * ((step + c) - StepCount);
            }

            // correction beta with current rotor angle and original angle (0)
            double beta = this.Beta + (RotorAngle - stator.VectorMMFAngle) * Motor.Rotor.p;//in degree

            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 = Path_ToAnalysisVariant + "\\" + 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);
            double t = Motor.Rotor.getTorqueInAns(femm);

            PMMMAnalysisOneStepResult result = new PMMMAnalysisOneStepResult();

            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
            var Results = this.Results as PM_MMAnalysisResults;

            result.torque        = t;
            result.FluxLinkage_M = Results.FluxLinkageM;
            result.theta_e       = (RotorAngle - stator.VectorMMFAngle) * Motor.Rotor.p * Math.PI / 180;//in radian

            Results[step] = result;

            femm.mo_close();
        }
Exemple #7
0
        /// <summary>
        /// Make a femm model using parameters from rotor creation process
        /// </summary>
        /// <param name="outfile">Output femm model</param>
        /// <param name="original">The original femm model to insert into</param>
        public void MakeAFEMMModelFile(String outfile, String original = "")
        {
            if (!isPointsCoordCalculated)
            {
                CalcPointsCoordinates();
            }

            // create new or open an exist
            if (original == "")
            {
                FEMM.newdocument(FEMM.DocumentType.Magnetic);
            }
            else
            {
                FEMM.open(original);
            }

            //
            double Rrotor = RotorParams.Rrotor;
            double alpha  = 2 * Math.PI / (4 * RotorParams.p);
            double alphaM = RotorParams.alphaM;
            int    p      = RotorParams.p;

            ///// Build 1 poles
            // point far right of rotors
            double xI = Rrotor;
            double yI = 0;

            // segments (magnet)
            FEMM.mi_addSegmentEx(xA, yA, xB, yB, Group_Lines); //AB
            FEMM.mi_addSegmentEx(xA, yA, xF, yF, Group_Lines); //AF
            FEMM.mi_addSegmentEx(xA, yA, xD, yD, Group_Lines); //AD
            FEMM.mi_addSegmentEx(xB, yB, xC, yC, Group_Lines); //BC
            FEMM.mi_addSegmentEx(xC, yC, xD, yD, Group_Lines); //CD

            // mirrored segments (magnet)
            FEMM.mi_addSegmentEx(xA, -yA, xB, -yB, Group_Lines); //AB
            FEMM.mi_addSegmentEx(xA, -yA, xF, -yF, Group_Lines); //AF
            FEMM.mi_addSegmentEx(xA, -yA, xD, -yD, Group_Lines); //AD
            FEMM.mi_addSegmentEx(xB, -yB, xC, -yC, Group_Lines); //BC
            FEMM.mi_addSegmentEx(xC, -yC, xD, -yD, Group_Lines); //CD

            // barrier segments
            FEMM.mi_addSegmentEx(xC, yC, xC, -yC, Group_Lines); //AB
            FEMM.mi_addSegmentEx(xD, yD, xD, -yD, Group_Lines); //AF

            // arcsegments
            double a = (Math.Atan(yF / xF) - Math.Atan(yB / xB)) * 180 / Math.PI;

            FEMM.mi_addArcEx(xB, yB, xF, yF, a, 1, Group_Lines);
            FEMM.mi_addArcEx(xF, -yF, xB, -yB, a, 1, Group_Lines);

            // arcsegments rotor
            FEMM.mi_addArcEx(xI, yI, xG, yG, alpha * 180 / Math.PI, 1, Group_Lines);
            FEMM.mi_addArcEx(xG, -yG, xI, yI, alpha * 180 / Math.PI, 1, Group_Lines);

            // blocks
            // air block label
            double air1X = (xA + xB + xF) / 3;
            double air1Y = (yA + yB + yF) / 3;

            FEMM.mi_addBlockLabelEx(air1X, air1Y, AirBlockName, Group_Label);
            FEMM.mi_addBlockLabelEx(air1X, -air1Y, AirBlockName, Group_Label);
            FEMM.mi_addBlockLabelEx((xC + xD) / 2, 0, AirBlockName, Group_Label);

            // magnet block label
            double magBlockLabelX = (xA + xC) / 2;
            double magBlockLabelY = (yA + yC) / 2;

            FEMM.mi_addBlockLabelEx(magBlockLabelX, magBlockLabelY, MagnetBlockName, Group_Label, 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);

            ///// Build 2 poles
            FEMM.mi_clearselected();
            FEMM.mi_selectgroup(Group_Lines);
            FEMM.mi_selectgroup(Group_Label);
            FEMM.mi_copyrotate(0, 0, 360 / (2 * p), 1, FEMM.EditMode.group);
            // rotate the magnet direction
            FEMM.mi_clearselected();
            FEMM.mi_selectlabel(magBlockLabelX, magBlockLabelY);
            FEMM.mi_setblockprop(MagnetBlockName, true, 0, "", alphaM * 180 / Math.PI - 90, Group_Label, 0);
            FEMM.mi_clearselected();
            FEMM.mi_selectlabel(magBlockLabelX, -magBlockLabelY);
            FEMM.mi_setblockprop(MagnetBlockName, true, 0, "", 90 - alphaM * 180 / Math.PI, Group_Label, 0);

            ///// Build p-1 pair of poles remaining
            FEMM.mi_clearselected();
            FEMM.mi_selectgroup(Group_Lines);
            FEMM.mi_selectgroup(Group_Label);
            FEMM.mi_copyrotate(0, 0, 360 / p, p - 1, FEMM.EditMode.group);

            FEMM.mi_addBlockLabelEx(0, 0, SteelBlockName, Group_Rotor_Steel);

            // clear selected, refresh, and go to natural zoom
            FEMM.mi_clearselected();
            FEMM.mi_zoomnatural();

            // save as
            if (Path.GetDirectoryName(outfile) == "")
            {
                outfile = Path.GetDirectoryName(original) + "\\" + outfile;
            }
            FEMM.mi_saveas(outfile);

            FEMM.mi_close();
        }
Exemple #8
0
        /// <summary>
        /// Analyze 1 step, using femm window
        /// </summary>
        /// <param name="data"></param>
        /// <param name="step"></param>
        /// <param name="femm"></param>
        private void AnalyzeOne(int step, FEMM femm = null)
        {
            if (femm == null)
            {
                femm = FEMM.DefaultFEMM;
            }

            if (SkewAngle <= 0 || NSkewSegment <= 0)
            {
                // prepare arguments for this step
                TransientStepArgs args = PrepareStepArgs(step);

                // before analyzing
                OnStartAnalyzeOneStep(this, args);

                // open femm file
                femm.open(Path_OriginalFEMFile);

                // modify rotor: rotate, or other things that we can think of
                DoModifyRotor(args, femm);

                // modify stator: change current, or something else?
                DoModifyStator(args, femm);

                // save as new file fem (temp only)
                String stepfileFEM = Path_ToAnalysisVariant + "\\" + String.Format("{0:D4}.FEM", step);
                femm.mi_saveas(stepfileFEM);

                // analyze
                femm.mi_analyze(true);

                // close
                femm.mi_close();

                // open ans file to measure ?
                String stepfileANS = Path.GetDirectoryName(stepfileFEM) + "\\" + Path.GetFileNameWithoutExtension(stepfileFEM) + ".ans";
                femm.open(stepfileANS);

                // do measure torque or anything else
                DoMeasureData(args, femm);

                // put in the list
                var Results = this.Results as Transient3PhaseMotorResults;
                Results[step] = args;

                //log.Info(String.Format("Time {0:F5}: {1}", t, torque));

                // save as bitmap
                if (ExportGif)
                {
                    femm.mo_clearblock();
                    femm.mo_zoom(0, -Motor.Stator.RYoke, Motor.Stator.RYoke, Motor.Stator.RYoke);
                    femm.mo_showdensityplot(true, false, 0, 2.1, FEMM.DensityPlotType.bmag);
                    femm.mo_savebitmap(Path.GetDirectoryName(stepfileFEM) + "\\" + Path.GetFileNameWithoutExtension(stepfileFEM) + ".bmp");
                }

                // close
                femm.mo_close();

                // after analyzing
                OnFinishAnalyzeOneStep(this, args);
            }
            else // has skewangle
            {
                // prepare arguments for this step
                TransientStepArgs total_args = PrepareStepArgs(step);

                // before analyzing
                OnStartAnalyzeOneStep(this, total_args);

                for (int k = 0; k < 2 * NSkewSegment + 1; k++)
                {
                    TransientStepArgs args = PrepareStepArgs(step);
                    double            sk   = (k - NSkewSegment) * SkewAngle / (2 * NSkewSegment);
                    args.skewAngleAdded = sk;
                    args.RotorAngle    += sk;

                    // open femm file
                    femm.open(Path_OriginalFEMFile);

                    // modify rotor: rotate, or other things that we can think of
                    DoModifyRotor(args, femm);

                    // modify stator: change current, or something else?
                    DoModifyStator(args, femm);

                    // save as new file fem (temp only)
                    String stepfileFEM = Path_ToAnalysisVariant + "\\" + String.Format("{0:D4}_{1}.FEM", step, k);
                    femm.mi_saveas(stepfileFEM);

                    // analyze
                    femm.mi_analyze(true);

                    // close
                    femm.mi_close();

                    // open ans file to measure ?
                    String stepfileANS = Path.GetDirectoryName(stepfileFEM) + "\\" + Path.GetFileNameWithoutExtension(stepfileFEM) + ".ans";
                    femm.open(stepfileANS);

                    // do measure torque or anything else
                    DoMeasureData(args, femm);

                    // initialize data for total
                    if (k == 0)
                    {
                        total_args        = JSON.DeepCopy(args);
                        total_args.Torque = 0;
                        foreach (string key in total_args.CircuitProperties.Keys)
                        {
                            total_args.CircuitProperties[key].fluxlinkage = 0;
                        }
                    }

                    femm.mo_close();

                    total_args.Torque += args.Torque / (2 * NSkewSegment + 1);
                    foreach (string key in total_args.CircuitProperties.Keys)
                    {
                        total_args.CircuitProperties[key].fluxlinkage += args.CircuitProperties[key].fluxlinkage / (2 * NSkewSegment + 1);
                    }
                }

                // put in the list
                var Results = this.Results as Transient3PhaseMotorResults;
                Results[step] = total_args;

                //log.Info(String.Format("Time {0:F5}: {1}", t, torque));

                // after analyzing
                OnFinishAnalyzeOneStep(this, total_args);
            }
        }