ningshuxia
2025-04-16 ed113213fc94c3d9886ea08dfddd09d08d9ba7d5
调度代码修正
已重命名1个文件
已修改13个文件
已添加2个文件
628 ■■■■ 文件已修改
01-api/Service/IStation.Service/05-service/01-analysis/AnalysisParameter.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/Service/IStation.Service/07-helper/01-analysis/AnalysisHelper.cs 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/Service/IStation.Service/07-helper/02-schedule/ScheduleHelper.cs 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/_Expand/IStation.Init/IStation.Init.csproj 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/_Expand/IStation.Init/Program.cs 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/_Expand/IStation.Win.Schedule/Core/Alert/AlertTool.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/_Expand/IStation.Win.Schedule/Properties/Resources.Designer.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/_Expand/IStation.Win.Schedule/Properties/Resources.resx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/_Expand/IStation.Win.Schedule/Resources/number.svg 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/_Expand/IStation.Win.Schedule/bjMain.Designer.cs 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/_Expand/IStation.Win.Schedule/bjMain.cs 73 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
02-desktop/Desktop/IStation.Test/IStation.Test.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
02-desktop/Desktop/IStation.Test/Program.cs 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
02-desktop/Desktop/IStation.Test/Station2TotalFlowDiffHelper.cs 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
02-desktop/Desktop/IStation.Test/TotalFlowDiffHelper - 复制.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
02-desktop/Desktop/IStation.Test/helper/DynamicThresholdProcessorHelper.cs 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
01-api/Service/IStation.Service/05-service/01-analysis/AnalysisParameter.cs
@@ -55,7 +55,7 @@
            var dict = GetDictCache();
            if (!dict.ContainsKey(tableName))
                return default;
            for (int i = 0; i < 3; i++)
            {
                pressure_diff += i * 0.1;
@@ -63,10 +63,6 @@
                   .Where(x => x.PressureDiff == pressure_diff)
                   .OrderBy(x => x.Power)
                   .ToList();
                if (list==null ||  !list.Any())
                {
                }
                if (list != null && list.Any())
                {
                    return list;
01-api/Service/IStation.Service/07-helper/01-analysis/AnalysisHelper.cs
@@ -11,7 +11,7 @@
        private readonly decimal _frequency_def = 50m;
        private readonly decimal _frequency_min = 25m;
        private readonly decimal _frequency_max = 50m;
        private readonly decimal _frequency_space = 0.2m;//频率间隔
        private readonly decimal _frequency_space = 0.1m;//频率间隔
        private readonly decimal _head_space = 0.1m;//扬程间隔
        private readonly DAL.SQLite.AnalysisPump _dal_analysis_pump = new();
@@ -260,18 +260,36 @@
                    continue;
                }
                var qhHzCurve = hzCurveDict[hz];
                for (decimal j = 1; j >= 0; j -= fre_space)
                if (pump.IsBp)
                {
                    var fre = hz - j;
                    var qh = IStation.Curve.FitHelper.BuildCurveExpress(qhHzCurve);
                    var qp = pump.CurveQP;
                    for (decimal j = 0; j <= 0.9m; j += fre_space)
                    {
                        var fre = hz - j;
                        var qp = Curve.PumpCalculateHelper.CalculateSimilarQP(pump.CurveQP, (double)fre_def, (double)fre);
                        var qh = IStation.Curve.FitHelper.BuildCurveExpress(qhHzCurve);
                        //var qh2 = qh.GetFitPointsByXRange(pump.CurveQP.Min, pump.CurveQP.Max);
                        //var qh3 = IStation.Curve.FitHelper.BuildCurveExpress(qh2);
                        var freItem = new AnaPumpFreItem();
                        freItem.Frequency = (double)fre;
                        freItem.CurveQH = Curve.PumpCalculateHelper.CalculateSimilarQH(qh, (double)hz, (double)fre);
                        freItem.CurveQP = qp;
                        list.Add(freItem);
                    }
                }
                else
                {
                    var qh = IStation.Curve.FitHelper.BuildCurveExpress(qhHzCurve);
                    var qh2 = qh.GetFitPointsByXRange(pump.CurveQP.Min, pump.CurveQP.Max);
                    var qh3 = IStation.Curve.FitHelper.BuildCurveExpress(qh2);
                    var qp = pump.CurveQP;
                    var freItem = new AnaPumpFreItem();
                    freItem.Frequency = (double)fre;
                    freItem.CurveQH = Curve.PumpCalculateHelper.CalculateSimilarQH(qh, (double)hz, (double)fre);
                    freItem.CurveQP = Curve.PumpCalculateHelper.CalculateSimilarQP(qp, (double)fre_def, (double)fre);
                    freItem.Frequency = 50;
                    freItem.CurveQH = qh3;
                    freItem.CurveQP = qp;
                    list.Add(freItem);
                }
            } 
