ソースを参照

数据拟合数据过滤调整

王波 4 日 前
コミット
a84553a74c

+ 198 - 10
runeconomy-xk/src/main/java/com/gyee/runeconomy/model/PowerProcessALG.java

@@ -145,6 +145,181 @@ public class PowerProcessALG {
     }
 
 
+    public static List<PowerPointData> dataProcess11(List<PowerPointData> list, Map<Double, Double> map,
+                                                   Double maxs, Double mins, Double maxp, Double minp, Boolean isfbw,
+                                                   Boolean isfhl, Boolean isbw, Boolean istj, Boolean isglpc, Boolean isqfh, Integer qfhdj) {
+
+        if (list == null || list.isEmpty()) return list;
+
+        // 并网起点时间(第一次遇到并网或者从非并网->并网时初始化)
+        String gridStartTime = null;
+
+        // 用索引保存 tempei / tempqf 窗口,避免存对象引用导致连带修改
+        List<Integer> tempeiIndex = new ArrayList<>();
+        List<Integer> tempqfIndex = new ArrayList<>();
+
+        // 遍历原始列表,按业务条件判断 filter(最终写回到每个 item 中)
+        for (int i = 0; i < list.size(); i++) {
+            PowerPointData item = list.get(i);
+            int filter = 0; // 0 保留,1 过滤
+
+            String currentTime = item.getTime();
+            double speed = item.getSpeed();
+            double power = item.getPower();
+            int mxzt = item.getMxzt();
+
+            // 状态判断
+            boolean isGrid = (mxzt == 2);      // 并网
+            boolean isNonGrid = !isGrid;       // 非并网
+
+            // ---------------------------
+            // 1) 过滤非并网值(如果开关 isfbw 为 true)
+            //    原逻辑中非并网要被过滤
+            // ---------------------------
+            if (isfbw != null && isfbw && isNonGrid) {
+                filter = 1;
+                // 标记:当发生非并网事件时,我们需要把之前记录的 tempeiIndex (并网期间的索引)标记为停机前10分钟过滤
+                // 这里的处理会在 istj 分支统一处理(以保持行为一致),但保留当前行为:非并网条目本身也被过滤
+            }
+
+            // ---------------------------
+            // 2) 若发现是并网且 gridStartTime 未初始化,则初始化(第一次并网或刚开始的数据)
+            //    这样能保证“第一条并网数据不会被误过滤”
+            // ---------------------------
+            if (isGrid && gridStartTime == null) {
+                gridStartTime = currentTime;
+                // 不对当前 item 做并网后 10 分钟过滤(作为起点)
+                // 注意:如果你想只在从非并网->并网才初始化,可以改为在 isNonGrid->isGrid 的过渡时初始化
+            }
+
+            // ---------------------------
+            // 3) 风速功率范围过滤(按mins/maxs/minp/maxp)
+            // ---------------------------
+            if (!Double.isNaN(speed) && !Double.isNaN(power)) {
+                if ((mins != null && speed < mins) || (maxs != null && speed > maxs)
+                        || (minp != null && power < minp) || (maxp != null && power > maxp)) {
+                    filter = 1;
+                }
+            }
+
+            // ---------------------------
+            // 4) 过滤非合理值(并网状态下功率小于等于 minp 或速度 < 0) - 保持与你原逻辑一致
+            // ---------------------------
+            if (filter == 0 && isfhl != null && isfhl) {
+                // 如果速度 < 0 且功率 <= minp 则认为不合理(参考原逻辑)
+                if (speed < 0 && !Double.isNaN(power) && minp != null && power <= minp) {
+                    filter = 1;
+                }
+            }
+
+            // ---------------------------
+            // 5) 并网后 10 分钟过滤(isbw 开关)
+            //    注意:gridStartTime 必须有效(非 null),getTimeDiff 返回 -1 时不做过滤
+            // ---------------------------
+            if (filter == 0 && isbw != null && isbw && gridStartTime != null) {
+                int diff = getTimeDiff(currentTime, gridStartTime);
+                if (diff >= 0 && diff <= 10) {
+                    filter = 1;
+                }
+            }
+
+            // ---------------------------
+            // 6) 停机前 10 分钟过滤(istj 开关)
+            //    语义:当检测到非并网(isNonGrid)时,将之前记录的并网期间最近的若干条(最多覆盖10分钟窗口)标记为过滤
+            //    我们通过 tempeiIndex 在并网期间保存索引;一旦发现非并网 -> 标记这些索引
+            // ---------------------------
+            if (istj != null && istj) {
+                if (isNonGrid) {
+                    // 发生非并网事件:把 tempeiIndex 中的候选项都标记为过滤
+                    for (Integer idx : tempeiIndex) {
+                        if (idx >= 0 && idx < list.size()) {
+                            list.get(idx).setFilter(1);
+                        }
+                    }
+                    // 清空窗口
+                    tempeiIndex.clear();
+                } else {
+                    // 当前仍为并网:维护 tempeiIndex,使其只保存最近不超过 10 分钟的并网索引
+                    if (!tempeiIndex.isEmpty()) {
+                        int firstIdx = tempeiIndex.get(0);
+                        String firstTime = list.get(firstIdx).getTime();
+                        int diff = getTimeDiff(firstTime, currentTime);
+                        if (diff >= 0 && diff >= 10) {
+                            // 超过 10 分钟,则移除最旧的(可以循环移除,但原逻辑是单次检查)
+                            tempeiIndex.remove(0);
+                        }
+                    }
+                    // 添加当前并网索引到窗口头(保持与原逻辑一致的顺序)
+                    tempeiIndex.add(i);
+                }
+            }
+
+            // ---------------------------
+            // 7) 欠发过滤(isqfh 开关 + qfhdj 等级判断)
+            //    逻辑:如果当前点满足欠发条件 -> 过滤,并把 tempqfIndex 中的索引标记为过滤
+            // ---------------------------
+            boolean needQF = false;
+            if (filter == 0 && isqfh != null && isqfh) {
+                // qfzt 为设备点的欠发状态等级
+                int qfzt = item.getQfzt();
+                if (!Double.isNaN(speed)) {
+                    if (speed >= 6 && speed < 12.5 && qfhdj != null && qfhdj < qfzt) {
+                        needQF = true;
+                    } else if (speed >= 12.5 && qfhdj != null && qfhdj < 1) {
+                        needQF = true;
+                    }
+                }
+            }
+
+            if (needQF) {
+                filter = 1;
+                for (Integer idx : tempqfIndex) {
+                    if (idx >= 0 && idx < list.size()) {
+                        list.get(idx).setFilter(1);
+                    }
+                }
+            }
+
+            // 更新 tempqfIndex:保持一个 5 分钟窗口(与原逻辑相同)
+            if (!tempqfIndex.isEmpty()) {
+                int firstIdx = tempqfIndex.get(0);
+                String firstTime = list.get(firstIdx).getTime();
+                int diff = getTimeDiff(firstTime, currentTime);
+                if (diff >= 0 && diff >= 5) {
+                    tempqfIndex.remove(0);
+                }
+            }
+            // 将当前索引放到 tempqfIndex 的头部(和你原来 add(0, item) 的语义对应)
+            tempqfIndex.add(0, i);
+
+            // ---------------------------
+            // 8) 功率曲线偏差(isglpc 开关)
+            //    使用 map 提供的保证功率(map.get(speed))和 map.get(24.0) 作为最大保证功率
+            // ---------------------------
+            if (filter == 0 && isglpc != null && isglpc && map != null && map.containsKey(speed)) {
+                Double guaranteePower = map.get(speed);
+                Double maxGuarantee = map.get(24.0);
+                if (guaranteePower != null && guaranteePower > 0 && !Double.isNaN(power) && power > 0) {
+                    double k = power / guaranteePower; // 实际功率 / 保证功率(注意:与你原 k 定义可换)
+                    // 按你原始逻辑规则决定阈值(此处保留原来的判断条件)
+                    if (k < 0.95 && maxGuarantee != null && maxGuarantee <= guaranteePower) filter = 1;
+                    if (k < 0.9 && maxGuarantee != null && maxGuarantee > guaranteePower) filter = 1;
+                    if (k < 0.85 && speed < 6 && speed > 4) filter = 1;
+                    if (k < 0.9 && speed <= 4 && speed > 3.5) filter = 1;
+                }
+            }
+
+            // ---------------------------
+            // 9) 最终设置当前项的 filter(0 或 1)
+            // ---------------------------
+            item.setFilter(filter);
+        }
+
+        // 返回原 list(对象被按需修改 filter 字段;但没有把对象引用放到临时集合中造成额外污染)
+        return list;
+    }
+
+
     /**
      * 按照给定风俗功率过滤
      * @param list
@@ -356,20 +531,33 @@ public class PowerProcessALG {
         return list;
     }
 
-
+//
+//    public static int getTimeDiff(String oldTime, String newTime) {
+//        int diff = 0;
+//        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+//        long NTime = 0;
+//        long OTime = 0;
+//        try {
+//            NTime = df.parse(newTime).getTime();
+//            //从对象中拿到时间
+//            OTime = df.parse(oldTime).getTime();
+//            diff = (int) (Math.abs((NTime-OTime))/1000/60);
+//        } catch (ParseException e) {
+//        }
+//
+//        return diff;
+//    }
+    // ---------- 时间差工具(请替换原有实现) ----------
     public static int getTimeDiff(String oldTime, String newTime) {
-        int diff = 0;
+        if (oldTime == null || newTime == null) return -1;
         SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        long NTime = 0;
-        long OTime = 0;
         try {
-            NTime = df.parse(newTime).getTime();
-            //从对象中拿到时间
-            OTime = df.parse(oldTime).getTime();
-            diff = (int) (Math.abs((NTime-OTime))/1000/60);
+            long OTime = df.parse(oldTime).getTime();
+            long NTime = df.parse(newTime).getTime();
+            return (int) (Math.abs(NTime - OTime) / 1000 / 60);
         } catch (ParseException e) {
+            // 解析失败视为无法比较
+            return -1;
         }
-
-        return diff;
     }
 }

+ 2 - 1
runeconomy-xk/src/main/java/com/gyee/runeconomy/service/auto/impl/NewDataFittingService.java

@@ -225,7 +225,8 @@ public class NewDataFittingService {
                 /** 数据预处理 **/
                 Boolean qfh = true;
                 Integer qfhdj = 2;
-                List<PowerPointData> data = PowerProcessALG.dataProcess(eis, modelPowerMap, maxs, mins, maxp, minp, isfbw, isfhl, isbw, istj, isglpc, qfh, qfhdj);
+//                List<PowerPointData> data = PowerProcessALG.dataProcess(eis, modelPowerMap, maxs, mins, maxp, minp, isfbw, isfhl, isbw, istj, isglpc, qfh, qfhdj);
+                List<PowerPointData> data = PowerProcessALG.dataProcess11(eis, modelPowerMap, maxs, mins, maxp, minp, isfbw, isfhl, isbw, istj, isglpc, qfh, qfhdj);
                 /** 静风频率 **/
                 List<Double> ls = WindDirectionALG.frequency(data.stream().map(PowerPointData::getSpeed).collect(Collectors.toList()), 3);
                 double frequency = ls.get(0);