Ejemplo 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;

            //如果限定条件形式为"(,70)",则lowerLimit=MinValue,upperLimit=70,其含义是要找某标签实时值小于70的时间段
            try
            {
                List <PValue> input = inputs[0];

                //处理截止时刻数据
                if (input.Count > 1)
                {
                    input.RemoveAt(input.Count - 1);
                }


                //1、取参数
                string[] paras = calcuinfo.fparas.Split(new char[1] {
                    ','
                });

                double min;
                if (paras.Length >= 1 && paras[0] != "")
                {
                    min = float.Parse(paras[0]);    //取第1个参数,归一化下限
                }
                else
                {
                    min = 0;  //如果没哟设置,取0
                }
                double max;
                if (paras.Length >= 2 && paras[1] != "")
                {
                    max = float.Parse(paras[1]);          //取第2个参数,归一化上限
                }
                else
                {
                    max = 100;  //如果没哟设置,取100
                }

                //2、根据设定的最大值和最小值进行归一化
                double range = max - min;
                for (i = 0; i < input.Count; i++)
                {
                    if (input[i].Value >= max)
                    {
                        input[i].Value = 1;
                    }
                    else if (input[i].Value <= min)
                    {
                        input[i].Value = 0;
                    }
                    else
                    {
                        input[i].Value = (input[i].Value - min) / range;
                    }
                }

                //3、返回结果
                List <PValue>[] results = new List <PValue> [1];
                results[0] = input;

                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(null, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
            }
        }//end module
