using DevExpress.XtraRichEdit.Model; using IStation.Epanet.Enums; using IStation.Epanet; using IStation.Model; using IStation.WinFrmUI; using System.Runtime; using System.Text; using IStation.Untity; namespace IStation.Test { public class CorrectedStationScheduleModelHelper { private static int _ratedFrequency = 50; /// /// 数据预处理 /// public static void StationDataPreproc( Dictionary pumpScheduleDict, List allStationRunRecordList, List stationModelMappingList, List pumpModelMappingList, string modelFile ) { // 先过滤一波数据再传进来 if (VerifyNull(pumpScheduleDict)) { return; } if (VerifyNull(allStationRunRecordList)) { return; } var temp_id_build = new StringBuilder(31); var code = EpanetMethods.ENopen(modelFile, "", ""); CheckCode(code); code = EpanetMethods.ENopenH(); if ((int)code > 6) { throw new Exception($"ENopenH:{code}"); } var curvePointCount = 100; foreach (var mapping in pumpModelMappingList) { var flag = mapping.Flag; var pumpSchedule = pumpScheduleDict[flag]; code = EpanetMethods.ENgetlinkindex(mapping.PumpId, out int pumpIndex); CheckCode(code); if (!string.IsNullOrEmpty(mapping.FlowId)) { code = EpanetMethods.ENgetlinkindex(mapping.FlowId, out int flowIndex); CheckCode(code); mapping.FlowIndex = flowIndex; } code = EpanetMethods.ENgetnodeindex(mapping.PressureId, out int pressureIndex); CheckCode(code); code = EpanetMethods.ENgetcurveindex(mapping.CurveId, out int curveIndex); CheckCode(code); mapping.PumpIndex = pumpIndex; mapping.PressureIndex = pressureIndex; mapping.CurveIndex = curveIndex; var curveQH = pumpSchedule.CurveQH; var fitPtList = curveQH.GetFitPoints(curvePointCount); var xList = fitPtList.Select(x => (float)x.X).ToArray(); var yList = fitPtList.Select(x => (float)x.Y).ToArray(); if (!CheckFitPointList(xList, yList)) { throw new Exception($"CheckFitPointList: false"); } code = EpanetMethods.ENsetcurve(mapping.CurveIndex, xList, yList, xList.Length); CheckCode(code); } foreach (var mapping in stationModelMappingList) { code = EpanetMethods.ENgetlinkindex(mapping.FlowId, out int flowIndex); CheckCode(code); code = EpanetMethods.ENgetnodeindex(mapping.PressureId, out int pressureIndex); CheckCode(code); mapping.PressureIndex = pressureIndex; mapping.FlowIndex = flowIndex; } var pumpModelMappingDict = pumpModelMappingList.ToDictionary(x => x.Flag, y => y); var pattern_id_list = AnalysisHelper.GetPatternIdList(); var pattern_id_dict = new Dictionary(); foreach (var id in pattern_id_list) { if (EpanetMethods.ENgetpatternindex(id, out int index) != ErrorCode.Ok) continue; pattern_id_dict.Add(id, index); } var vm_list = new List(); var vm_diff_list = new List(); foreach (var station_record in allStationRecordList) { var model_record_dict = station_record.ModelRecordDict; var pipe_flow_err = true; var pipe_pressure_err = true; foreach (var id in pipeFlowIdList) { if (model_record_dict[id] < 1) { pipe_flow_err = false; break; } } foreach (var id in pipePressureIdList) { var value = model_record_dict[id]; if (value < 1 || value > 40) { pipe_pressure_err = false; break; } } if (!pipe_flow_err || !pipe_pressure_err) { continue; } var time = station_record.Time.ToString("G"); var pump_allStationRecordList = station_record.PumpSignalRecords; var total_flow = station_record.TotalFlow; var total_pressure = station_record.TotalPressure; var pump_total_flow = pump_allStationRecordList.Sum(x => x.FlowRate); var diff_flow = station_record.DiffFlow; if (total_pressure < 0) { continue; } if (total_flow <= 0 && pump_total_flow <= 0) { continue; } if (pump_total_flow > 0 && Math.Abs(diff_flow) > 2000) { continue; } if (pump_allStationRecordList.Exists(x => x.Flag != 15 && x.Flag != 16 && x.Rpm < 1)) { continue; } if (pump_allStationRecordList.Exists(x => x.OutletPressure > 50)) { continue; } foreach (var pattern in pattern_id_dict) { var pattern_id = pattern.Key; var pattern_index = pattern.Value; var pattern_value = 0f; if (model_record_dict.ContainsKey(pattern_id)) { pattern_value = (float)model_record_dict[pattern_id]; } code = EpanetMethods.ENsetpattern(pattern_index, new float[] { pattern_value }, 1); if ((int)code > 6) { throw new Exception($"ENsetpattern:{code}"); } } code = EpanetMethods.ENinitH(0); if ((int)code > 6) { throw new Exception($"ENinitH:{code}"); } code = EpanetMethods.ENrunH(out _); if ((int)code > 6) { throw new Exception($"ENrunH:{code}"); } foreach (var pump_record in pump_allStationRecordList) { var flag = pump_record.Flag; var pump = flagPumpDict[flag]; var qh = flagQhCurveDict[flag]; var mapping = pumpModelMappingDict[flag]; var rpm = pump_record.Rpm; if (!pump.IsBp) rpm = pump.Nr; if (rpm == 0) break; var hz = Math.Round(rpm / pump.Nr * 50, 2); var hz0 = Math.Round(hz, 0); var wl = pump_record.WaterLevel; var inlet_pressure = Model.CurveCalcuHelper.Mpa2M(pump_record.InletPressure); var outlet_pressure = Model.CurveCalcuHelper.Mpa2M(pump_record.OutletPressure); var pressure_diff = outlet_pressure - inlet_pressure; var flow = pump_record.FlowRate; var curve_head = pump_record.Head; code = EpanetMethods.ENgetlinkvalue(mapping.PumpIndex, LinkValue.Flow, out float model_flow); if ((int)code > 6) { throw new Exception($"ENgetnodevalue:{code}"); } if (Math.Abs(model_flow) < 1) { break; } code = EpanetMethods.ENgetnodevalue(mapping.PressureIndex, NodeValue.Pressure, out float model_outlet_pressure); if ((int)code > 6) { throw new Exception($"ENgetnodevalue:{code}"); } if (Math.Abs(model_outlet_pressure) > 45) { break; } model_flow = Math.Abs(model_flow); model_outlet_pressure = Math.Abs(model_outlet_pressure); var model_pressure_diff = model_outlet_pressure - inlet_pressure; var flow_diff = flow - model_flow; var vm = new PumpViewModel(); vm.Time = time; vm.Rpm = rpm; vm.Flag = flag; vm.Hz = hz; vm.Hz0 = hz0; vm.WaterLevel = wl; vm.InletPressure = Math.Round(inlet_pressure, 2); vm.OutletPressure = Math.Round(outlet_pressure, 2); vm.PressureDiff = Math.Round(pressure_diff, 2); vm.Flow = Math.Round(flow, 1); vm.ModelFlow = Math.Round(model_flow, 1); vm.ModelOutletPressure = Math.Round(model_outlet_pressure, 2); vm.CurvePressureDiff = Math.Round(model_pressure_diff, 2); vm.PressureDiffDev = Math.Round(pressure_diff - model_pressure_diff, 3); vm.FlowDiff = Math.Round(flow_diff, 1); var other_press = 0d; if (pump.IsBp) { other_press = Model.CurveCalcuHelper.CalculateOtherPress(model_flow, pump.Ic, pump.Oc, null, null); } var other_outlet = other_press + pressure_diff; var mdoel_other_outlet = other_press + model_pressure_diff; var diff = pressure_diff - model_pressure_diff; if (diff > 0.1) { } var calcHead = other_outlet + vm.PressureDiffDev; vm.CalcHead = Math.Round(mdoel_other_outlet, 2); vm_list.Add(vm); } foreach (var mapping in model_mapping_list) { if (!model_record_dict.ContainsKey(mapping.ScadaPressureId)) { continue; } if (!model_record_dict.ContainsKey(mapping.ScadaFlowId)) { continue; } var flow = model_record_dict[mapping.ScadaFlowId]; var outlet_pressure = model_record_dict[mapping.ScadaPressureId]; code = EpanetMethods.ENgetlinkvalue(mapping.FlowIndex, LinkValue.Flow, out float model_flow); if ((int)code > 6) { throw new Exception($"ENgetnodevalue:{code}"); } code = EpanetMethods.ENgetnodevalue(mapping.PressureIndex, NodeValue.Pressure, out float model_outlet_pressure); if ((int)code > 6) { throw new Exception($"ENgetnodevalue:{code}"); } var flow_diff = flow - model_flow; var pressure_diff = outlet_pressure - model_outlet_pressure; var vm = new ModelDiffViewModel(); vm.Date = station_record.Time; vm.Time = time; vm.Name = mapping.Name; vm.ScadaFlow = Math.Round(flow, 1); vm.ScadaPressure = Math.Round(outlet_pressure, 3); vm.MonitorFlow = Math.Round(model_flow, 1); vm.MonitorPressure = Math.Round(model_outlet_pressure, 3); vm.FlowDiff = Math.Round(flow_diff, 1); vm.PressureDiff = Math.Round(pressure_diff, 3); vm_diff_list.Add(vm); } } code = EpanetMethods.ENcloseH(); if ((int)code > 6) { throw new Exception($"ENcloseH:{code}"); } code = EpanetMethods.ENclose(); if ((int)code > 6) { throw new Exception($"ENclose:{code}"); } if (!vm_list.Any()) { return; } var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "pumpcsv"); var allPumpRecordList2 = vm_list.Where(x => { if (x.Rpm == IStation.Error.Default) { return false; } return true; }).ToList(); var pumpFlagRecordGroup = allPumpRecordList2.OrderBy(x => x.Flag).GroupBy(x => x.Flag); var pumpFlagHzRecordGroup = new Dictionary<(int Flag, int Hz), List>(); foreach (var pumpFlag in pumpFlagRecordGroup) { var flag = pumpFlag.Key; var pump = flagPumpDict[flag]; var pumpQh = flagQhCurveDict[flag]; if (!pump.IsBp) { var allFlagHzRecordList = pumpFlag.ToList(); if (allFlagHzRecordList.Count < 30) { Console.WriteLine($"{flag}泵-{50}hz 总数:{allFlagHzRecordList.Count},<5 跳过"); } var flagHzRecordList = DynamicThresholdProcessorHelper.Filter(allFlagHzRecordList); Console.WriteLine($"{flag}泵-{50}hz 总数:{allFlagHzRecordList.Count},过滤:{allFlagHzRecordList.Count - flagHzRecordList.Count}"); pumpFlagHzRecordGroup.Add((flag, 50), flagHzRecordList); if (flagHzRecordList.Any()) { var curvePtList = pumpQh.GetFitPoints(200).Select(x => new CurvePtViewModel(x)).ToList(); CsvHelper.ExportToCsv(curvePtList, Path.Combine(fullPath, $"{flag}_{50}_old_curve.csv")); CsvHelper.ExportToCsv(flagHzRecordList.Select(x => new CurvePtViewModel(x.ModelFlow, x.CalcHead)).ToList(), Path.Combine(fullPath, $"{flag}_{50}.csv")); } } else { var hzGroup = pumpFlag.OrderBy(x => x.Rpm).GroupBy(x => { var hz = Math.Round(x.Rpm / pump.Nr * 50, 0); return hz; }); hzGroup = hzGroup.Where(x => x.Key > 10).ToList(); foreach (var pumpFlagHz in hzGroup) { var hz = pumpFlagHz.Key; if (hz > 50) { continue; } var allFlagHzRecordList = pumpFlagHz.ToList(); if (allFlagHzRecordList.Count < 30) { Console.WriteLine($"{flag}泵-{hz}hz 总数:{allFlagHzRecordList.Count},<5 跳过"); } var flagHzRecordList = DynamicThresholdProcessorHelper.Filter(allFlagHzRecordList); if (allFlagHzRecordList.Count < 30) { Console.WriteLine($"{flag}泵-{hz}hz 过滤后总数:{allFlagHzRecordList.Count},<5 跳过"); } Console.WriteLine($"{flag}泵-{hz}hz 总数:{allFlagHzRecordList.Count},过滤:{allFlagHzRecordList.Count - flagHzRecordList.Count}"); pumpFlagHzRecordGroup.Add((flag, (int)hz), flagHzRecordList); if (flagHzRecordList.Any()) { var curvePtList = SimilarCalculateHelper.CalculateQH(pumpQh, 50, hz).GetFitPoints(100); CsvHelper.ExportToCsv(curvePtList.Select(x => new CurvePtViewModel(x)).ToList(), Path.Combine(fullPath, $"{flag}_{hz}_old_curve.csv")); CsvHelper.ExportToCsv(flagHzRecordList.Select(x => new CurvePtViewModel(x.ModelFlow, x.CalcHead)).ToList(), Path.Combine(fullPath, $"{flag}_{hz}.csv")); } } } } GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(2, GCCollectionMode.Forced); GC.WaitForFullGCComplete(); } /// /// 数据预处理 /// public static void PumpDataPreproc( Dictionary pumpScheduleDict, List allPumpRunRecordList ) { // 先过滤一波数据再传进来 if (VerifyNull(pumpScheduleDict)) { return; } if (VerifyNull(allPumpRunRecordList)) { return; } var pumpRunRecordGroupByFlag = allPumpRunRecordList.GroupBy(x => x.Flag); foreach (var flagGroup in pumpRunRecordGroupByFlag) { var flag = flagGroup.Key; var pump = pumpScheduleDict[flag]; var pumpRunRecordGroupByHz = new Dictionary>(); var tempPumpRunRecordList = flagGroup.ToList(); if (pump.IsVariableFrequency) { var validList = FilterHead(tempPumpRunRecordList); pumpRunRecordGroupByHz.Add(50, validList); } else { var tempHzGroup = tempPumpRunRecordList.OrderBy(x => x.Rpm).GroupBy(x => { return (int)Math.Round(x.Rpm / pump.RatedSpeed * _ratedFrequency, 0); }); foreach (var hzGroup in tempHzGroup) { var hz = hzGroup.Key; var tempFilterList = FilterHead(hzGroup); pumpRunRecordGroupByHz.Add(hz, tempFilterList); } } foreach (var hzGroup in pumpRunRecordGroupByHz) { var hz = hzGroup.Key; var similarCurveQH = SimilarCalculateHelper.CalculateQH(pump.CurveQH, _ratedFrequency, hz); var curveQHPtList = similarCurveQH.GetFitPoints(100); //CsvHelper.ExportToCsv(curvePtList.Select(x => new CurvePtViewModel(x)).ToList(), Path.Combine(fullPath, $"{flag}_{hz}_old_curve.csv")); //CsvHelper.ExportToCsv(flagHzRecordList.Select(x => new CurvePtViewModel(x.FlowRate, x.Head)), Path.Combine(fullPath, $"{flag}_{hz}.csv")); } } } public static List FilterHead(IEnumerable list) { var pressures = list.Select(p => p.Head).ToList(); // 计算统计量 var (mean, stdDev) = DynamicThresholdProcessorHelper.CalculateStats(pressures); double skewness = DynamicThresholdProcessorHelper.CalculateSkewness(pressures); // 动态调整σ倍数 double sigmaMultiplier = DynamicThresholdProcessorHelper.CalculateSigmaMultiplier(skewness); // var sigmaMultiplier = 3;//目前默认 标准差 // 计算边界 double lower = mean - sigmaMultiplier * stdDev; double upper = mean + sigmaMultiplier * stdDev; return list.Where(p => p.Head >= lower && p.Head <= upper).ToList(); } static bool CheckFitPointList(float[] x, float[] y) { bool is_x_increasing = CheckIncreasing(x); bool is_y_decreasing = CheckDecreasing(y); if (!is_x_increasing) { Console.WriteLine("x不满足递增趋势"); return false; } if (!is_y_decreasing) { Console.WriteLine("y不满足递减趋势"); return false; } return true; }   static bool CheckIncreasing(float[] values) { for (int i = 1; i < values.Length; i++) { if (values[i] < values[i - 1]) { return false; } } return true; } static bool CheckDecreasing(float[] values) { for (int i = 1; i < values.Length; i++) { if (values[i] > values[i - 1]) { return false; } } return true; } private static bool VerifyNull(IEnumerable objs) { if (objs == null || !objs.Any()) { return true; } return false; } private static bool VerifyNull(Dictionary objs) { if (objs == null || !objs.Any()) { return true; } return false; } private static void CheckCode(ErrorCode code) { if (code != ErrorCode.Ok) { if ((int)code > 100) { var msg = code.GetDisplayText(); throw new Exception(msg); } } } public class PumpModelMapping { public int Flag { get; set; } public string PumpId { get; set; } public string FlowId { get; set; } public string PressureId { get; set; } public string CurveId { get; set; } public int PumpIndex { get; set; } public int FlowIndex { get; set; } public int PressureIndex { get; set; } public int CurveIndex { get; set; } } public class StationModelMapping { public string ScadaFlowId { get; set; } public string ScadaPressureId { get; set; } public string FlowId { get; set; } public string PressureId { get; set; } public int FlowIndex { get; set; } public int PressureIndex { get; set; } } } }