Exemplo n.º 1
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> [4];
            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[] 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]); //第三个参数是得分曲线序号

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

                try
                {
                    if (readMethod.ToUpper() == "S")
                    {
                        //第一个参数为S时,静态读取期望曲线和积分曲线表
                        opxCurve   = CurveConfig.GetOPXCurve(opxid, 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 (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 opx, opxe, opxerate, opxw;                                      //期望值、偏差、偏差比、得分

                opx      = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //期望值
                opxe     = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //偏差
                opxerate = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //偏差比
                opxw     = 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);
                 * }
                 */

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


                //期望值

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


                //偏差=实际值-期望值
                opxe.Value = pvdata.Value - opx.Value;
                //偏差比=偏差/期望值
                if (opx.Value == 0)
                {
                    opxerate.Value = 0;
                }
                else
                {
                    opxerate.Value = opxe.Value / opx.Value * 100;
                }
                //得分:查记分曲线
                //——偏差超过限度时,直接返回得分边界值。而得分不像偏差曲线的x越界,要置invalidflag
                opxw.Value = scoreCurve.Fx(opxe.Value);

                //4、组织输出
                for (i = 0; i < 4; i++)
                {
                    results[i] = new List <PValue>();
                }
                results[0].Add(opx);
                results[1].Add(opxe);
                results[2].Add(opxerate);
                results[3].Add(opxw);

                //5、如果越界标识不为0,还需要给每个结果的状态添加越界的标志。
                if (invalidflag != 0)
                {
                    for (i = 0; i < 4; i++)
                    {
                        results[i][0].Status = (long)invalidflag;
                    }
                }

                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));
            }
        }