Ejemplo 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   = "";

            //0输出初始化:该算法如果没有有效输入值(inputs为null)或者输入值得有效值为null,给出的计算结果。值为0,计算标志位为StatusConst.InputIsNull
            List <PValue>[] results = new List <PValue> [6];   //平均值;最小值;最小值所在的点号;最大值;最大值所在的点号;最均差;最大差(最大值与最小值得差);和;绝对值和
            for (int 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、输入
                List <PValue> input;
                //0.1、输入处理:输入长度。当输入为空时,则输出项也为空.
                if (inputs == null || inputs.Length == 0 || inputs[0] == null)
                {
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                else
                {
                    input = new List <PValue>();
                    //应当是每个输入只有一个值
                    for (int j = 0; j < inputs.Length; j++)
                    {
                        if (inputs[j].Count() > 0)
                        {
                            input.Add(inputs[j][0]);
                        }
                    }
                }

                //1 参数处理
                double   k;
                double   b;
                string[] paras = calcuinfo.fparas.Split(';');
                k = float.Parse(paras[0]);
                b = float.Parse(paras[1]);

                //计算结果初始化
                PValue AddMulSum    = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //和; 1
                PValue AddMulAbsSum = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //绝对值的和; 2
                PValue AddMulMul    = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //积;3
                PValue AddMulAbsMul = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //绝对值的积;4
                PValue AddMulAvg    = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //平均值;5
                PValue AddMulAbsAvg = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //绝对值的平均值;6

                double sum = 0, abssum = 0, mul = 1, absmul = 1, avg, absavg;

                for (int i = 0; i < input.Count; i++)
                {
                    sum    = sum + input[i].Value;
                    abssum = abssum + Math.Abs(input[i].Value);
                    mul    = mul * input[i].Value;
                    absmul = absmul * Math.Abs(input[i].Value);
                }
                avg    = sum / input.Count;
                absavg = abssum / input.Count;

                //对计算结果赋值
                AddMulSum.Value    = k * sum + b;
                AddMulAbsSum.Value = k * abssum + b;
                AddMulMul.Value    = k * mul + b;
                AddMulAbsMul.Value = k * absmul + b;
                AddMulAvg.Value    = k * avg + b;
                AddMulAbsAvg.Value = k * absavg + b;

                //录入数据库
                MAddMulOutClass MessageIN = new MAddMulOutClass();
                MessageIN.addMulSum    = AddMulSum.Value;
                MessageIN.addMulAbsSum = AddMulAbsSum.Value;
                MessageIN.addMulMul    = AddMulMul.Value;
                MessageIN.addMulAbsMul = AddMulAbsMul.Value;
                MessageIN.addMulAvg    = AddMulAvg.Value;
                MessageIN.addMulAbsAvg = AddMulAbsAvg.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.insertMAddMul(MessageIN, calcuinfo.fsourtagids[0].ToString(), year, month, day, hour);
                if (isok)
                {
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                else
                {
                    _fatalFlag = true;
                    _fatalInfo = "MAddMul数据录入数据库是失败";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }



                results[0] = new List <PValue>();
                results[0].Add(AddMulSum);
                results[1] = new List <PValue>();
                results[1].Add(AddMulAbsSum);
                results[2] = new List <PValue>();
                results[2].Add(AddMulMul);
                results[3] = new List <PValue>();
                results[3].Add(AddMulAbsMul);
                results[4] = new List <PValue>();
                results[4].Add(AddMulAvg);
                results[5] = new List <PValue>();
                results[5].Add(AddMulAbsAvg);
                return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
            }
            catch (Exception ex)
            {
                _fatalFlag = true;
                _fatalInfo = ex.ToString();
                return(new Results(null, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
            }
        }
Ejemplo 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,则输出项也为空.
            List <PValue>[] results = new List <PValue> [1];
            results[0] = new List <PValue>();
            results[0].Add(new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, (long)StatusConst.InputIsNull));

            try
            {
                //0.2、输入处理:截止时刻值。该算法不需要截止时刻点参与计算。
                for (i = 0; i < inputs.Length; i++)
                {
                    if (inputs[i].Count > 1)
                    {
                        inputs[i].RemoveAt(inputs[i].Count - 1);
                    }
                }

                //0.3、输入处理:标志位。该算法考虑标志位不检测标志位
                //for (i = input.Count - 1; i >= 0; i--)
                //{
                //    if (input[i].Status != 0) input.RemoveAt(i);
                //}
                //0.4、输入处理:过滤后结果。
                //——如果去除了截止时刻点,过滤后长度小于1(计算要求至少有一个有效数据),则直接返回null
                //——如果没取除截止时刻点,过滤后长度小于2(计算要求至少有一个有效数据和一个截止时刻值)
                for (i = 0; i < inputs.Length; i++)
                {
                    if (inputs[i].Count < 1)
                    {
                        return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                    }
                }


                //参数处理
                int num;

                string paras = calcuinfo.fparas;
                num = int.Parse(paras);

                PValue CleanF = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0);
                results = new List <PValue> [1];
                List <PValue> list = new List <PValue>();

                //开始计算
                //第一个输入为发电量  第二个输入为辐照量
                //辐照量每隔15分钟取一个值
                double b = 0.0;
                double m = 0.0;
                b = inputs[num - 1][13].Value;  //13点的值
                for (int j = 0; j < inputs.Length; j++)
                {
                    if (j != (num - 1))
                    {
                        list.Add(inputs[j][13]);
                    }
                }
                list.Sort();
                if (list.Count % 2 != 0)
                { //奇数
                    m = list[list.Count / 2].Value;
                }
                else   //偶数
                {
                    m = (list[list.Count / 2 - 1].Value + list[list.Count / 2].Value) / 2;
                }
                double result;
                for (int j = 0; j < inputs[1].Count; j++)
                {
                    if (j % 15 == 0)
                    {
                        b = b + inputs[1][j].Value;
                    }
                }
                result       = (b - m) / b * 100;
                CleanF.Value = result;
                results[0]   = new List <PValue>();
                results[0].Add(CleanF);
                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(null, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
            }
        }
Ejemplo 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   = "";

            //0输出初始化:该算法如果没有有效输入值(inputs为null)或者输入值得有效值为null,给出的计算结果。值为0,计算标志位为StatusConst.InputIsNull
            List <PValue>[] results = new List <PValue> [6];   //平均值;最小值;最小值所在的点号;最大值;最大值所在的点号;最均差;最大差(最大值与最小值得差);和;绝对值和
            for (int 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、输入
                List <PValue> input;
                //0.1、输入处理:输入长度。当输入为空时,则输出项也为空.
                if (inputs == null || inputs.Length == 0 || inputs[0] == null)
                {
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                else
                {
                    input = new List <PValue>();
                    //应当是每个输入只有一个值
                    for (int j = 0; j < inputs.Length; j++)
                    {
                        if (null != inputs[j])
                        {
                            input.Add(inputs[j][0]);
                        }
                    }
                }

                //1 参数处理

                string[] paras = calcuinfo.fparas.Split(';');

                double K      = float.Parse(paras[0]);
                double kR     = float.Parse(paras[1]);
                double M      = float.Parse(paras[2]);
                double SE     = float.Parse(paras[3]);
                double Result = float.Parse(paras[4]);
                double Status = float.Parse(paras[5]);

                //计算结果初始化
                PValue k    = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //和; 1
                PValue LRkR = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //绝对值的和; 2
                PValue LRa  = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //积;3
                PValue LRb  = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //绝对值的积;4
                PValue LRc  = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //平均值;5
                PValue LRR2 = new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0); //绝对值的平均值;6

                double sum = 0, abssum = 0, mul = 1, absmul = 1, avg, absavg;

                for (int i = 0; i < input.Count; i++)
                {
                    sum    = sum + input[i].Value;
                    abssum = abssum + Math.Abs(input[i].Value);
                    mul    = mul * input[i].Value;
                    absmul = absmul * Math.Abs(input[i].Value);
                }
                avg    = sum / input.Count;
                absavg = abssum / input.Count;

                //对计算结果赋值
                k.Value    = sum;
                LRkR.Value = abssum;
                LRa.Value  = mul;
                LRb.Value  = absmul;
                LRc.Value  = avg;
                LRR2.Value = absavg;

                //组织输出
                results[0] = new List <PValue>();
                results[0].Add(k);
                results[1] = new List <PValue>();
                results[1].Add(LRkR);
                results[2] = new List <PValue>();
                results[2].Add(LRa);
                results[3] = new List <PValue>();
                results[3].Add(LRb);
                results[4] = new List <PValue>();
                results[4].Add(LRc);
                results[5] = new List <PValue>();
                results[5].Add(LRR2);
                return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
            }
            catch (Exception ex)
            {
                _fatalFlag = true;
                _fatalInfo = ex.ToString();
                return(new Results(null, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
            }
        }
Ejemplo 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;

            List <PValue>[] results = new List <PValue> [28];
            for (i = 0; i < results.Length; i++)
            {
                results[i] = new List <PValue>();
                results[i].Add(new PValue(0, calcuInfo.fstarttime, calcuinfo.fendtime, 0));
            }
            results[22] = null;   //LLLSeries
            results[23] = null;   //LLSeries
            results[24] = null;   //LSeries
            results[25] = null;   //HSeries
            results[26] = null;   //HHSeries
            results[27] = null;   //HHHSeries

            try
            {
                //0输出初始化:该算法如果没有有效输入值(inputs为null)或者输入值得有效值为null,则0-21项应当有输出,所有的输出项为0.23-27项应当为空


                //0、输入
                List <PValue> input = new List <PValue>();
                //0.1、输入处理:输入长度。当输入为空时,所有的输出项为0.
                if (inputs == null || inputs.Length == 0 || inputs[0] == null)
                {
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }
                else
                {
                    input = inputs[0];
                }
                //0.2、输入处理:截止时刻值。该算法采用线性计算,截止时刻点要参与计算。不删除
                //if (input.Count > 1) input.RemoveAt(input.Count - 1);
                //0.3、输入处理:标志位。该算法考虑标志位不为0的情况,先过滤这些点。
                for (i = input.Count - 1; i >= 0; i--)
                {
                    input.RemoveAt(i);
                }
                //0.4、输入处理:过滤后结果。
                //——如果去除了截止时刻点,过滤后长度小于1(计算要求至少有一个有效数据),则直接返回null
                //——如果没取除截止时刻点,过滤后长度小于2(计算要求至少有一个有效数据和一个截止时刻值)
                if (input.Count < 2)
                {
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //1、准备界限数组和死区值
                double[] LimitRange = new double[6];  //界限数组,用于查找当前value值处于的值域段。界限数组包括八个值LLL、LL、L、H、HH、HHH六个值,MinValue和MaxValue
                double   LLLDeadBand, LLDeadBand, LDeadBand, HDeadBand, HHDeadBand, HHHDeadBand;
                LLLDeadBand = 0; LLDeadBand = 0; LDeadBand = 0; HDeadBand = 0; HHDeadBand = 0; HHHDeadBand = 0;
                double threshold;

                //1.1、对输入参数paras进行解析,输入参数一共12个值,包括三高三低的设定值和三高三低的死区值。如“20,50,60,80,85,90,2,2,2,2,2,2”
                string[] paras = calcuinfo.fparas.Split(',');
                for (i = 0; i < 6; i++)
                {
                    LimitRange[i] = float.Parse(paras[i]);
                }

                //对LimitRange进行排序,保证正确性。
                Array.Sort(LimitRange);

                LLLDeadBand = float.Parse(paras[6]);
                LLDeadBand  = float.Parse(paras[7]);
                LDeadBand   = float.Parse(paras[8]);
                HDeadBand   = float.Parse(paras[9]);
                HHDeadBand  = float.Parse(paras[10]);
                HHHDeadBand = float.Parse(paras[11]);

                if (paras.Length == 13 && paras[12] != "")
                {
                    threshold = float.Parse(paras[12]);
                }
                else
                {
                    threshold = 0;
                }

                //1.1 对各限值进行死区调整
                //超限统计,根据三低限值和三高限值,把值域分成7个限值区域,
                //——0区域代表MinValue<x<=LLL, 1区域代表LLL<x<=LL, 2区域代表LL<x<=L,   3区域代表L<x<=H,    4区域代表H<x<=HH,   5区域代表HH<x<HHH,  6区域代表HHH<x<=MaxValue
                //但是,由于有死区的设定,点进入不同区域时,对应的限值数组需要做调整.x区域的点对应LimitRangeDeadBand[x]。
                //位于不同限值区域的点,要使用不同的限值数组进行下一个点的限值区域判定。
                double[][] LimitRangeDeadBand = new double[7][];
                for (i = 0; i < 7; i++)                         //先用LimitRange去初始化LimitRangeDeadBand
                {
                    LimitRangeDeadBand[i] = new double[6];
                    for (int j = 0; j < 3; j++)
                    {   //在限值上不算越限。由于本算法采用的是排序法,找到点所在的区域。
                        //——当点位于H、HH、HHH的位置时,计算得到的点的区域刚好是想要的结果,即不算越限。
                        //——当点位于L、LL、LLL的位置时,计算得到的点的区域会被认为是算为越界。这不是想要的结果。为了使点在L、LL、LLL位置时不被认为是越界,需要给L、LL、LLL减掉一个极小值。这样在L、LL、LLL边界上的点会返回正确的结果
                        LimitRangeDeadBand[i][j] = LimitRange[j] - 0.00000001;
                    }
                    for (int j = 3; j < 6; j++)
                    {
                        LimitRangeDeadBand[i][j] = LimitRange[j];
                    }
                }
                //当实时值位于LLL区时,当前区域值为currentRange=0,在LLL区内,返回LL时,要求实时值要到LLL+LLLDeadBand之上,才返回有效。返回L时要求实时值到LL+LLDeadBand之上才有效,返回Normal时,要求返回L+LDeadBand才有效。
                //此区域区域值为0,对应的调整死区界限数组为 LimitRangeDeadBand[0],要对LLL、LL、L值做调整
                LimitRangeDeadBand[0][0] = LimitRangeDeadBand[0][0] + LLLDeadBand;
                LimitRangeDeadBand[0][1] = LimitRangeDeadBand[0][1] + LLDeadBand;
                LimitRangeDeadBand[0][2] = LimitRangeDeadBand[0][2] + LDeadBand;
                //当实时值位于LL区时,当前区域值为currentRange=1,在LL区内,返回L时要求实时值到LL+LLDeadBand之上才有效,返回Normal时,要求返回L+LDeadBand才有效。
                //此区域currentRange=1,对应的限值数组 LimitRangeDeadBand[1],要对LL、L值做调整
                LimitRangeDeadBand[1][1] = LimitRangeDeadBand[1][1] + LLDeadBand;
                LimitRangeDeadBand[1][2] = LimitRangeDeadBand[1][2] + LDeadBand;
                //当实时值位于L区时,当前区域值为currentRange=2,在L区内,返回Normal时,要求返回L+LDeadBand才有效。
                //此区域currentRange=2,对应的限值数组 LimitRangeDeadBand[2],要对L值做调整
                LimitRangeDeadBand[2][2] = LimitRangeDeadBand[2][2] + LDeadBand;
                //当实时值位于正常区间时,当前区域值为currentRange=3,所有区域均不调整

                //当实时值位于H区时,当前区域值为currentRange=4,在H区内,返回Normal时,要求返回H-HDeadBand才有效。
                LimitRangeDeadBand[4][3] = LimitRangeDeadBand[4][3] - HDeadBand;
                //当实时值位于HH区时,当前区域值为currentRange=5,在HH区内,返回H时,要求返回HH-HHDeadBand才有效。返回Normal时,要求返回H-HDeadBand才有效。
                LimitRangeDeadBand[5][3] = LimitRangeDeadBand[5][3] - HDeadBand;
                LimitRangeDeadBand[5][4] = LimitRangeDeadBand[5][4] - HHDeadBand;
                //当实时值位于HHH区时,当前区域值为currentRange=6,在HHH区内,返回HH时,要求返回HHH-HHHDeadBand才有效。返回H时,要求返回HH-HHDeadBand才有效。返回Normal时,要求返回H-HDeadBand才有效。
                LimitRangeDeadBand[6][3] = LimitRangeDeadBand[6][3] - HHHDeadBand;
                LimitRangeDeadBand[6][4] = LimitRangeDeadBand[6][4] - HHHDeadBand;
                LimitRangeDeadBand[6][5] = LimitRangeDeadBand[6][5] - HHHDeadBand;


                //2、准备存储变量
                double[]        LimitNumber     = new double[7];         //各限值区域的次数统计
                double[]        LimitSpan       = new double[7];         //各限值区域的时长统计
                double[]        LimitArea       = new double[7];         //各限值区域的面积统计
                double[]        LimitAreaRatio  = new double[7];         //各限值区域的面积统计
                List <PValue>[] LimitSpanSeries = new List <PValue> [7]; //各限值区域的时间序列统计
                for (i = 0; i < 7; i++)
                {
                    LimitSpanSeries[i] = new List <PValue>();
                }

                //3、对数据进行遍历
                int      currentRange  = 10;                //当前点的限值区域
                int      previousRange = 10;                //上一个点的限值区域
                PValue   currentPoint;                      //当前点Pvalue值
                PValue   previousPoint;                     //上一点PValue值
                PValue[] crossPoint = new PValue[6];        //与限值的焦点
                PValue[] transPoint;                        //currentPoint、previousPoint及限值焦点构成的直线
                double[] SortArray   = new double[7];
                double   currentSpan = 0;
                double   currentArea = 0;


                for (int iPoint = 0; iPoint < input.Count; iPoint++)
                {
                    //3.1、判断点的位置是否有变化
                    //3.1.1、计算当前点的所在的限值区域
                    if (iPoint == 0)
                    {
                        //计算第一个点的当前区域。当previousStatus == 10时,是第一个点
                        //计算第一个点的当前区域,采用正常值区域3对应的界限数组来判断第一个点的区域。这样规定算法,是有微小误差的。
                        //误差可能:如果统计周期前面的点,是从[H,HH]落入到[H,H-HDeadBand]内,实际的统计可能会有误差。这个需要在仔细分析
                        LimitRangeDeadBand[3].CopyTo(SortArray, 0);                         //如果是第一个点
                        SortArray[6] = input[iPoint].Value;
                        Array.Sort(SortArray);
                        currentRange  = Array.IndexOf(SortArray, input[iPoint].Value);      //找第一个点的所在的区域,这个相当于在每个区间(L,H]内找
                        previousRange = currentRange;                                       //假定第一个点的前一时刻点的previousRange与currentRange相同
                        currentPoint  = input[iPoint];                                      //获取当前点
                        previousPoint = input[iPoint];                                      //获取上一个点
                        //results[currentRange].Add(new PValue(1, input[iPoint].Timestamp, new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0));
                        LimitSpanSeries[currentRange].Add(new PValue(1, input[iPoint].Timestamp, new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0));
                    }
                    else
                    {
                        //不是第一个点
                        LimitRangeDeadBand[previousRange].CopyTo(SortArray, 0);
                        SortArray[6] = input[iPoint].Value;
                        Array.Sort(SortArray);
                        currentRange  = Array.IndexOf(SortArray, input[iPoint].Value);      //找当前点所在的区域,这个相当于在每个区间(min,max]内找
                        currentPoint  = input[iPoint];                                      //获取当前点
                        previousPoint = input[iPoint - 1];                                  //获取上一个点
                    }

                    //3.1.2、跟当前点所在限值区域与上一个点所在限值区域情况,进行统计
                    if (currentRange == previousRange)
                    {
                        //如果当前点的限值区域没有变化
                        //——则统计时长和面积到对应的previousRange内
                        //——第一个点,currentRange == previousRange,一定走该分支
                        currentSpan = (currentPoint.Timestamp - previousPoint.Timestamp).TotalMilliseconds / 1000;
                        if (currentRange > 3)
                        {
                            currentArea = (Math.Abs(currentPoint.Value - LimitRange[currentRange - 1]) + Math.Abs(previousPoint.Value - LimitRange[currentRange - 1])) * currentSpan / 2;
                        }
                        else if (currentRange < 3)
                        {
                            currentArea = (Math.Abs(currentPoint.Value - LimitRange[currentRange]) + Math.Abs(previousPoint.Value - LimitRange[currentRange])) * currentSpan / 2;
                        }
                        else
                        {
                            currentArea = 0;
                        }
                        //累计时长
                        LimitSpan[previousRange] = LimitSpan[previousRange] + currentSpan; //对于第一个点来说,currentSpan为0
                        //累计面积
                        LimitArea[previousRange] = LimitArea[previousRange] + currentArea; //对于第一个点来说,currentSpan为0
                    }
                    else
                    {
                        //如果当前的点的限值区域有变化,则
                        //——1、则计算交叉点,并和previousPoint、currentPoint构成直线
                        //——2、据直线的端点和交叉点统计时长和面积
                        if (currentRange > previousRange)
                        {
                            //1、求出焦点,并把焦点和previousPoint、currentPoint构成数组
                            transPoint    = new PValue[currentRange - previousRange + 2]; //previousPoint、currentPoint以及和限值的交点构成的直线,共currentRange - previousRange + 2个点
                            transPoint[0] = previousPoint;
                            transPoint[transPoint.Length - 1] = currentPoint;
                            for (i = previousRange; i < currentRange; i++)   //这个循环是求交点,是< currentRange
                            {
                                //两点式:x=((y-y0)*(x1-x0)/(y1-y0))+x0
                                DateTime transcendtimestamp = previousPoint.Timestamp.AddMilliseconds(((LimitRange[i] - previousPoint.Value) * (currentPoint.Timestamp - previousPoint.Timestamp).TotalMilliseconds) / (currentPoint.Value - previousPoint.Value));

                                transPoint[i - previousRange + 1] = new PValue(LimitRange[i], transcendtimestamp, new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0); //得到交点
                                LimitSpanSeries[i][LimitSpanSeries[i].Count - 1].Endtime = transcendtimestamp;                                                               //写上一个range的结束时间
                                LimitSpanSeries[i + 1].Add(new PValue(1, transcendtimestamp, new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0));                     //写当期range的开始时间
                            }
                            //2、根区域跨越的点求累计时长和累计面积
                            for (i = previousRange; i <= currentRange; i++) //这个循环是求每一段累加值,是<= currentRange
                            {
                                //——第一个点,currentRange == previousRange,一定走该分支
                                currentSpan = (transPoint[i - previousRange + 1].Timestamp - transPoint[i - previousRange].Timestamp).TotalMilliseconds / 1000;
                                if (i > 3)
                                {
                                    currentArea = (Math.Abs(transPoint[i - previousRange + 1].Value - LimitRange[i - 1]) + Math.Abs(transPoint[i - previousRange].Value - LimitRange[i - 1])) * currentSpan / 2;
                                }
                                else if (i < 3)
                                {
                                    currentArea = (Math.Abs(transPoint[i - previousRange + 1].Value - LimitRange[i]) + Math.Abs(transPoint[i - previousRange].Value - LimitRange[i])) * currentSpan / 2;
                                }
                                else
                                {
                                    currentArea = 0;
                                }
                                //累计时长
                                LimitSpan[i] = LimitSpan[i] + currentSpan; //对于第一个点来说,currentSpan为0
                                //累计面积
                                LimitArea[i] = LimitArea[i] + currentArea; //对于第一个点来说,currentSpan为0
                            }
                        }
                        else
                        {
                            //1、求出焦点,并把焦点和previousPoint、currentPoint构成数组
                            transPoint    = new PValue[previousRange - currentRange + 2];//previousPoint、currentPoint以及和限值的交点构成的直线,共currentRange - previousRange + 2个点
                            transPoint[0] = previousPoint;
                            transPoint[transPoint.Length - 1] = currentPoint;
                            for (i = previousRange; i > currentRange; i--)  //这个循环是求交点,是> currentRange
                            {
                                //两点式:x=((y-y0)*(x1-x0)/(y1-y0))+x0
                                DateTime transcendtimestamp = previousPoint.Timestamp.AddMilliseconds(((LimitRange[i - 1] - previousPoint.Value) * (currentPoint.Timestamp - previousPoint.Timestamp).TotalMilliseconds) / (currentPoint.Value - previousPoint.Value));

                                transPoint[previousRange - i + 1] = new PValue(LimitRange[i - 1], transcendtimestamp, new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0);
                                LimitSpanSeries[i][LimitSpanSeries[i].Count - 1].Endtime = transcendtimestamp;                                           //写上一个range的结束时间
                                LimitSpanSeries[i - 1].Add(new PValue(1, transcendtimestamp, new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0)); //写当期range的开始时间
                            }
                            //2、根区域跨越的点求累计时长和累计面积
                            for (i = previousRange; i >= currentRange; i--)//这个循环是求每一段累加值,是>= currentRange
                            {
                                //——第一个点,currentRange == previousRange,一定走该分支
                                currentSpan = (transPoint[previousRange - i + 1].Timestamp - transPoint[previousRange - i].Timestamp).TotalSeconds;
                                if (i > 3)
                                {
                                    currentArea = (Math.Abs(transPoint[previousRange - i + 1].Value - LimitRange[i - 1]) + Math.Abs(transPoint[previousRange - i].Value - LimitRange[i - 1])) * currentSpan / 2;
                                }
                                else if (i < 3)
                                {
                                    currentArea = (Math.Abs(transPoint[previousRange - i + 1].Value - LimitRange[i]) + Math.Abs(transPoint[previousRange - i].Value - LimitRange[i])) * currentSpan / 2;
                                }
                                else
                                {
                                    currentArea = 0;
                                }

                                //累计时长
                                LimitSpan[i] = LimitSpan[i] + currentSpan; //对于第一个点来说,currentSpan为0
                                //累计面积
                                LimitArea[i] = LimitArea[i] + currentArea; //对于第一个点来说,currentSpan为0
                            }
                        }


                        //——寻找下降沿或者上升沿统计超限次数
                        //值域分成7个限值区域:0,1,2,3,4,5,6
                        //在3H区域看上升沿,即实时值由低向高值变动
                        if (currentRange > 3 && currentRange > previousRange)
                        {
                            for (i = previousRange; i < currentRange; i++)
                            {
                                if (i >= 3)
                                {
                                    LimitNumber[i + 1] = LimitNumber[i + 1] + 1;
                                }
                            }
                        }
                        //在3L区域看上升沿,即实时值由低值向高值变动
                        else if (currentRange < 3 && currentRange < previousRange)
                        {
                            for (i = previousRange; i > currentRange; i--)
                            {
                                if (i <= 3)
                                {
                                    LimitNumber[i - 1] = LimitNumber[i - 1] + 1;
                                }
                            }
                        }
                        previousRange = currentRange;
                    }
                    //4.2.3 处理结束点
                    if (iPoint == input.Count - 1)
                    {
                        LimitSpanSeries[currentRange][LimitSpanSeries[currentRange].Count - 1].Endtime = currentPoint.Endtime;
                        //目前该算法不处理最后一个点起始值到结束值之间的时间段。这是该算法统计存在误差的原因之一。
                    }
                }//end for

                //计算占比
                if (LimitSpan[1] == 0 || (LimitRange[1] - LimitRange[0]) == 0)
                {
                    LimitAreaRatio[1] = 0;
                }
                else
                {
                    LimitAreaRatio[1] = LimitArea[1] / (LimitSpan[1] * (LimitRange[1] - LimitRange[0]));//LL面积占比
                }
                if (LimitSpan[2] == 0 || (LimitRange[2] - LimitRange[1]) == 0)
                {
                    LimitAreaRatio[2] = 0;
                }
                else
                {
                    LimitAreaRatio[2] = LimitArea[2] / (LimitSpan[2] * (LimitRange[2] - LimitRange[1]));//L面积占比
                }
                if (LimitSpan[4] == 0 || (LimitRange[4] - LimitRange[3]) == 0)
                {
                    LimitAreaRatio[4] = 0;
                }
                else
                {
                    LimitAreaRatio[4] = LimitArea[4] / (LimitSpan[4] * (LimitRange[4] - LimitRange[3]));//H面积占比
                }
                if (LimitSpan[5] == 0 || (LimitRange[5] - LimitRange[4]) == 0)
                {
                    LimitAreaRatio[5] = 0;
                }
                else
                {
                    LimitAreaRatio[5] = LimitArea[5] / (LimitSpan[5] * (LimitRange[5] - LimitRange[4]));//HH面积占比
                }



                //对找出的时间序列进行过滤,如果长度小于threshold,则去掉
                if (threshold > 0)
                {
                    for (i = 0; i < 7; i++)
                    {
                        for (int j = LimitSpanSeries[i].Count - 1; j >= 0; j--)
                        {
                            if (LimitSpanSeries[i][j].Timespan < threshold * 60)
                            {
                                LimitSpanSeries[i].RemoveAt(j);
                            }
                        }
                    }
                }



                //组织计算结果:共返回24个统计结果
                //LLLNumber;LLLSpan;LLLArea;
                //LLNumber;LLSpan;LLArea;;
                //LNumber;LSpan;LArea;;
                //HNumber;HSpan;HArea;;;
                //HHNumber;HHSpan;HHArea;;
                //HHHNumber;HHHSpan;HHHArea;
                //LLAreaRatio,LAreaRatio,HAreaRatio,HHAreaRatio


                results[0][0] = new PValue(LimitNumber[0], calcuInfo.fstarttime, calcuinfo.fendtime, 0);     //LLLNumber

                results[1][0] = new PValue(LimitSpan[0], calcuInfo.fstarttime, calcuinfo.fendtime, 0);       //LLLSpan

                results[2][0] = new PValue(LimitArea[0], calcuInfo.fstarttime, calcuinfo.fendtime, 0);       //LLLArea

                results[3][0] = new PValue(LimitNumber[1], calcuInfo.fstarttime, calcuinfo.fendtime, 0);     //LLNumber

                results[4][0] = new PValue(LimitSpan[1], calcuInfo.fstarttime, calcuinfo.fendtime, 0);       //LLSpan

                results[5][0] = new PValue(LimitArea[1], calcuInfo.fstarttime, calcuinfo.fendtime, 0);       //LLArea

                results[6][0] = new PValue(LimitNumber[2], calcuInfo.fstarttime, calcuinfo.fendtime, 0);     //LNumber

                results[7][0] = new PValue(LimitSpan[2], calcuInfo.fstarttime, calcuinfo.fendtime, 0);       //LSpan

                results[8][0] = new PValue(LimitArea[2], calcuInfo.fstarttime, calcuinfo.fendtime, 0);       //LArea

                results[9][0] = new PValue(LimitNumber[4], calcuInfo.fstarttime, calcuinfo.fendtime, 0);     //HNumber

                results[10][0] = new PValue(LimitSpan[4], calcuInfo.fstarttime, calcuinfo.fendtime, 0);      //HSpan

                results[11][0] = new PValue(LimitArea[4], calcuInfo.fstarttime, calcuinfo.fendtime, 0);      //HArea

                results[12][0] = new PValue(LimitNumber[5], calcuInfo.fstarttime, calcuinfo.fendtime, 0);    //HHNumber

                results[13][0] = new PValue(LimitSpan[5], calcuInfo.fstarttime, calcuinfo.fendtime, 0);      //HHSpan

                results[14][0] = new PValue(LimitArea[5], calcuInfo.fstarttime, calcuinfo.fendtime, 0);      //HHArea

                results[15][0] = new PValue(LimitNumber[6], calcuInfo.fstarttime, calcuinfo.fendtime, 0);    //HHHNumber

                results[16][0] = new PValue(LimitSpan[6], calcuInfo.fstarttime, calcuinfo.fendtime, 0);      //HHHSpan

                results[17][0] = new PValue(LimitArea[6], calcuInfo.fstarttime, calcuinfo.fendtime, 0);      //HHHArea

                results[18][0] = new PValue(LimitAreaRatio[1], calcuInfo.fstarttime, calcuinfo.fendtime, 0); //LLAreaRatio

                results[19][0] = new PValue(LimitAreaRatio[2], calcuInfo.fstarttime, calcuinfo.fendtime, 0); //LAreaRatio

                results[20][0] = new PValue(LimitAreaRatio[4], calcuInfo.fstarttime, calcuinfo.fendtime, 0); //HAreaRatio

                results[21][0] = new PValue(LimitAreaRatio[5], calcuInfo.fstarttime, calcuinfo.fendtime, 0); //HHAreaRatio

                results[22] = LimitSpanSeries[0];                                                            //LLLSeries

                results[23] = LimitSpanSeries[1];                                                            //LLSeries

                results[24] = LimitSpanSeries[2];                                                            //LSeries

                results[25] = LimitSpanSeries[4];                                                            //HSeries

                results[26] = LimitSpanSeries[5];                                                            //HHSeries

                results[27] = LimitSpanSeries[6];                                                            //HHHSeries

                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));
            }
        }