01-api/Service/IStation.Service/07-helper/02-schedule/ScheduleHelper.cs
@@ -33,9 +33,7 @@
        private double _sel_opt_flow_deviation_ratio = 0.05;//可选方案的流量偏差比
        private readonly double _sel_opt_reasonable_flow_deviation_ratio = 0.005;//合理的方案的流量偏差比
        private readonly Service.AnalysisParameter _service_analysis_parameter = new();
        private readonly Service.AnalysisDeviation _service_analysis_deviation = new();
        private readonly Service.AnalysisFactor _service_analysis_factor = new();
        private readonly Service.AnalysisParameter _service_analysis_parameter = new();
        private int _min_open_count;//最小开泵数量
        private int _max_open_count;//最大开泵数量
@@ -522,7 +520,8 @@
                //组合偏差系数
                var combine_deviation_factor = combine_deviation_factor_dict[flag];
                var current_pressure_diff = target_pressure - inlet_water_level + combine_deviation_factor + _sel_opt_pump_pressure_excess;
                var current_pressure_diff = target_pressure - inlet_water_level - combine_deviation_factor + _sel_opt_pump_pressure_excess;
                current_pressure_diff = Math.Round(current_pressure_diff, 1);
                //频率限制
@@ -550,7 +549,8 @@
                        }
                        else
                        {
                            conclusion_list = new List<Model.AnalysisParameter>() { min_pressure_diff_conclusion };
                            var list = _service_analysis_parameter.GetList(run_flag);
                            conclusion_list = _service_analysis_parameter.GetList(run_flag, current_pressure_diff);
                        }
                    }
                }
@@ -571,22 +571,11 @@
            {
                if (GlobalHelper.IsStation1(combine))
                {
                    _sel_opt_flow_excess = 0.995;
                    _sel_opt_flow_excess = 0.97;
                }
                else
                {
                    //人为修正
                    if (combine.Count() < 3)
                    {
                        _sel_opt_flow_excess = 0.92;
                        _sel_opt_flow_deviation_ratio = 0.08;
                    }
                }
                var flow_excess = target_flow * _sel_opt_flow_excess;
                if (max_supply_flow < flow_excess)
                    return default;
            }
            var opt_ana_combine = GetOptAnaCombine(conclusion_ex_list_dict, pump_nr_dict, pump_bp_dict, target_flow);
@@ -727,7 +716,7 @@
            }
            if (!ana_combine_list.Any())
                return default;
            var opt_ana_combine = ana_combine_list.OrderBy(x => x.TotalPower).First();
            var opt_ana_combine = ana_combine_list.OrderBy(x=>x.TotalFlow).OrderBy(x => x.TotalPower).First();
            return opt_ana_combine;
        }
@@ -1072,109 +1061,7 @@
            return ana_fre_pump_list;
        }
        /// <summary>
        /// èŽ·å–å˜é¢‘æ³µåˆ—è¡¨ æ ¹æ®å·¥å†µè®¡ç®—
        /// </summary>
        /// <param name="pumps"></param>
        /// <param name="flag_rpm_dic"></param>
        /// <param name="flag_inlet_water_level_dict"></param>
        /// <param name="flag_flow_dic"></param>
        /// <param name="flag_head_dic"></param>
        /// <param name="flag_curve_head_dic"></param>
        /// <param name="total_flow"></param>
        /// <param name="ues_deviation_factor"></param>
        /// <returns></returns>
        public List<AnaFrePump> GetAnaFrePumpListByWorking(
            List<Model.Pump> pumps,
            Dictionary<int, double> flag_rpm_dic,
            Dictionary<int, double> flag_inlet_water_level_dict,
            Dictionary<int, double> flag_flow_dic,
            Dictionary<int, double> flag_head_dic,
            double total_flow,
            out Dictionary<int, double> flag_curve_head_dic,
            bool ues_deviation_factor = false
            )
        {
            flag_curve_head_dic = new Dictionary<int, double>();
            if (pumps == null || !pumps.Any())
            {
                return default;
            }
            if (flag_rpm_dic == null || !flag_rpm_dic.Any())
            {
                return default;
            }
            var run_flag_list = flag_rpm_dic.Where(x => x.Value > 1).Select(x => x.Key).OrderBy(x => x).ToList();
            var ana_fre_pump_list = new List<AnaFrePump>();
            foreach (var flag in run_flag_list)
            {
                var pump = pumps.Find(x => x.Flag == flag);
                if (pump == null)
                    continue;
                var rpm = flag_rpm_dic[flag];
                if (rpm < 1)
                    continue;
                var hz = Math.Round(rpm / pump.Nr * 50, 1);
                var CurveQH50 = pump.CurveQH;
                var CurveQP50 = pump.CurveQP;
                var curveQH = Curve.PumpCalculateHelper.CalculateSimilarQH(CurveQH50, pump.Nr, rpm);
                var curveQP = Curve.PumpCalculateHelper.CalculateSimilarQP(CurveQP50, pump.Nr, rpm);
                double flow = 0, head = 0;
                if (flag_head_dic != null && flag_head_dic.ContainsKey(pump.Flag))
                {
                    head = flag_head_dic[pump.Flag];
                }
                if (flag_inlet_water_level_dict != null && flag_inlet_water_level_dict.ContainsKey(pump.Flag))
                {
                    head -= flag_inlet_water_level_dict[pump.Flag];
                }
                if (ues_deviation_factor)
                {
                    //var combine_deviation_factor_dict = GetCombineDeviationFactorDict(total_flow, run_flag_list);//修正组合曲线和模型的偏差扬程
                    //if (combine_deviation_factor_dict != null && combine_deviation_factor_dict.ContainsKey(flag))
                    //{
                    //    var combine_deviation_factor = combine_deviation_factor_dict[flag];  //组合偏差系数
                    //    head -= combine_deviation_factor;
                    //}
                }
                flow = curveQH.GetInterPointLastX(head) ?? 0;
                if (flow < 0)
                    continue;
                var working_flow = flag_flow_dic[flag];
                flag_curve_head_dic[flag] = curveQH.GetFitPointY(working_flow);
                var fre_pump = new AnaFrePump();
                fre_pump.Flag = flag;
                fre_pump.Flow = flow;
                fre_pump.Head = head;
                fre_pump.Power = curveQP.GetFitPointY(flow);
                fre_pump.PressureDiff = head - Curve.PumpCalculateHelper.CalculateOtherPress(flow, pump.Ic, pump.Oc, null, null);
                fre_pump.Eff = Curve.PumpCalculateHelper.CalculateE(fre_pump.Flow, fre_pump.Head, fre_pump.Power);
                fre_pump.Frequency = rpm / pump.Nr * 50;
                fre_pump.Speed = rpm;
                ana_fre_pump_list.Add(fre_pump);
            }
            return ana_fre_pump_list;
        }
        #endregion  
    }
