Beispiel #1
0
 public static bool insertMDeviation2DS(MDeviationSOutClass newClass, string type, string year, string month, string day, string hour, int invalidflag)
 {
     try
     {
         bool      isok = false;
         DataTable dt   = isHaveData(year, month, day, hour, type, "psl_mdeviation2ds");
         if (dt != null && dt.Rows.Count > 0)
         {
             isok = DAL.AlgorithmDAL.updateMDeviation2DS(Convert.ToInt32(dt.Rows[0]["id"].ToString()), newClass, type, year, month, day, hour, invalidflag);
         }
         else
         {
             isok = DAL.AlgorithmDAL.insertMDeviation2DS(newClass, type, year, month, day, hour, invalidflag);
         }
         return(isok);
     }
     catch (Exception)
     {
         throw;
     }
 }
Beispiel #2
0
        public static Results Calcu(List <PValue>[] inputs, CalcuInfo calcuinfo)
        {
            //公用变量
            bool   _errorFlag   = false;
            string _errorInfo   = "";
            bool   _warningFlag = false;
            string _warningInfo = "";
            bool   _fatalFlag   = false;
            string _fatalInfo   = "";

            int i;

            //0输出初始化:该算法如果没有有效输入值(inputs为null)或者输入值得有效值为null,给出的计算结果。值为0,计算标志位为StatusConst.InputIsNull
            List <PValue>[] results = new List <PValue> [5];
            for (i = 0; i < results.Length; i++)
            {
                results[i] = new List <PValue>();
                results[i].Add(new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, (long)StatusConst.InputIsNull));
            }

            try
            {
                //0、输入

                //0.1、输入处理:输入长度。当输入为空时,给出标志位为StatusConst.InputIsNull的计算结果.
                if (inputs == null || inputs.Length < 2 || inputs[0] == null || inputs[1] == null)          //一些情况下,进来就有null,这样下面的的取出状态为会出错
                {
                    _errorFlag = true;
                    _errorInfo = "输入有效数据数量不足。一维偏差及得分计算要求必须有且仅有两个有效输入。";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //0.2、输入处理:截止时刻值。该算法,截止时刻点不需要参与计算,要删除。
                //本算法做特别处理
                //if (input.Count > 1) input.RemoveAt(input.Count - 1);

                //0.3、输入处理:标志位。该算法考虑标志位不为0的情况,先过滤这些点。
                //********如果计算偏差前,参考量和被考核量,在计算的分钟周期内,分钟值为状态位无效的值。
                //********这里会读入这个值,并在下面过滤。如果被过滤,则下面的参考量和被考核量长度判断会报错。并返回不正常状态的计算结果。
                for (i = 0; i < inputs.Length; i++)
                {
                    for (int j = inputs[i].Count - 1; j >= 0; j--)
                    {
                        if (inputs[i][j].Status != 0)
                        {
                            inputs[i].RemoveAt(j);
                        }
                    }
                }

                //0.4、输入处理:过滤后结果。
                //本算法做特别处理
                //——如果去除了截止时刻点,过滤后长度小于1(计算要求至少有一个有效数据),则直接返回全0
                //——如果没取除截止时刻点,过滤后长度小于2(计算要求至少有一个有效数据和一个截止时刻值)
                //if (input.Count < 1) return results;


                //1、检查并整理数据
                //——这里是计算每分钟的偏差。
                //——输入量是被评变量每分钟滤波值、参考变量每分钟滤波值
                if (inputs[0] == null || inputs[0].Count < 2)
                {
                    _warningFlag = true;
                    _warningInfo = "一维偏差及得分计算,被测评量经状态位过滤后数据为空!";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                if (inputs[1] == null || inputs[1].Count < 2)
                {
                    _warningFlag = true;
                    _warningInfo = "一维偏差及得分计算,参考量经状态位过滤后数据为空!";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //1.2 直接取各变量第一个数值计算,不需要处理截止时刻值
                PValue pvdata;
                PValue refdata;

                pvdata  = inputs[0][0];                       //不使用截止值
                refdata = inputs[1][0];                       //不使用截止值

                StatusConst invalidflag = StatusConst.Normal; //参考指标值是否超越偏差曲线x范围,当次指标考核计算是否有效

                //2、根据参数获取期望曲线、记分曲线
                string   calcuMode;                       //计算方式选择
                string[] para       = calcuinfo.fparas.Split(new char[] { ';' });
                string   readMethod = para[0];            //第一个参数是获取曲线的方式,D为动态,S为静态。动态方式,每次计算均读取CSV。静态方式,只读取一次CSV。
                int      opxid      = int.Parse(para[1]); //第二个参数是期望曲线序号
                int      scoreid    = int.Parse(para[2]); //第三个参数是得分曲线序号
                double   k          = double.Parse(para[3]);
                double   b          = double.Parse(para[4]);
                if (para.Length == 6)
                {
                    calcuMode = para[5];            //如果设定了第5个参数,计算模式用二维计分。D表示二维计分,s表示一维计分
                }
                else
                {
                    calcuMode = "S"; //如果没设定第5个参数,计算模式为一维计分
                }
                Curve1D opxCurve;    //期望值
                Curve1D scoreCurve;  //计分值
                Curve2D scoreCurve2D;

                string strTemp   = CurveConfig.Instance.OPXCurvesReadStatus; //这行这条语句是为了下面在使用CurveConfig.GetXXXCurve时保证Instance已被初始化。20181109调试发现该问题。
                string strTemp2D = CurveConfig.Instance.ScoreCurves2DReadStatus;

                try
                {
                    if (readMethod.ToUpper() == "S")
                    {
                        //第一个参数为S时,静态读取期望曲线和积分曲线表
                        opxCurve = CurveConfig.GetOPXCurve(opxid, calcuinfo.fstarttime);

                        scoreCurve2D = CurveConfig.GetScoreCurve2D(scoreid, calcuinfo.fstarttime);

                        scoreCurve = CurveConfig.GetScoreCurve(scoreid, calcuinfo.fstarttime);
                    }
                    else
                    {
                        //——20181031,因动态方式读取曲线,速度太慢,不在采用。
                        //——转而采用在静态方式下读取带生效时间的配置曲线。这样在增加配置曲线时,仅需要暂停计算引擎后重启,即可载入新的配置曲线,并继续进行计算。
                        //第一个参数为D时,动态读取期望曲线和积分曲线表
                        //opxCurve = CurveConfig.ReadOPXCurves(calcuinfo.fstarttime).Find(delegate(Curve1D a) { return a.Index == opxid; });
                        //scoreCurve = CurveConfig.ReadScoreCurves(calcuinfo.fstarttime).Find(delegate(Curve1D a) { return a.Index == scoreid; });
                        _errorFlag = true;
                        _errorInfo = "参数配置为D,动态读取配置曲线功能已经取消,请使用静态读取方式。";
                        return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                    }
                }
                catch (Exception ex)
                {
                    _errorFlag = true;
                    _errorInfo = String.Format("读取期望和得分曲线时错误!错误信息:{0}", ex.ToString());
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //判读所需要的曲线是否正确读取,如果没有正确读取一定是返回null,此时要给出错误log
                if (opxCurve == null)
                {
                    _errorFlag = true;
                    _errorInfo = String.Format("期望曲线为空,对应的期望曲线:{0}-{1}获取错误!", opxid, calcuinfo.fstarttime.ToString("yyyy-MM-dd HH:mm:ss"));
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                if (calcuMode == "D")
                {
                    if (scoreCurve2D == null)
                    {
                        _errorFlag = true;
                        _errorInfo = String.Format("得分曲线为空,对应的得分曲线:{0}-{1}获取错误!", scoreid, calcuinfo.fstarttime.ToString("yyyy-MM-dd HH:mm:ss"));
                        return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                    }
                }
                if (calcuMode == "S")
                {
                    if (scoreCurve == null)
                    {
                        _errorFlag = true;
                        _errorInfo = String.Format("得分曲线为空,对应的得分曲线:{0}-{1}获取错误!", scoreid, calcuinfo.fstarttime.ToString("yyyy-MM-dd HH:mm:ss"));
                        return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                    }
                }



                //3、计算偏差
                PValue sp, err, errrate, score, wscore;                               //期望值、偏差、偏差比、得分

                sp      = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //期望值
                err     = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //偏差
                errrate = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //偏差比
                score   = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //得分
                wscore  = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //加权得分


                //Debug.WriteLine("----opxCurve.Xvalue[0] " + opxCurve.Xvalue[0].ToString() + "~opxCurve.Xvalue[1]" + opxCurve.Xvalue[opxCurve.Xvalue.Length - 1].ToString());
                //期望值:查期望曲线
                //处理方式一:参考点超限时,不做处理,对应时间段没有任何计算结果
                //——该方法的主要问题是,整分钟的偏差和得分计算接口,会有空。在那些超过偏差曲线范围外的时间段,没有分钟计算值。
                //——该方法导致的另外一个问题就是,由于缺少分钟值,并发计算在缺少分钟值的位置要去插值,这个插值行为是错误的。
                //——在缺少分钟值的情况下,实时计算,由于取数据时存在起始时间和截止时间的插值算法,如果恰好这些时间点没有值,也会进行插值,这个插值会造成错误。

                /*
                 * if (refdata.Value < opxCurve.Xvalue[0] || refdata.Value > opxCurve.Xvalue[opxCurve.Xvalue.Length - 1])
                 * {
                 *  return null;
                 * }
                 * else
                 * {
                 *  opx.Value = opxCurve.Fx(refdata.Value);
                 * }
                 */

                //处理方式二:参考点超限时,按边界点计算偏差。同时在计算结果中置标志位为StatusConst.OutOfValid4Bias.
                //——四个计算结果均按边界值计算,置计算结果标志位为StatusConst.OutOfValid4Bias。
                //——但是,凡是对偏差和得分这些结果进行进一步计算的,这些算法需要考虑标志位。
                //——由于不会缺少分钟值,无论是并发计算和实时计算都不会出现问题。


                if (refdata.Value < opxCurve.XLowerLimit)   //小于下限
                {
                    //如果参考标签的值,在期望曲线参考值有效范围外,则期望返回边界值。
                    sp.Value    = opxCurve.Fx(opxCurve.XLowerLimit); //期望值返回边界值
                    invalidflag = StatusConst.OutOfValid4Bias;       //至过程值超限标志
                }
                else if (refdata.Value > opxCurve.XUpperLimit)       //大于上限
                {
                    sp.Value    = opxCurve.Fx(opxCurve.XUpperLimit);
                    invalidflag = StatusConst.OutOfValid4Bias;
                }
                else
                {
                    sp.Value = opxCurve.Fx(refdata.Value);          //期望值按正常计算
                }

                //偏差=实际值-期望值
                err.Value = pvdata.Value - sp.Value;
                //偏差比=偏差/期望值
                if (sp.Value == 0)
                {
                    errrate.Value = 0;
                }
                else
                {
                    errrate.Value = err.Value / sp.Value * 100;
                }
                //得分:查记分曲线
                //——偏差超过限度时,直接返回得分边界值。但是得分不像偏差曲线的x越界,要置invalidflag
                if (calcuMode == "S")
                {
                    score.Value = scoreCurve.Fx(err.Value);
                }
                else
                {
                    //参考值Y(对应表的第一列配置)
                    if (refdata.Value < scoreCurve2D.YLowerLimit)
                    {
                        refdata.Value = scoreCurve2D.YLowerLimit;
                        invalidflag   = StatusConst.OutOfValid4Bias;
                    }
                    else if (refdata.Value > scoreCurve2D.YUpperLimit)
                    {
                        refdata.Value = scoreCurve2D.YUpperLimit;
                        invalidflag   = StatusConst.OutOfValid4Bias;
                    }
                    score.Value = scoreCurve2D.Fx(err.Value, refdata.Value); //虽然一律要算期望值,但是超限后按边界算期望,所有计算结果标志位都会被置位
                }

                wscore.Value = k * score.Value + b;
                //4、录入数据库
                MDeviationSOutClass MessageIN = new MDeviationSOutClass();
                MessageIN.sp      = sp.Value;
                MessageIN.err     = err.Value;
                MessageIN.errrate = errrate.Value;
                MessageIN.score   = score.Value;
                MessageIN.wscore  = wscore.Value;
                string year  = string.Empty;
                string month = string.Empty;
                string day   = string.Empty;
                string hour  = string.Empty;
                year  = calcuinfo.fstarttime.Year.ToString();
                month = calcuinfo.fstarttime.Month.ToString();
                day   = calcuinfo.fstarttime.Day.ToString();
                hour  = calcuinfo.fstarttime.Hour.ToString();
                bool isok = BLL.AlgorithmBLL.insertMDeviationS(MessageIN, calcuinfo.fsourtagids[0].ToString(), year, month, day, hour, Convert.ToInt32(invalidflag));
                if (isok)
                {
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                else
                {
                    _fatalFlag = true;
                    _fatalInfo = "MDeviationS数据录入数据库是失败";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
            }
            catch (Exception ex)
            {
                //计算中出任何错误,则需要记录log
                //LogHelper.Write(LogType.Error, "计算模块错误!");
                //记录计算模块的名称、当前标签、起始时间、结束时间
                //string moduleInfo = string.Format("——计算模块的名称是:{0},当前计算源标签是:{1},计算起始时间是:{2},计算结束时间是:{3}。", calcuInfo.fmodulename, calcuInfo.sourcetagname, calcuinfo.fstarttime.ToString(), calcuinfo.fendtime.ToString());
                //LogHelper.Write(LogType.Error, moduleInfo);
                //计算引擎报错具体信息
                //string errInfo = string.Format("——具体报错信息:{0}。", ex.ToString());
                //LogHelper.Write(LogType.Error, errInfo);
                //返回null供计算引擎处理
                _fatalFlag = true;
                _fatalInfo = ex.ToString();
                return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
            }
        }
        public static Results Calcu(List <PValue>[] inputs, CalcuInfo calcuinfo)
        {
            //公用变量
            bool   _errorFlag   = false;
            string _errorInfo   = "";
            bool   _warningFlag = false;
            string _warningInfo = "";
            bool   _fatalFlag   = false;
            string _fatalInfo   = "";

            int i;

            //0输出初始化:该算法如果没有有效输入值(inputs为null)或者输入值得有效值为null,给出的计算结果。值为0,计算标志位为StatusConst.InputIsNull
            List <PValue>[] results = new List <PValue> [5];
            for (i = 0; i < results.Length; i++)
            {
                results[i] = new List <PValue>();
                results[i].Add(new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, (long)StatusConst.InputIsNull));
            }

            try
            {
                //0、输入

                //0.1、输入处理:输入长度。当输入为空时,给出标志位为StatusConst.InputIsNull的计算结果.
                if (inputs == null || inputs.Length < 3)
                {
                    _errorFlag = true;
                    _errorInfo = "二维偏差及得分计算要求必须有且仅有三个有效输入。当前输入为空或输入数量不足。";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                if (inputs[0] == null || inputs[1] == null || inputs[2] == null)
                {
                    _errorFlag = true;
                    _errorInfo = "二维偏差及得分计算要求三个输入均不为空。当前输入有空数据。";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                //0.2、输入处理:截止时刻值。该算法,截止时刻点不需要参与计算,要删除。
                //本算法做特别处理
                //if (input.Count > 1) input.RemoveAt(input.Count - 1);
                //0.3、输入处理:标志位。该算法考虑标志位不为0的情况,先过滤这些点。
                //********如果计算偏差前,参考量和被考核量,在计算的分钟周期内,分钟值为状态位无效的值。
                //********这里会读入这个值,并在下面过滤。如果被过滤,则下面的参考量和被考核量长度判断会报错。并返回不正常状态的计算结果。
                for (i = 0; i < inputs.Length; i++)
                {
                    for (int j = inputs[i].Count - 1; j >= 0; j--)
                    {
                        if (inputs[i][j].Status != 0)
                        {
                            inputs[i].RemoveAt(j);
                        }
                    }
                }

                //0.4、输入处理:过滤后结果。
                //本算法做特别处理
                //——如果去除了截止时刻点,过滤后长度小于1(计算要求至少有一个有效数据),则直接返回全0
                //——如果没取除截止时刻点,过滤后长度小于2(计算要求至少有一个有效数据和一个截止时刻值)
                //if (input.Count < 1) return results;

                //1、检查并整理数据
                //——这里是计算每分钟的偏差。
                //——输入量是被评变量每分钟滤波值、参考变量每分钟滤波值
                if (inputs[0] == null || inputs[0].Count < 2)
                {
                    _warningFlag = true;
                    _warningInfo = "二维偏差及得分计算,被测评量正常状态的数据为空";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                if (inputs[1] == null || inputs[1].Count < 2)
                {
                    _warningFlag = true;
                    _warningInfo = "二维偏差及得分计算,第一个参考量正常状态的数据为空";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                if (inputs[2] == null || inputs[2].Count < 2)
                {
                    _warningFlag = true;
                    _warningInfo = "二维偏差及得分计算,第二个参考量正常状态的数据为空";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //1.2、直接读取各变量第一个数据,不需要处理截止时刻值

                PValue pvdata;
                PValue refdataX;
                PValue refdataY;

                pvdata   = inputs[0][0];                      //不使用截止值,被测评量
                refdataX = inputs[1][0];                      //不使用截止值,参考量1
                refdataY = inputs[2][0];                      //不使用截止值,参考量2

                StatusConst invalidflag = StatusConst.Normal; //参考指标值是否超越偏差曲线x范围,当次指标考核计算是否有效

                //2、根据参数获取期望曲线、记分曲线
                string[] para       = calcuinfo.fparas.Split(new char[] { ';' });
                string   readMethod = para[0];            //第一个参数是获取曲线的方式,D为动态,S为静态。动态方式,每次计算均读取CSV。静态方式,只读取一次CSV。
                int      opxid      = int.Parse(para[1]); //第二个参数是期望曲线序号
                int      scoreid    = int.Parse(para[2]); //第三个参数是得分曲线序号
                double   k          = double.Parse(para[3]);
                double   b          = double.Parse(para[4]);
                Curve2D  opxCurve;                                           //偏差曲线是二维
                Curve1D  scoreCurve;                                         //得分曲线是一维
                string   strTemp = CurveConfig.Instance.OPXCurvesReadStatus; //这行这条语句是为了下面在使用CurveConfig.GetXXXCurve时保证Instance已被初始化。20181109调试发现该问题。

                try
                {
                    if (readMethod.ToUpper() == "S")
                    {   //静态读取,对于分钟计算来说,只有第一次才读取偏差曲线和得分曲线
                        opxCurve   = CurveConfig.GetOPXCurve2D(opxid, calcuinfo.fstarttime);
                        scoreCurve = CurveConfig.GetScoreCurve(scoreid, calcuinfo.fstarttime);
                    }
                    else
                    {   //——20181031,因动态方式读取曲线,速度太慢,不在采用。
                        //——转而采用在静态方式下读取带生效时间的配置曲线。这样在增加配置曲线时,仅需要暂停计算引擎后重启,即可载入新的配置曲线,并继续进行计算。
                        //动态读取,对于分钟计算来说,每次计算都要读取偏差曲线和得分曲线
                        //opxCurve = CurveConfig.ReadOPXCurves2D(calcuinfo.fstarttime).Find(delegate(Curve2D a) { return a.Index == opxid; });
                        //scoreCurve = CurveConfig.ReadScoreCurves(calcuinfo.fstarttime).Find(delegate(Curve1D a) { return a.Index == scoreid; });
                        _errorFlag = true;
                        _errorInfo = "参数配置为D,动态读取配置曲线功能已经取消,请使用静态读取方式。";
                        return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                    }
                }
                catch (Exception ex)
                {
                    _errorFlag = true;
                    _errorInfo = String.Format("读取期望和得分曲线时错误!错误信息:{0}", ex.ToString());
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                //判读所需要的曲线是否正确读取,如果没有正确读取一定是返回null,此时要给出错误log
                if (opxCurve == null)
                {
                    _errorFlag = true;
                    _errorInfo = String.Format("期望曲线为空,对应的期望曲线:{0}-{1}获取错误!", opxid, calcuinfo.fstarttime.ToString("yyyy-MM-dd HH:mm:ss"));
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                if (scoreCurve == null)
                {
                    _errorFlag = true;
                    _errorInfo = String.Format("得分曲线为空,对应的得分曲线:{0}-{1}获取错误!", scoreid, calcuinfo.fstarttime.ToString("yyyy-MM-dd HH:mm:ss"));
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //3、计算偏差
                PValue sp, err, errrate, score, wscore;       //期望值、偏差、偏差比、得分

                sp      = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0);
                err     = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0);
                errrate = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0);
                score   = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0);
                wscore  = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0);       //加权得分
                //计算期望值,查期望曲线。当参考量超限时,有两种处理方法
                //处理方式一:不做处理,返回null,对应时间段没有任何计算结果

                /*
                 * if (refdataX.Value < opxCurve.Xvalue[0] ||
                 *  refdataX.Value > opxCurve.Xvalue[opxCurve.Xvalue.Length - 1] ||
                 *  refdataY.Value < opxCurve.Yvalue[0] ||
                 *  refdataY.Value > opxCurve.Yvalue[opxCurve.Yvalue.Length - 1]
                 *  )
                 * {
                 *  //如果参考标签的值,在期望曲线参考值有效范围外,则当前时刻点,考核无效,不返回任何考核值
                 *  return null;
                 * }
                 */
                //处理方式二:任意一个参考值超限时,按边界值计算偏差,同时所有计算结果状态位置为StatusConst.OutOfValid4Bias
                //要注意,防止偏差曲线的x不是从小到大。
                //参考值X(对应表的第一行配置)
                if (refdataX.Value < opxCurve.XLowerLimit)
                {
                    refdataX.Value = opxCurve.XLowerLimit;
                    invalidflag    = StatusConst.OutOfValid4Bias;
                }
                else if (refdataX.Value > opxCurve.XUpperLimit)
                {
                    refdataX.Value = opxCurve.XUpperLimit;
                    invalidflag    = StatusConst.OutOfValid4Bias;
                }
                //参考值Y(对应表的第一列配置)
                if (refdataY.Value < opxCurve.YLowerLimit)
                {
                    refdataY.Value = opxCurve.YLowerLimit;
                    invalidflag    = StatusConst.OutOfValid4Bias;
                }
                else if (refdataY.Value > opxCurve.YUpperLimit)
                {
                    refdataY.Value = opxCurve.YUpperLimit;
                    invalidflag    = StatusConst.OutOfValid4Bias;
                }
                //期望值:查期望曲线 - 2d表格
                sp.Value = opxCurve.Fx(refdataX.Value, refdataY.Value); //虽然一律要算期望值,但是超限后按边界算期望,所有计算结果标志位都会被置位

                //偏差=实际值-期望值
                err.Value = pvdata.Value - sp.Value;
                //偏差比=偏差/期望值
                if (sp.Value == 0)
                {
                    errrate.Value = 0;
                }
                else
                {
                    errrate.Value = err.Value / sp.Value * 100;
                }

                //得分:查记分曲线
                //——偏差超过限度时,直接返回得分边界值。但是得分不像偏差曲线的x越界,要置invalidflag
                score.Value  = scoreCurve.Fx(err.Value);
                wscore.Value = k * score.Value + b;
                //4、录入数据库
                MDeviationSOutClass MessageIN = new MDeviationSOutClass();
                MessageIN.sp      = sp.Value;
                MessageIN.err     = err.Value;
                MessageIN.errrate = errrate.Value;
                MessageIN.score   = score.Value;
                MessageIN.wscore  = wscore.Value;
                string year  = string.Empty;
                string month = string.Empty;
                string day   = string.Empty;
                string hour  = string.Empty;
                year  = calcuinfo.fstarttime.Year.ToString();
                month = calcuinfo.fstarttime.Month.ToString();
                day   = calcuinfo.fstarttime.Day.ToString();
                hour  = calcuinfo.fstarttime.Hour.ToString();
                bool isok = BLL.AlgorithmBLL.insertMDeviation2DS(MessageIN, calcuinfo.fsourtagids[0].ToString(), year, month, day, hour, Convert.ToInt32(invalidflag));
                if (isok)
                {
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                else
                {
                    _fatalFlag = true;
                    _fatalInfo = "MDeviationS数据录入数据库是失败";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
            }
            catch (Exception ex)
            {
                //计算中出任何错误,则需要记录log
                //LogHelper.Write(LogType.Error, "计算模块错误!");
                //记录计算模块的名称、当前标签、起始时间、结束时间
                //string moduleInfo = string.Format("——计算模块的名称是:{0},当前计算源标签是:{1},计算起始时间是:{2},计算结束时间是:{3}。", calcuInfo.fmodulename, calcuInfo.sourcetagname, calcuinfo.fstarttime.ToString(), calcuinfo.fendtime.ToString());
                //LogHelper.Write(LogType.Error, moduleInfo);
                //计算引擎报错具体信息
                //string errInfo = string.Format("——具体报错信息:{0}。", ex.ToString());
                //LogHelper.Write(LogType.Error, errInfo);
                //返回null供计算引擎处理
                _fatalFlag = true;
                _fatalInfo = ex.ToString();
                return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
            }
        }