Exemplo n.º 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> [4];
            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的计算结果.
                //——在该算法下,正常情况不应该出现inputs整体为空的情况,出现整体为空,说明前置的求每分钟均值的算法有误。这种情况必须给出错误
                if (inputs == null || inputs.Length < 2 || inputs[0] == null || inputs[0].Count == 0 || inputs[1] == null || inputs[1].Count == 0)            //一些情况下,进来就有null,这样下面的的取出状态为会出错
                {
                    _errorFlag = true;
                    _errorInfo = "时间段一维偏差算法输入错误。输入为空或输入数量不足,或者被考核量、参考量数据长度为0。";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //0.2、输入处理:输入的是要参与考核的被考核量与参考量的分钟数据,长度必须相同
                if (inputs[0].Count != inputs[1].Count)
                {
                    _errorFlag = true;
                    _errorInfo = "时间段一维偏差算法输入错误。被考核量和参考量数据长度不相同。";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //准备结果,只要输入数据没有整体错误,则必须有计算结果
                int             spanNumber      = inputs[0].Count - 1; //不算截止数据
                double          intervalseconds = (double)(calcuinfo.fendtime.Subtract(calcuinfo.fstarttime).TotalSeconds / spanNumber);
                List <PValue>[] tempresults     = new List <PValue> [4];
                tempresults[0] = new List <PValue>();  //期望
                tempresults[1] = new List <PValue>();  //偏差
                tempresults[2] = new List <PValue>();  //偏差比
                tempresults[3] = new List <PValue>();  //得分

                //在输入数量正确,且分钟数量的数量相同的情况下,循环计算每分钟的偏差值
                for (int j = 0; j < inputs[0].Count - 1; j++)   //不计算截止数据
                {
                    //0.3 初始化当前分钟的计算结果
                    for (i = 0; i < results.Length; i++)
                    {
                        tempresults[i].Add(new PValue(0, calcuinfo.fstarttime.AddSeconds(j * intervalseconds), calcuinfo.fstarttime.AddSeconds((j + 1) * intervalseconds), (long)StatusConst.InputIsNull));
                    }
                    //0.4、输入处理:检查标志位。
                    //——这里是计算每分钟的偏差。
                    //——输入量是被评变量每分钟滤波值、参考变量每分钟滤波值
                    if (inputs[0][j] == null || inputs[1][j] == null)
                    {
                        //正常状态下,不应该出现分钟过滤值在某个点没有值得情况,这种情况说明分钟过滤算法有误,应该检查
                        //在计算引擎中,即使计算错误标志为true,但仍会写计算结果
                        string nullobject = "";
                        if (inputs[0][j] == null)
                        {
                            nullobject += "被考核量";
                        }
                        if (inputs[1][j] == null)
                        {
                            nullobject += "、参考量";
                        }

                        _errorFlag  = true;
                        _errorInfo += String.Format("时间段一维偏差及得分计算,{0}分钟数据为空。请检查!" + Environment.NewLine, nullobject);
                        //return new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo);  //这里不直接结束,而是继续循环
                        continue;
                    }
                    if (inputs[0][j].Status != 0 || inputs[1][j].Status != 0)
                    {
                        string statusnotzero = "";
                        if (inputs[0][j].Status != 0)
                        {
                            statusnotzero += "被考核量";
                        }
                        if (inputs[1][j].Status != 0)
                        {
                            statusnotzero += "、参考量";
                        }
                        //正常状态下,有可能出现分钟过滤在某个时刻点状态值非0,记录报警,并计算下一个点
                        _warningFlag  = true;
                        _warningInfo += String.Format("时间段一维偏差及得分计算,{0}分钟数据状态位异常。{1}到{2}无有效数据!" + Environment.NewLine,
                                                      statusnotzero,
                                                      inputs[0][j].Timestamp.ToString("yyyy-MM-dd HH:mm:ss"),
                                                      inputs[0][j].Timestamp.ToString("yyyy-MM-dd HH:mm:ss")
                                                      );
                        continue;
                    }

                    //1.2 直接取各变量分钟值
                    PValue pvdata;
                    PValue refdata;

                    pvdata  = inputs[0][j];                       //
                    refdata = inputs[1][j];                       //

                    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]); //第三个参数是得分曲线序号

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

                    try
                    {
                        if (readMethod.ToUpper() == "S")
                        {
                            //第一个参数为S时,静态读取期望曲线和积分曲线表
                            opxCurve   = CurveConfig.GetOPXCurve(opxid, 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()) + Environment.NewLine;
                        //return new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo);
                        continue;
                    }

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

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

                    sp      = new PValue(0, calcuinfo.fstarttime.AddSeconds(j * intervalseconds), calcuinfo.fstarttime.AddSeconds((j + 1) * intervalseconds), 0); //期望值
                    err     = new PValue(0, calcuinfo.fstarttime.AddSeconds(j * intervalseconds), calcuinfo.fstarttime.AddSeconds((j + 1) * intervalseconds), 0); //偏差
                    errrate = new PValue(0, calcuinfo.fstarttime.AddSeconds(j * intervalseconds), calcuinfo.fstarttime.AddSeconds((j + 1) * intervalseconds), 0); //偏差比
                    score   = new PValue(0, calcuinfo.fstarttime.AddSeconds(j * intervalseconds), calcuinfo.fstarttime.AddSeconds((j + 1) * intervalseconds), 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。
                    //——但是,凡是对偏差和得分这些结果进行进一步计算的,这些算法需要考虑标志位。
                    //——由于不会缺少分钟值,无论是并发计算和实时计算都不会出现问题。

                    //要注意,防止偏差曲线的x不是从小到大。(但是,目前硬性要求期望曲线和得分曲线配置,范围要从低到高。因此老版本上,没有这个判断)
                    double XMin = opxCurve.Xvalue[0] < opxCurve.Xvalue[opxCurve.Xvalue.Length - 1] ? opxCurve.Xvalue[0] : opxCurve.Xvalue[opxCurve.Xvalue.Length - 1];
                    double XMax = opxCurve.Xvalue[0] < opxCurve.Xvalue[opxCurve.Xvalue.Length - 1] ? opxCurve.Xvalue[opxCurve.Xvalue.Length - 1] : opxCurve.Xvalue[0];

                    if (refdata.Value < XMin)
                    {
                        //如果参考标签的值,在期望曲线参考值有效范围外,则偏差返回边界值。
                        sp.Value    = opxCurve.Fx(XMin);
                        invalidflag = StatusConst.OutOfValid4Bias;
                    }
                    else if (refdata.Value > XMax)
                    {
                        sp.Value    = opxCurve.Fx(XMax);
                        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
                    score.Value = scoreCurve.Fx(err.Value);

                    //4、组织输出
                    for (i = 0; i < 4; i++)
                    {
                        results[i] = new List <PValue>();
                    }
                    tempresults[0][j] = sp;
                    tempresults[1][j] = err;
                    tempresults[2][j] = errrate;
                    tempresults[3][j] = score;

                    //如果越界标识不为0,还需要给每个结果的状态添加越界的标志。
                    if (invalidflag != 0)
                    {
                        for (i = 0; i < 4; i++)
                        {
                            tempresults[i][j].Status = (long)invalidflag;
                        }
                    }
                }//end for

                return(new Results(tempresults, _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));
            }
        }
Exemplo n.º 3
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));
            }
        }
