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
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)); } }
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)); } }
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)); } }
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)); } }
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)); } }
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)); } }
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