01-api/_Expand/IStation.Init/IStation.Init.csproj
@@ -27,9 +27,6 @@
    <None Update="Data\AnalysisDeviation.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="Data\AnalysisFactor.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="Data\ScheduleConfig.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
01-api/_Expand/IStation.Init/Program.cs
@@ -1,12 +1,17 @@
// See https://aka.ms/new-console-template for more information
using IStation.Curve;
using System.Reflection;
using System.Text;
Console.WriteLine("是否初始化数据库?(y)");
var str = Console.ReadLine();
if (str != "y")
    return;
if (File.Exists(IStation.Settings.ParasHelper.LocalFile.DataFolderDirectory + "\\analysis.db"))
{
    File.Delete(IStation.Settings.ParasHelper.LocalFile.DataFolderDirectory + "\\analysis.db");
}
IStation.Settings.ParasHelper.DataBase.SQLite.AnalysisConnectString ="DataSource="+ IStation.Settings.ParasHelper.LocalFile.DataFolderDirectory+ "\\analysis.db";
//IStation.Settings.ParasHelper.DataBase.SQLite.ScheduleConnectString = "DataSource=" + IStation.Settings.ParasHelper.LocalFile.DataFolderDirectory+ "\\schedule.db";
//IStation.Settings.ParasHelper.DataBase.SQLite.HydraulicConnectString = "DataSource=" + IStation.Settings.ParasHelper.LocalFile.DataFolderDirectory+ "\\hydraulic.db";
@@ -23,12 +28,210 @@
all_pump_list.AddRange(station.Station1);
all_pump_list.AddRange(station.Station2);
 