Exemplo n.º 4
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> [4];
            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[0].Count == 0)
                {
                    _errorFlag = true;
                    _errorInfo = "时间段二维偏差及得分计算输入错误。被考核量输入数据为空。";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                if (inputs[1] == null || inputs[1].Count == 0)
                {
                    _errorFlag = true;
                    _errorInfo = "时间段二维偏差及得分计算输入错误。参考量1输入数据为空。";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                if (inputs[2] == null || inputs[2].Count == 0)
                {
                    _errorFlag = true;
                    _errorInfo = "时间段二维偏差及得分计算输入错误。参考量2输入数据为空。";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //0.2、在判断各个数据长度是否相等之前,对常数标签按照被考核量进行扩充。因为常数标签仅返回一个值。
                for (i = 1; i < inputs.Length; i++)                                         //第0个量是被考核指标,不可能是常数标签
                {
                    if (calcuinfo.fsourtagids[i] < APPConfig.rdbtable_constmaxnumber)
                    {
                        double        constValue = inputs[i][0].Value;                      //常数标签仅返回一个值
                        List <PValue> constList  = new List <PValue>();                     //以被考核量为标准,重新构建常数标签
                        for (int j = 0; j < inputs[0].Count; j++)
                        {
                            constList.Add(new PValue(constValue, inputs[0][j].Timestamp, inputs[0][j].Endtime, inputs[0][j].Status));
                        }
                        inputs[i] = constList;
                    }
                }

                //0.2、输入处理:输入的是要参与考核的被考核量与参考量的分钟数据,长度必须相同。
                //——因为被考核量和考核量,都是经过filter计算的,无论实时数据有什么问题,filter计算后都应该产生计算结果(只不过状态位不同)。
                //——因此正常状态下,被考核量与考核量的长度应该相同,如果不相同,则说明filter计算一定有问题,需要检查。因此这里应该报错误。而不是报警告。
                if (inputs[0].Count != inputs[1].Count || inputs[0].Count != inputs[2].Count || inputs[1].Count != inputs[2].Count)
                {
                    _errorFlag = true;
                    _errorInfo = "时间段一维偏差算法输入错误。被考核量和参考量数据长度不相同。";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //准备结果,只要输入数据没有整体错误,则必须有计算结果
                int             spanNumber      = inputs[0].Count - 1; //不算截止数据
                double          intervalseconds = (double)(calcuinfo.fendtime.Subtract(calcuinfo.fstarttime).TotalSeconds / spanNumber);
                List <PValue>[] tempresults     = new List <PValue> [4];
                tempresults[0] = new List <PValue>();                //期望
                tempresults[1] = new List <PValue>();                //偏差
                tempresults[2] = new List <PValue>();                //偏差比
                tempresults[3] = new List <PValue>();                //得分

                //在输入数量正确,且分钟数量的数量相同的情况下,循环计算每分钟的偏差值
                for (int j = 0; j < inputs[0].Count - 1; j++) //不计算截止数据
                {
                    //0.3 初始化当前分钟的计算结果
                    for (i = 0; i < results.Length; i++)
                    {
                        tempresults[i].Add(new PValue(0, calcuinfo.fstarttime.AddSeconds(j * intervalseconds), calcuinfo.fstarttime.AddSeconds((j + 1) * intervalseconds), (long)StatusConst.InputIsNull));
                    }

                    //0.4、输入处理:检查标志位。
                    //——这里是计算每分钟的偏差。
                    //——输入量是被评变量每分钟滤波值、参考变量每分钟滤波值
                    if (inputs[0][j] == null || inputs[1][j] == null || inputs[2][j] == null)
                    {
                        //正常状态下,不应该出现分钟过滤值在某个点没有值得情况,这种情况说明分钟过滤算法有误,应该检查
                        //在计算引擎中,即使计算错误标志为true,但仍会写计算结果
                        string nullobject = "";
                        if (inputs[0][j] == null)
                        {
                            nullobject += "|被考核量|";
                        }
                        if (inputs[1][j] == null)
                        {
                            nullobject += "|参考量1|";
                        }
                        if (inputs[2][j] == null)
                        {
                            nullobject += "|参考量2|";
                        }

                        _errorFlag  = true;
                        _errorInfo += String.Format("时间段二维偏差及得分计算,{0}从{1}到{2}的分钟数据为空。请检查!" + Environment.NewLine,
                                                    nullobject,
                                                    inputs[0][j].Timestamp.ToString("yyyy-MM-dd HH:mm:ss"),
                                                    inputs[0][j].Endtime.ToString("yyyy-MM-dd HH:mm:ss")
                                                    );
                        //return new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo);  //这里不直接结束,而是继续循环,计算下一分钟的偏差值
                        continue;
                    }
                    else if (inputs[0][j].Status != 0 || inputs[1][j].Status != 0 || inputs[2][j].Status != 0)
                    {
                        string statusnotzero = "";
                        if (inputs[0][j].Status != 0)
                        {
                            statusnotzero += "|被考核量|";
                        }
                        if (inputs[1][j].Status != 0)
                        {
                            statusnotzero += "|参考量1|";
                        }
                        if (inputs[2][j].Status != 0)
                        {
                            statusnotzero += "|参考量2|";
                        }
                        //正常状态下,有可能出现分钟过滤在某个时刻点状态值非0,记录报警,并计算下一个点
                        _warningFlag  = true;
                        _warningInfo += String.Format("时间段二维偏差及得分计算,{0}的分钟数据状态位异常。从{1}到{2}无有效数据。请检查!" + Environment.NewLine,
                                                      statusnotzero,
                                                      inputs[0][j].Timestamp.ToString("yyyy-MM-dd HH:mm:ss"),
                                                      inputs[0][j].Endtime.ToString("yyyy-MM-dd HH:mm:ss")
                                                      );
                        continue;
                    }

                    //1.2、直接取各变量分钟值

                    PValue pvdata;
                    PValue refdataX;
                    PValue refdataY;

                    pvdata   = inputs[0][j];                      //不使用截止值,被测评量
                    refdataX = inputs[1][j];                      //不使用截止值,参考量1
                    refdataY = inputs[2][j];                      //不使用截止值,参考量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]);                   //第三个参数是得分曲线序号

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

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

                    sp      = new PValue(0, calcuinfo.fstarttime.AddSeconds(j * intervalseconds), calcuinfo.fstarttime.AddSeconds((j + 1) * intervalseconds), 0);
                    err     = new PValue(0, calcuinfo.fstarttime.AddSeconds(j * intervalseconds), calcuinfo.fstarttime.AddSeconds((j + 1) * intervalseconds), 0);
                    errrate = new PValue(0, calcuinfo.fstarttime.AddSeconds(j * intervalseconds), calcuinfo.fstarttime.AddSeconds((j + 1) * intervalseconds), 0);
                    score   = new PValue(0, calcuinfo.fstarttime.AddSeconds(j * intervalseconds), calcuinfo.fstarttime.AddSeconds((j + 1) * intervalseconds), 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);

                    //4、组织输出
                    results = new List <PValue> [4];
                    for (i = 0; i < 4; i++)
                    {
                        results[i] = new List <PValue>();
                    }
                    tempresults[0][j] = sp;
                    tempresults[1][j] = err;
                    tempresults[2][j] = errrate;
                    tempresults[3][j] = score;

                    //如果越界标识不为0,还需要给每个结果的状态添加越界的标志。
                    if (invalidflag != 0)
                    {
                        for (i = 0; i < 4; i++)
                        {
                            tempresults[i][j].Status = (long)invalidflag;
                        }
                    }
                }
                return(new Results(tempresults, _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));
            }
        }
Exemplo n.º 5
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 < 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));
            }
        }