Ejemplo n.º 6
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,则输出项也为空.
            List <PValue>[] results = new List <PValue> [1];
            results[0] = new List <PValue>();
            results[0].Add(new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, (long)StatusConst.InputIsNull));

            try
            {
                //0、输入
                List <PValue> input = new List <PValue>();
                //0.1、输入处理:输入长度。当输入为空时,则输出项也为空.
                if (inputs == null || Array.IndexOf(inputs, null) != -1)
                {
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));        //不报错,直接返回空
                }
                else if (inputs.Length < 2)
                {
                    _errorFlag = true;  //报错
                    _errorInfo = "输入标签必须是两个。";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //0.2、输入处理:截止时刻值。该算法不需要截止时刻点参与计算。
                for (i = 0; i < inputs.Length; i++)
                {
                    if (inputs[i].Count > 1)
                    {
                        inputs[i].RemoveAt(inputs[i].Count - 1);
                    }
                }

                //0.3、输入处理:标志位。该算法考虑标志位不检测标志位
                //for (i = input.Count - 1; i >= 0; i--)
                //{
                //    if (input[i].Status != 0) input.RemoveAt(i);
                //}
                //0.4、输入处理:过滤后结果。
                //——如果去除了截止时刻点,过滤后长度小于1(计算要求至少有一个有效数据),则直接返回null
                //——如果没取除截止时刻点,过滤后长度小于2(计算要求至少有一个有效数据和一个截止时刻值)
                for (i = 0; i < inputs.Length; i++)
                {
                    if (inputs[i].Count < 1)
                    {
                        return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                    }
                }


                //参数处理
                double   k;
                double   b;
                string[] paras = calcuinfo.fparas.Split(';');
                k = float.Parse(paras[0]);
                b = float.Parse(paras[1]);


                //2、合并数组
                List <SpanSeries> spanconcat = new List <SpanSeries>();
                for (i = 0; i < inputs.Length; i++)
                {
                    foreach (PValue pv in inputs[i])
                    {
                        spanconcat.Add(new SpanSeries(pv.Timestamp, i.ToString() + ";" + pv.Value.ToString(), "0"));
                    }
                }

                //3、排序
                spanconcat = spanconcat.OrderBy(m => m.Datetime).ToList();

                //4、
                double[] valueSeries = new double[2];
                valueSeries[0] = 0;
                valueSeries[1] = 0;
                double currentSum = 0;

                DateTime currentDate  = spanconcat[0].Datetime;         //当前计算时间
                DateTime lastDate     = spanconcat[0].Datetime;         //上一次计算时间
                int      currentIndex = 0;                              //当前标志位对应的模拟量序号
                double   currentValue = 0;                              //当前标志位对应的模拟量值

                List <PValue> result = new List <PValue>();
                result.Add(new PValue(currentSum, spanconcat[0].Datetime, new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0));
                for (i = 0; i < spanconcat.Count; i++)
                {
                    //读取当前时间
                    currentDate = spanconcat[i].Datetime;
                    //如果当前时间等于上一次时间,则把统一时间的状态变化依次进行处理,改变flagSeries
                    if (currentDate == lastDate)
                    {
                        //如果当前的时间等于上一次时间,则仅更新flagSeries
                        string[] flags = spanconcat[i].Flag.Split(';');
                        currentIndex = int.Parse(flags[0]);
                        currentValue = double.Parse(flags[1]);
                        valueSeries[currentIndex] = currentValue;
                    }
                    else
                    {//如果当前时间不等于上一次时间,说明上一个时刻的所有状态变化处理完毕,flagSeries以代表上一个时刻最后状态
                        //2.1 写入上次结果
                        //currentSum = valueSeries[0] + valueSeries[1];
                        currentSum = k * (valueSeries[0] + valueSeries[1]) + b;
                        //填写上上时刻点的结束时间
                        result[result.Count - 1].Value   = currentSum;
                        result[result.Count - 1].Endtime = currentDate;                 //不是第一个点,写入上一个数据的值和结束时间。


                        //2.2 更新flagSeries
                        string[] flags = spanconcat[i].Flag.Split(';');
                        currentIndex = int.Parse(flags[0]);
                        currentValue = double.Parse(flags[1]);
                        valueSeries[currentIndex] = currentValue;
                        //currentSum = valueSeries[0] + valueSeries[1];
                        currentSum = k * (valueSeries[0] + valueSeries[1]) + b;
                        //2.3、写入新点的起始时间
                        result.Add(new PValue(0, currentDate, new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0));

                        lastDate = currentDate;
                    }
                }

                //写结束点的末尾:结尾点状态改变不改变已经不重要
                currentSum = k * (valueSeries[0] + valueSeries[1]) + b;
                //Console.WriteLine("系数:" + k + "---b:" + b + " c1:" + valueSeries[0] + "--c2:" + valueSeries[1] + "---res:" + currentSum);
                result[result.Count - 1].Value   = currentSum;
                result[result.Count - 1].Endtime = inputs[0][inputs[0].Count - 1].Endtime;

                //组织计算结果

                results[0] = result;
                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(null, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
            }
        }