var flagHzCurveDict = GetFlagHzCurveDict();
var helper = new IStation.Service.AnalysisHelper();
helper.AnalysisNew(all_pump_list, ana_factor_list);
helper.AnalysisNew(all_pump_list, flagHzCurveDict);
helper.AnalysisParameter(all_pump_list);
Console.WriteLine("Analysis is ok");
Console.WriteLine("OK"); 
Console.ReadKey();
Console.ReadKey();
  static Dictionary<int, Dictionary<int, List<CurvePoint>>> GetFlagHzCurveDict()
{
    var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "pumpcsv");
    var fileNameList = Directory.GetFiles(fullPath).Select(x => Path.GetFileNameWithoutExtension(x)).ToList();
    if (fileNameList == null || fileNameList.Count < 1)
    {
        return new Dictionary<int, Dictionary<int, List<CurvePoint>>>();
    }
    var dict = new Dictionary<int, Dictionary<int, List<CurvePoint>>>();
    var group = fileNameList.Where(x => x.Contains("_update_curve")).GroupBy(x => x.Substring(0, 2));
    foreach (var flagItem in group)
    {
        var flag = int.Parse(flagItem.Key);
        var files = flagItem.OrderBy(x => x).ToList();
        var fileInfoList = new List<(int Hz, string FileName)>();
        dict[flag] = new Dictionary<int, List<CurvePoint>>();
        foreach (var fileName in files)
        {
            var hz = int.Parse(fileName.Substring(3, 2));
            if (hz > 50)
            {
                continue;
            }
            fileInfoList.Add((hz, fileName));
        }
        foreach (var item in fileInfoList)
        {
            var updateCurvePtList = new List<CurvePoint>();
            var updateCurveFile = Path.Combine(fullPath, $"{item.FileName}.csv");
            var hz = item.Hz;
            using (var fs = new FileStream(updateCurveFile, FileMode.Open, FileAccess.Read))
            using (var sr = new StreamReader(fs, Encoding.UTF8))
            {
                var strLine = string.Empty;
                sr.ReadLine();
                while (!string.IsNullOrEmpty(strLine = sr.ReadLine()))
                {
                    var strList = strLine.Split(',');
                    var x = double.Parse(strList[0]);
                    var y = double.Parse(strList[1]);
                    updateCurvePtList.Add(new CurvePoint(x, y));
                }
                var x_values = updateCurvePtList.Select(x => (float)x.X).ToArray();
                var y_values = updateCurvePtList.Select(x => (float)x.Y).ToArray();
                if (!CheckFitPointList(x_values, y_values))
                {
                    var (newX, newY) = UpdateFitPointList(x_values, y_values);
                    if (newX.Length < x_values.Length / 2)
                    {
                        throw new Exception($"{item.FileName}数据异常");
                    }
                    updateCurvePtList = new List<CurvePoint>();
                    for (int i = 0; i < newX.Length; i++)
                    {
                        var x = newX[i];
                        var y = newY[i];
                        updateCurvePtList.Add(new CurvePoint(x, y));
                    }
                }
            }
            dict[flag][item.Hz] = updateCurvePtList;
        }
    }
    return dict;
}
/// <summary>
/// è®¡ç®—相似流量扬程曲线
/// </summary>
/// <param name="express">表达式</param>
/// <param name="originHz">原始频率</param>
/// <param name="changeHz">换算频率</param>
/// <param name="pointNumber">拟合点数量</param>
/// <returns></returns>
  static List<CurvePoint> CalculateSimilarQH(List<CurvePoint> ptList, double originHz, double changeHz, int pointNumber = 12)
{
    if (ptList == null || !ptList.Any())
        return null;
    if (changeHz < 1)
        return null;
    List<CurvePoint> fitPoints = ptList;
    var ratio = changeHz / originHz;
    var similarPoints = new List<CurvePoint>();
    foreach (CurvePoint fitPoint in fitPoints)
    {
        var similarPoint = new CurvePoint();
        similarPoint.X = fitPoint.X * ratio;
        similarPoint.Y = fitPoint.Y * ratio * ratio;
        similarPoints.Add(similarPoint);
    }
    return IStation.Curve.FitHelper.BuildCurveExpress(similarPoints).GetFitPoints(pointNumber);
}
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 (float[] NewX, float[] NewY) UpdateFitPointList(float[] x_values, float[] y_values)
{
    List<int> indices_to_keep = new();
    var prev_y_index = 0;
    float prev_y = y_values[prev_y_index];
    var max_y_index = y_values.ToList().FindLastIndex(x => x > prev_y);
    if (max_y_index > 0)
    {
        var temp_index = (int)(y_values.Length * 0.5);
        if (temp_index > max_y_index)
        {
            prev_y_index = max_y_index;
            prev_y = y_values[prev_y_index];
        }
        var tttIndex = y_values.Skip(prev_y_index).ToList().FindLastIndex(x => x > prev_y);
        if (tttIndex > 0)
        {
            throw new Exception("aaa");
            //temp_index = (int)(y_values.Length * 0.5);
            //if (temp_index > max_y_index)
            //{
            //    prev_y_index = max_y_index;
            //    prev_y = y_values[prev_y_index];
            //}
        }
    }
    for (int i = prev_y_index; i < y_values.Length; i++)
    {
        float current_y = y_values[i];
        if (current_y <= prev_y)
        {
            indices_to_keep.Add(i);
            prev_y = current_y;
        }
    }
    float[] x_processed = new float[indices_to_keep.Count];
    float[] y_processed = new float[indices_to_keep.Count];
    for (int i = 0; i < indices_to_keep.Count; i++)
    {
        int index = indices_to_keep[i];
        x_processed[i] = x_values[index];
        y_processed[i] = y_values[index];
    }
    return new(x_processed, y_processed);
}
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;
}
01-api/_Expand/IStation.Win.Schedule/Core/Alert/AlertTool.cs
@@ -8,12 +8,12 @@
        private static AlertControl Alert
        {
            get
            {
            {
                if (_alert == null)
                {
                    _alert = new AlertControl();
                    //_alert.FormMaxCount = 1;
                    _alert.AutoFormDelay = 5 * 1000;
                    _alert.AutoFormDelay = 2 * 1000;
                    _alert.AutoHeight = true;
                }
                return _alert;
@@ -29,7 +29,7 @@
        /// <param name="text"></param>
        public static void ShowInfo(Form owner, string caption, string text)
        {
            DevExpress.XtraBars.Alerter.AlertInfo info = new DevExpress.XtraBars.Alerter.AlertInfo(caption, text);
            DevExpress.XtraBars.Alerter.AlertInfo info = new DevExpress.XtraBars.Alerter.AlertInfo(caption, text);
            AlertTool.Alert.Show(owner, info);
        }
01-api/_Expand/IStation.Win.Schedule/Properties/Resources.Designer.cs
@@ -73,6 +73,16 @@
        /// <summary>
        ///   æŸ¥æ‰¾ DevExpress.Utils.Svg.SvgImage ç±»åž‹çš„æœ¬åœ°åŒ–资源。
        /// </summary>
        internal static DevExpress.Utils.Svg.SvgImage number {
            get {
                object obj = ResourceManager.GetObject("number", resourceCulture);
                return ((DevExpress.Utils.Svg.SvgImage)(obj));
            }
        }
        /// <summary>
        ///   æŸ¥æ‰¾ DevExpress.Utils.Svg.SvgImage ç±»åž‹çš„æœ¬åœ°åŒ–资源。
        /// </summary>
        internal static DevExpress.Utils.Svg.SvgImage weather_water {
            get {
                object obj = ResourceManager.GetObject("weather_water", resourceCulture);
01-api/_Expand/IStation.Win.Schedule/Properties/Resources.resx
@@ -124,4 +124,7 @@
  <data name="weather_water" type="System.Resources.ResXFileRef, System.Windows.Forms">
    <value>..\Resources\weather_water.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a</value>
  </data>
  <data name="number" type="System.Resources.ResXFileRef, System.Windows.Forms">
    <value>..\Resources\number.svg;DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a</value>
  </data>
</root>
01-api/_Expand/IStation.Win.Schedule/Resources/number.svg
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<svg x="0px" y="0px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" id="Number_1_" style="enable-background:new 0 0 32 32">
  <style type="text/css">
    .Black{fill:#727272;}
</style>
  <path d="M7,24V12H3v-2c0.6,0,1.2,0,1.7-0.1c0.6-0.1,1-0.3,1.5-0.6C6.6,9,7,8.6,7.3,8.2  C7.6,7.7,7.8,6.7,7.9,6H11v18H7z M15.7,10.3c0.2-0.9,0.6-1.6,1.1-2.3c0.5-0.6,1.1-1.2,1.9-1.5C19.5,6.2,20.3,6,21.3,6  c0.7,0,1.5,0.1,2.1,0.4c0.7,0.3,1.3,0.6,1.8,1.1c0.5,0.5,0.9,1.1,1.2,1.7c0.3,0.7,0.5,1.5,0.5,2.3c0,0.9-0.1,1.7-0.4,2.3  c-0.3,0.6-0.6,1.2-1.1,1.7C25,16,24.5,16.5,24,16.9c-0.6,0.4-1.1,0.8-1.7,1.2c-0.6,0.4-1.1,0.8-1.6,1.3c-0.5,0.5-1,1-1.4,1.6H27V24  H15c0-1,0.1-1.9,0.4-2.7c0.3-0.8,0.6-1.4,1.1-2c0.5-0.6,1-1.1,1.6-1.7c0.6-0.5,1.3-1,2-1.5c0.4-0.3,0.7-0.5,1.1-0.8  c0.4-0.3,0.8-0.6,1.1-0.9c0.3-0.3,0.6-0.7,0.8-1.1c0.2-0.4,0.3-0.9,0.3-1.4c0-0.9-0.2-1.5-0.7-2c-0.5-0.5-1-0.7-1.8-0.7  c-0.5,0-0.9,0.1-1.2,0.4c-0.3,0.2-0.6,0.6-0.8,1c-0.2,0.4-0.3,0.8-0.4,1.3c-0.1,0.5-0.1,1-0.1,1.4h-3.2  C15.3,12.1,15.5,11.2,15.7,10.3z" id="Number" class="Black" />
</svg>
01-api/_Expand/IStation.Win.Schedule/bjMain.Designer.cs
@@ -40,6 +40,7 @@
            barCekSimSchedule = new DevExpress.XtraBars.BarCheckItem();
            barCekUseCalcDev = new DevExpress.XtraBars.BarCheckItem();
            barCekCalcFlowDiff = new DevExpress.XtraBars.BarCheckItem();
            barCekCalcPressureDiff = new DevExpress.XtraBars.BarCheckItem();
            ribbonPage1 = new RibbonPage();
            ribbonPageGroup1 = new RibbonPageGroup();
            gridControl1 = new DevExpress.XtraGrid.GridControl();
@@ -137,10 +138,10 @@
            ribbon.EmptyAreaImageOptions.ImagePadding = new Padding(24, 25, 24, 25);
            ribbon.ExpandCollapseItem.Id = 0;
            ribbon.ItemPanelStyle = RibbonItemPanelStyle.Classic;
            ribbon.Items.AddRange(new DevExpress.XtraBars.BarItem[] { ribbon.ExpandCollapseItem, barEditImgDate, barEditImgRealTime, barCekSimSchedule, barCekUseCalcDev, barCekCalcFlowDiff });
            ribbon.Items.AddRange(new DevExpress.XtraBars.BarItem[] { ribbon.ExpandCollapseItem, barEditImgDate, barEditImgRealTime, barCekSimSchedule, barCekUseCalcDev, barCekCalcFlowDiff, barCekCalcPressureDiff });
            ribbon.Location = new Point(0, 0);
            ribbon.Margin = new Padding(2);
            ribbon.MaxItemId = 11;
            ribbon.MaxItemId = 14;
            ribbon.Name = "ribbon";
            ribbon.OptionsMenuMinWidth = 264;
            ribbon.Pages.AddRange(new RibbonPage[] { ribbonPage1 });
@@ -199,11 +200,19 @@
            // 
            // barCekCalcFlowDiff
            // 
            barCekCalcFlowDiff.Caption = "计算流量偏差";
            barCekCalcFlowDiff.Caption = "计算二输水流量偏差";
            barCekCalcFlowDiff.Id = 10;
            barCekCalcFlowDiff.ImageOptions.SvgImage = Properties.Resources.weather_water;
            barCekCalcFlowDiff.Name = "barCekCalcFlowDiff";
            barCekCalcFlowDiff.CheckedChanged += barCekCalcFlowDiff_CheckedChanged;
            //
            // barCekCalcPressureDiff
            //
            barCekCalcPressureDiff.Caption = "计算一输水压力偏差";
            barCekCalcPressureDiff.Id = 13;
            barCekCalcPressureDiff.ImageOptions.SvgImage = Properties.Resources.number;
            barCekCalcPressureDiff.Name = "barCekCalcPressureDiff";
            barCekCalcPressureDiff.CheckedChanged += barCekCalcPressureDiff_CheckedChanged;
            // 
            // ribbonPage1
            // 
@@ -217,6 +226,7 @@
            ribbonPageGroup1.ItemLinks.Add(barEditImgRealTime);
            ribbonPageGroup1.ItemLinks.Add(barCekSimSchedule);
            ribbonPageGroup1.ItemLinks.Add(barCekUseCalcDev);
            ribbonPageGroup1.ItemLinks.Add(barCekCalcPressureDiff);
            ribbonPageGroup1.ItemLinks.Add(barCekCalcFlowDiff);
            ribbonPageGroup1.Name = "ribbonPageGroup1";
            ribbonPageGroup1.Text = "操作";
@@ -939,5 +949,6 @@
        private DevExpress.XtraBars.BarCheckItem barCekUseCalcDev;
        private DevExpress.XtraBars.BarButtonItem barBtnCalcFlowDiff;
        private DevExpress.XtraBars.BarCheckItem barCekCalcFlowDiff;
        private DevExpress.XtraBars.BarCheckItem barCekCalcPressureDiff;
    }
}
01-api/_Expand/IStation.Win.Schedule/bjMain.cs
@@ -83,15 +83,15 @@
            {
                return;
            }
            var time_list = _schedule_request_list.Select(x => x.ReceptionTime).OrderBy(x => x).ToList();
            var start_time = time_list.Last().AddDays(-2);
            var end_time = time_list.Last().AddDays(1);
            var deline = new DateTime(2024,12,1);
            var deline2 = new DateTime(2025,1,1);
            var time_list = _schedule_request_list.Where(x=>x.ReceptionTime>=deline&&x.ReceptionTime<= deline2).Select(x => x.ReceptionTime).OrderBy(x => x).ToList();
            foreach (var item in time_list)
            {
                this.repImgDate.Items.Add(item.ToString("G"), item, -1);
            }
            var monitor_record_list = _service_monitor_record.GetByReceiptTimeRange(start_time, end_time);
            }
            var monitor_record_list = _service_monitor_record.GetByReceiptTimeRange(deline, deline2);
            if (monitor_record_list == null || !monitor_record_list.Any())
            {
                return;
@@ -123,7 +123,7 @@
            if (this.barCekSimSchedule.Checked)
            {
                var target_flow1 = request.TargetFlow1;
                var target_flow2 = request.TargetFlow2;
                var target_flow2 = request.TargetFlow2;
                var target_pressure1 = Curve.PumpCalculateHelper.Mpa2M(request.TargetPressure1);
                var target_pressure2 = Curve.PumpCalculateHelper.Mpa2M(request.TargetPressure2);
@@ -139,12 +139,30 @@
                    analysis_deviation_list = null;
                }
                if (this.barCekCalcPressureDiff.Checked)
                {
                    var time = Convert.ToDateTime(this.barEditImgRealTime.EditValue);
                    if (_monitor_record_dict != null && _monitor_record_dict.ContainsKey(time))
                    {
                        var valid_record_list = _monitor_record_dict[time];
                        var station_scada_dict = GetStationScadaDict(monitor_record_list);
                        var validRealTimePressure = station_scada_dict[IStation.eDockingStation.Ch1s][0].Item2 ;
                        if (validRealTimePressure.HasValue)
                        {
                            var validRealTimePressureDiff = validRealTimePressure.Value - target_pressure1;
                            target_pressure1 += validRealTimePressureDiff;
                            AlertTool.ShowInfo(this, "填补压力缺失", $"{validRealTimePressureDiff:N3}");
                        }
                    }
                }
                if (this.barCekCalcFlowDiff.Checked)
                {
                    var ptList = new List<CurvePoint>();
                    try
                    {
                        var filePath = @"D:\WorkCode\Project\ChDt1\Schedule.Ch.V1.0\02-desktop\Desktop\IStation.Test\bin\Debug\net6.0-windows\csv\alow.csv";
                        var filePath = @"D:\WorkCode\Project\ChDt1\Schedule.Ch.V1.0\02-desktop\Desktop\IStation.Test\bin\Debug\net6.0-windows\stationcsv\characteristic_curve.csv";
                        using (StreamReader reader = new StreamReader(filePath))
                        {
                            reader.ReadLine();
@@ -164,17 +182,17 @@
                            }
                        }
                    }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("读取文件时出错: " + ex.Message);
                    }
                    var x = ptList.Select(x => x.X).ToArray();
                    var y = ptList.Select(x => x.Y).ToArray();
                    // å¤šé¡¹å¼å›žå½’的阶数(例如,二次多项式)
                    int degree = 10;
                    int degree = 3;
                    // æ‹Ÿåˆå¤šé¡¹å¼å›žå½’模型
                    double[] coefficients = NonlinearRegressionHelper.FitPolynomial(x, y, degree);
@@ -184,12 +202,13 @@
                    double yPredicted = NonlinearRegressionHelper.PredictPolynomial(xNew, coefficients);
                    target_flow2 += yPredicted;
                    AlertTool.ShowInfo(this,"预测缺失",$"{yPredicted}");
                    AlertTool.ShowInfo(this, "预测流量缺失", $"{yPredicted:N1}");
                    // è®¡ç®— R² å’Œ MSE
                    double rSquared = NonlinearRegressionHelper.CalculateRSquared(x, y, coefficients);
                    double mse = NonlinearRegressionHelper.CalculateMSE(x, y, coefficients);
                }
@@ -690,6 +709,14 @@
            Verify(time);
        }
        private void barCekCalcPressureDiff_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            var time = Convert.ToDateTime(this.barEditImgRealTime.EditValue);
            Schedule(_schedule_request);
            Verify(time);
        }
        #region Expand
        private string GetStationName(eDockingStation station)
        {
@@ -927,13 +954,17 @@
            var pump27_power = scada_dict[GlobalHelper.二输27æ³µ_有功功率];
            var pump21_maintenance_status = scada_dict[GlobalHelper.二输21æ³µ_状态];
            var pump22_maintenance_status = scada_dict[GlobalHelper.二输22æ³µ_状态];
            var pump23_maintenance_status = scada_dict[GlobalHelper.二输23æ³µ_状态];
            var pump24_maintenance_status = scada_dict[GlobalHelper.二输24æ³µ_状态];
            var pump25_maintenance_status = scada_dict[GlobalHelper.二输25æ³µ_状态];
            var pump26_maintenance_status = scada_dict[GlobalHelper.二输26æ³µ_状态];
            var pump27_maintenance_status = scada_dict[GlobalHelper.二输27æ³µ_状态];
            if (scada_dict.ContainsKey(GlobalHelper.二输21æ³µ_状态))
            {
            }
            //var pump21_maintenance_status = scada_dict[GlobalHelper.二输21æ³µ_状态];
            //var pump22_maintenance_status = scada_dict[GlobalHelper.二输22æ³µ_状态];
            //var pump23_maintenance_status = scada_dict[GlobalHelper.二输23æ³µ_状态];
            //var pump24_maintenance_status = scada_dict[GlobalHelper.二输24æ³µ_状态];
            //var pump25_maintenance_status = scada_dict[GlobalHelper.二输25æ³µ_状态];
            //var pump26_maintenance_status = scada_dict[GlobalHelper.二输26æ³µ_状态];
            //var pump27_maintenance_status = scada_dict[GlobalHelper.二输27æ³µ_状态];
            pump21_pressure.Mpa2M();
@@ -1091,7 +1122,7 @@
        #endregion
        public class NonlinearRegressionHelper
        {
        {
            // å¤šé¡¹å¼å›žå½’拟合
            public static double[] FitPolynomial(double[] x, double[] y, int degree)
02-desktop/Desktop/IStation.Test/IStation.Test.csproj
@@ -43,6 +43,7 @@
    <Compile Remove="Program -doubao.cs" />
    <Compile Remove="Station1CombineHelper - å¤åˆ¶.cs" />
    <Compile Remove="Station2Helper - å¤åˆ¶.cs" />
    <Compile Remove="TotalFlowDiffHelper - å¤åˆ¶.cs" />
  </ItemGroup>
  <ItemGroup>
02-desktop/Desktop/IStation.Test/Program.cs
@@ -20,7 +20,10 @@
            //StationCombineHelper.Start(1);// 5 ç»„合偏差修正
            //StationCombineHelper.Start(2);// 5 ç»„合偏差修正
            StationCombineHelper.Start(3);// 6 åˆ†æžæ³µé¢‘谱系数
            // 6 åˆ†æžæ³µé¢‘谱系数
            // 7
            Station2TotalFlowDiffHelper.Start();// 8 è¡¥å…¨æµé‡åå·®
            Console.WriteLine();
            Console.WriteLine("ok");
            Console.ReadKey();
02-desktop/Desktop/IStation.Test/Station2TotalFlowDiffHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,109 @@
using IStation.Model;
namespace IStation.Test
{
    public class Station2TotalFlowDiffHelper
    {
        /// <summary>
        /// è¾“出偏差数据
        /// </summary>
        public static void Start()
        {
            var bll = new BLL.StationSignalRecordPacket();
            var projectId = 661070185922629;
            IStation.SettingsD.Project.ID = projectId;
            var monitorDataSourcesId = 663976941449285;//2024-202504
            var stationId = 462958422204485;
            var ptFilterList = new List<PointViewModel>();
            var packets = bll.Get(monitorDataSourcesId, stationId);
            var ptList = new List<FlowDiffViewModel>();
            var records = packets.SelectMany(x => x.StationSignalRecords).ToList();
            foreach (var x in records)
            {
                if (x.TotalPressure > 0 && x.TotalFlow > 0)
                {
                    ptList.Add( new (x.TotalFlow, Math.Round(x.TotalPressure, 1), x.DiffFlow));
                }
            }
            var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "stationcsv");
            if (!Directory.Exists(fullPath))
            {
                Directory.CreateDirectory(fullPath);
            }
            var group = ptList.GroupBy(x => x.Pressure);
            string filePath = Path.Combine(fullPath, "flow_diff_range2.csv");
            using StreamWriter writer = new(filePath, false, System.Text.Encoding.UTF8);
            writer.WriteLine($"Pressure2,FlowDiffUpper,FlowDiffAverage,FlowDiffLower");
            var allList = new List<FlowDiffViewModel>();
            foreach (var item in group)
            {
                var tt = item.ToList();
                var fList = Filter(tt);
                allList.AddRange(fList);
                var x = item.Key;
                var yUpper = item.Max(x => x.FlowDiff);
                var yLower = item.Min(x => x.FlowDiff);
                var yAverage = item.Average(x => x.FlowDiff);
                if (fList != null && fList.Any())
                {
                    yUpper = fList.Max(x => x.FlowDiff);
                    yLower = fList.Min(x => x.FlowDiff);
                    yAverage = fList.Average(x => x.FlowDiff);
                }
                yUpper = Math.Round(yUpper,1);
                yLower = Math.Round(yLower, 1);
                yAverage = Math.Round(yAverage, 1);
                writer.WriteLine($"{x},{yUpper},{yAverage},{yLower}");
            }
            string filePathAll = Path.Combine(fullPath, "flow_diff2.csv");
            CsvHelper.ExportToCsv(allList, filePathAll);
            Console.WriteLine("ok");
            Console.ReadKey();
        }
        public static List<FlowDiffViewModel> Filter(List<FlowDiffViewModel> ptList)
        {
            var pressures = ptList.Select(p => p.FlowDiff).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 ptList.Where(p => p.FlowDiff >= lower && p.FlowDiff <= upper).ToList();
        }
        public class FlowDiffViewModel
        {
            public FlowDiffViewModel(double totalFlow, double pressure, double flowDiff)
            {
                TotalFlow = Math.Round(totalFlow, 1);
                Pressure = pressure;
                FlowDiff = Math.Round(flowDiff,1);
            }
            public double TotalFlow { get; set; }
            public double Pressure { get; set; }
            public double FlowDiff { get; set; }
        }
    }
}
02-desktop/Desktop/IStation.Test/TotalFlowDiffHelper - ¸´ÖÆ.cs
ÎļþÃû´Ó 02-desktop/Desktop/IStation.Test/TotalFlowDiffHelper.cs ÐÞ¸Ä
@@ -35,7 +35,6 @@
                {
                    if (x.TotalPressure > 0 && x.TotalFlow > 0)
                    {
                        //if (stationIndex == 2 && Math.Abs(x.DiffFlow) > 0)
                        if (stationIndex == 2 && x.DiffFlow > 0)
                        {
                            continue;
@@ -45,7 +44,6 @@
                }
                //var newPtList = DynamicThresholdProcessorHelper.Filter(ptList);
                var newPtList = ptList;
                ptFilterList.AddRange(newPtList);
            }
@@ -79,16 +77,14 @@
                recordList.Add(record);
            }
            var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "csv");
            var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "stationcsv");
            if (!Directory.Exists(fullPath))
            {
                Directory.CreateDirectory(fullPath);
            }
            }
            {
                var r_list = recordList.Select(x => new PointViewModel(x.Time, Math.Round(x.Pressure2, 1), x.FlowDiff2, 0, 2)).ToList();
                var group = r_list.GroupBy(x => x.X);
@@ -96,7 +92,7 @@
                string filePath = Path.Combine(fullPath, "atest.csv");
                using StreamWriter writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8);
                string filePathLow = Path.Combine(fullPath, "alow.csv");
                string filePathLow = Path.Combine(fullPath, "flowdiff2.csv");
                using StreamWriter writerLow = new StreamWriter(filePathLow, false, System.Text.Encoding.UTF8);
                writer.WriteLine($"Pressure2,FlowDiffUpper,FlowDiffAverage,FlowDiffLower");
                writerLow.WriteLine($"Pressure2,FlowDiffLower");
02-desktop/Desktop/IStation.Test/helper/DynamicThresholdProcessorHelper.cs
@@ -22,6 +22,8 @@
            return ptList.Where(p => p.Item3 >= lower && p.Item3 <= upper).ToList();
        }
        public static List<PointViewModel> Filter(List<PointViewModel> ptList)
        {
@@ -108,7 +110,7 @@
        }
        // ååº¦è®¡ç®—(Pearson's moment coefficient)
        private static double CalculateSkewness(List<double> values)
        public static double CalculateSkewness(List<double> values)
        {
            double mean = values.Average();
            double std = CalculateStats(values).stdDev;