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();
        }
Beispiel #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();
        }
Beispiel #3
0
        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();
        }
Beispiel #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();
        }
Beispiel #7
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);
            }
        }