Ejemplo n.º 7
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、组织输出
                results = new List <PValue> [5];
                for (i = 0; i < 5; i++)
                {
                    results[i] = new List <PValue>();
                }
                results[0].Add(sp);
                results[1].Add(err);
                results[2].Add(errrate);
                results[3].Add(score);
                results[4].Add(wscore);

                //如果越界标识不为0,还需要给每个结果的状态添加越界的标志。
                if (invalidflag != 0)
                {
                    for (i = 0; i < 5; 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));
            }
        }
Ejemplo n.º 8
0
        public static Results Calcu(List <PValue>[] inputs, CalcuInfo calcuinfo)
        {
            //本计算需要获得限定条件上下限
            //如果限定条件形式为"[20,70]",则lowerLimit=20,upperLimit=70,其含义是要找某标签实时值在20~70范围内的时间段
            //如果限定条件形式为"(20,70)",则lowerLimit=20,upperLimit=70,其含义是要找某标签实时值在20~70范围内的时间段,不包含边界值
            //如果限定条件形式为"[20,]",则lowerLimit=20,upperLimit=MaxValue,其含义是要找某标签实时值大于等于20的时间段
            //如果限定条件形式为"(20,)",则lowerLimit=20,upperLimit=MaxValue,其含义是要找某标签实时值大于20的时间段
            //如果限定条件形式为"[,70]",则lowerLimit=MinValue,upperLimit=70,其含义是要找某标签实时值小于等于70的时间段
            //如果限定条件形式为"(,70)",则lowerLimit=MinValue,upperLimit=70,其含义是要找某标签实时值小于70的时间段
            //公用变量
            bool   _errorFlag   = false;
            string _errorInfo   = "";
            bool   _warningFlag = false;
            string _warningInfo = "";
            bool   _fatalFlag   = false;
            string _fatalInfo   = "";

            int i;

            //List<PValue>[] results = new List<PValue>[4] { spanseries, spansNumber, spansTotal, spansRS };
            //符合限定条件的时间段(毫秒);符合限定条件的次数;符合限定的总时长(毫秒);符合条件与否的数字量
            List <PValue>[] results = new List <PValue> [4];
            results[0] = null;
            results[1] = new List <PValue>();
            results[1].Add(new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0));
            results[2] = new List <PValue>();
            results[2].Add(new PValue(0, calcuinfo.fstarttime, calcuinfo.fendtime, 0));
            results[3] = null;

            try
            {
                //0、输入
                List <PValue> input = new List <PValue>();
                //0.1、输入处理:输入长度。当输入为空时,所有的输出项为0.
                if (inputs == null || inputs.Length == 0 || inputs[0] == null)
                {
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo)); //如果输入为空,则主引擎已经报警
                }
                else
                {
                    input = inputs[0];
                }
                //0.2、输入处理:截止时刻值。该算法采用线性计算,截止时刻点要参与计算。不删除
                if (input.Count > 1)
                {
                    input.RemoveAt(input.Count - 1);
                }
                //0.3、输入处理:标志位。该算法考虑标志位不为0的情况,先过滤这些点。
                for (i = input.Count - 1; i >= 0; i--)
                {
                    if (input[i].Status != 0)
                    {
                        input.RemoveAt(i);
                    }
                    //典型的,比如在指标考核中,当负荷降为0以后,所有的偏差的状态值均为1000。即超出偏差曲线范围。这个过程可能持续1天。
                    //那整个一天的每分钟偏差值,状态位均为1000。
                    //此时,如果对1天的偏差进行超限统计,则输入值均会被过滤掉,过滤完的inputs为null。
                    //应该直接返回头部定义的结果results,并且该result的状态位为StatusConst.InputIsNull
                }
                //0.4、输入处理:过滤后结果。
                //——如果去除了截止时刻点,过滤后长度小于1(计算要求至少有一个有效数据),则直接返回全0
                //——如果没取除截止时刻点,过滤后长度小于2(计算要求至少有一个有效数据和一个截止时刻值)
                if (input.Count < 1)
                {
                    _warningFlag = true;
                    _warningInfo = "对应时间段内的源数据状态位全部异常";
                    return(new Results(results, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
                }

                //1、准备界限数组\和区间边界标识
                double[] LimitRange = new double[4];                        //界限数组,用于查找当前value值处于的值域段
                string   CompareStr = "";                                   //比较符
                int      len        = calcuinfo.fparas.Length;
                string[] paras      = Regex.Split(calcuinfo.fparas, ";|;"); //要测试一下,split分割完仅有三个元素是否可以
                CompareStr    = String.Format("{0}{1}", paras[0].Substring(0, 1), paras[1].Substring(paras[1].Length - 1, 1));
                paras[0]      = paras[0].Substring(1, paras[0].Length - 1); //范围的下边界“(20”中把20取出
                paras[1]      = paras[1].Substring(0, paras[1].Length - 1); //范围的上边界“50)”中把50取出
                LimitRange[0] = float.MinValue;
                LimitRange[3] = float.MaxValue;
                if (paras[0].Trim() == "")
                {
                    LimitRange[1] = float.MinValue;
                }
                else
                {
                    LimitRange[1] = float.Parse(paras[0]);
                }

                if (paras[1].Trim() == "")
                {
                    LimitRange[2] = float.MaxValue;
                }
                else
                {
                    LimitRange[2] = float.Parse(paras[1]);
                }
                //如果输入时,上下限填写反了,则对调
                if (LimitRange[1] > LimitRange[2])
                {
                    double temp = LimitRange[1];
                    LimitRange[1] = LimitRange[2];
                    LimitRange[2] = temp;
                }
                double threshold;
                if (paras.Length >= 3 && paras[2] != "")
                {
                    threshold = float.Parse(paras[2]);
                }
                else
                {
                    threshold = 0;  //如果没有给定threshold值,则取默认值0秒钟
                }
                double delay;
                if (paras.Length >= 4 && paras[3] != "")
                {
                    delay = float.Parse(paras[3]);
                }
                else
                {
                    delay = 0;  //如果没有给定threshold值,则取默认值0秒钟
                }

                //2、准备符合条件的时间段存储变量

                //3、对数据进行遍历
                int             currentRange  = 10;            //当前点是否位于定义区间内
                int             previousRange = 10;            //上一个点是否位于定义区间内
                PValue          currentPoint;                  //当前点
                PValue          previousPoint;                 //上一点
                List <PValue>[] spans = new List <PValue> [3]; //三个值域段的时间段序列
                spans[0] = new List <PValue>();
                spans[1] = new List <PValue>();
                spans[2] = new List <PValue>();

                //4.遍历所有点
                for (int iPoint = 0; iPoint < input.Count; iPoint++)
                {
                    //4.0、选择当前点和上一个点
                    if (iPoint == 0)
                    {
                        currentPoint  = input[iPoint];
                        previousPoint = input[iPoint];
                    }
                    else
                    {
                        currentPoint  = input[iPoint];
                        previousPoint = input[iPoint - 1];
                    }
                    //4.1、判断当前点是否在条件区间内
                    //对于两点的区间判断,采用下面更为高效的判断方式
                    switch (CompareStr)
                    {
                    case "()":
                        if (input[iPoint].Value >= LimitRange[2])
                        {
                            currentRange = 2;
                        }
                        else if (input[iPoint].Value > LimitRange[1] && input[iPoint].Value < LimitRange[2])
                        {
                            currentRange = 1;
                        }
                        else
                        {
                            currentRange = 0;
                        }
                        break;

                    case "[]":
                        if (input[iPoint].Value > LimitRange[2])
                        {
                            currentRange = 2;
                        }
                        else if (input[iPoint].Value >= LimitRange[1] && input[iPoint].Value <= LimitRange[2])
                        {
                            currentRange = 1;
                        }
                        else
                        {
                            currentRange = 0;
                        }
                        break;

                    case "(]":
                        if (input[iPoint].Value > LimitRange[2])
                        {
                            currentRange = 2;
                        }
                        else if (input[iPoint].Value > LimitRange[1] && input[iPoint].Value <= LimitRange[2])
                        {
                            currentRange = 1;
                        }
                        else
                        {
                            currentRange = 0;
                        }
                        break;

                    case "[)":
                        if (input[iPoint].Value >= LimitRange[2])
                        {
                            currentRange = 2;
                        }
                        else if (input[iPoint].Value >= LimitRange[1] && input[iPoint].Value < LimitRange[2])
                        {
                            currentRange = 1;
                        }
                        else
                        {
                            currentRange = 0;
                        }
                        break;

                    default:     //如果以上情况均不是,则按()情况来做。
                        if (input[iPoint].Value >= LimitRange[2])
                        {
                            currentRange = 2;
                        }
                        else if (input[iPoint].Value > LimitRange[1] && input[iPoint].Value < LimitRange[2])
                        {
                            currentRange = 1;
                        }
                        else
                        {
                            currentRange = 0;
                        }
                        break;
                    }//end switch



                    //4.2、判断点的位置(是否位于条件区间内)是否有变化

                    //4.2.1、处理第一个点。当previousStatus == 10时,是第一个点
                    if (previousRange == 10)
                    {
                        previousRange = currentRange;
                        spans[currentRange].Add(new PValue(1, input[iPoint].Timestamp.AddSeconds(delay), new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0));
                    }
                    //4.2.2、处理中间点
                    if (currentRange == previousRange)
                    {
                        //如果当前点的位置没有变化,则什么也不做
                    }
                    else
                    {
                        if (currentRange > previousRange)
                        {
                            for (i = previousRange; i < currentRange; i++)
                            {
                                //两点式:x=((y-y0)*(x1-x0)/(y1-y0))+x0
                                DateTime transcendtimestamp = previousPoint.Timestamp.AddMilliseconds(((LimitRange[i + 1] - previousPoint.Value) * (currentPoint.Timestamp - previousPoint.Timestamp).TotalMilliseconds) / (currentPoint.Value - previousPoint.Value));
                                //写上一个区域的结束值
                                spans[i][spans[i].Count - 1].Endtime = transcendtimestamp.AddSeconds(delay);  //该交点的时间计算,精确到毫秒
                                //写下一个区域的开始值
                                spans[i + 1].Add(new PValue(1, transcendtimestamp.AddSeconds(delay), new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0));
                            }
                        }
                        else
                        {
                            for (i = previousRange; i > currentRange; i--)
                            {
                                //两点式:x=((y-y0)*(x1-x0)/(y1-y0))+x0
                                DateTime transcendtimestamp = previousPoint.Timestamp.AddMilliseconds(((LimitRange[i] - previousPoint.Value) * (currentPoint.Timestamp - previousPoint.Timestamp).TotalMilliseconds) / (currentPoint.Value - previousPoint.Value));
                                //把点加入对应的划分区域
                                //写上一个区域的结束值
                                spans[i][spans[i].Count - 1].Endtime = transcendtimestamp.AddSeconds(delay);
                                //写下一个区域的开始值
                                spans[i - 1].Add(new PValue(1, transcendtimestamp.AddSeconds(delay), new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local), 0));        //下一个区域的开始点
                            }
                        }
                        previousRange = currentRange;
                    }
                    //4.2.3 处理结束点
                    if (iPoint == input.Count - 1)
                    {
                        spans[currentRange][spans[currentRange].Count - 1].Endtime = currentPoint.Endtime.AddSeconds(delay);
                    }
                }//end for

                //5、对找出的时间序列进行过滤,如果长度小于threshold,则去掉
                double spanstotal = 0;
                for (i = spans[1].Count - 1; i >= 0; i--)
                {
                    if (threshold > 0)
                    {
                        if (spans[1][i].Timespan < threshold * 1000)      //注意pvalue中的Timespan记录的是毫秒值
                        {
                            spans[1].RemoveAt(i);
                        }
                    }
                    spans[1][i].Value = spans[1][i].Timespan;              //Timespan是毫秒值,返回的时间序列List<PValue>的值,是每个时间段的毫秒值
                    spanstotal        = spanstotal + spans[1][i].Timespan;
                }

                //6、组织计算结果
                //results[0]对应小于下限的时间段,results[1]对应于下限和上限之间的时间段,results[2]对应于大于上限的时间段
                List <PValue> spanseries = new List <PValue>();
                spanseries = spans[1];
                List <PValue> spansNumber = new List <PValue>();
                spansNumber.Add(new PValue(spans[1].Count, calcuinfo.fstarttime, calcuinfo.fendtime, 0));
                List <PValue> spansTotal = new List <PValue>();
                spansTotal.Add(new PValue(spanstotal, calcuinfo.fstarttime, calcuinfo.fendtime, 0));

                results = new List <PValue>[3] {
                    spanseries, spansNumber, spansTotal
                };

                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(null, _errorFlag, _errorInfo, _warningFlag, _warningInfo, _fatalFlag, _fatalInfo));
            }
        }//end module