Bladeren bron

偏差分析调整

王波 3 maanden geleden
bovenliggende
commit
858adc5c03

+ 173 - 237
runeconomy-xk/src/main/java/com/gyee/runeconomy/service/WindDirection/WindMachineService.java

@@ -10,9 +10,9 @@ import org.springframework.stereotype.Service;
 import javax.annotation.Resource;
 import java.time.LocalDate;
 import java.time.ZoneId;
-import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.function.ToDoubleFunction;
 import java.util.stream.Collectors;
 
 @Service
@@ -25,285 +25,221 @@ public class WindMachineService {
     private IStationInfoDayService stationInfoDayService;
 
 
-    public Object machine(String wpid,int year) throws Exception {
-        // 获取当前日期
-        int currentYear = LocalDate.now().getYear();
-        currentYear = year;
+    public Object machine(String wpid, int year) throws Exception {
+        LocalDate startOfYear = LocalDate.of(year, 1, 1);
+        LocalDate endOfYear = LocalDate.of(year, 12, 31);
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        String startOfYearStr = startOfYear.format(formatter);
+        String endOfYearStr = endOfYear.format(formatter);
 
-        List<ProBasicEquipment> collect = CacheContext.wtls.stream()
-                .filter(wt -> wpid.equals(wt.getWindpowerstationId()))
-                .collect(Collectors.toList());
+        Map<String, List<Double>> monthlyData = new LinkedHashMap<>();
+
+        // =================================================================================
+        // 1. 提取公共数据:一次性计算全场站的月度测风塔数据
+        // =================================================================================
+        List<StationInfoDay> stationInfoDays = stationInfoDayService.getTurbineList(wpid, startOfYearStr, endOfYearStr);
+
+        Map<Integer, List<StationInfoDay>> stationDataByMonth = stationInfoDays.stream()
+                .collect(Collectors.groupingBy(day -> day.getRecordDate().getMonthValue()));
 
-        Map<String, List> monthlyData = new LinkedHashMap<>();
+        List<Double> cftfsAvgList = calculateMonthlyAverages(stationDataByMonth, day -> Optional.ofNullable(day.getCftfs()).map(Number::doubleValue).orElse(0.0));
+        List<Double> cftfxAvgList = calculateMonthlyAverages(stationDataByMonth, day -> Optional.ofNullable(day.getCftfx()).map(Number::doubleValue).orElse(0.0));
 
+        // 将计算出的场站数据格式化为两位小数
+        List<Double> formattedCftfsAvgList = cftfsAvgList.stream()
+                .map(d -> Double.parseDouble(String.format("%.2f", d)))
+                .collect(Collectors.toList());
 
-        // 风机循环:每台风机每个月一个 WindData 对象
-        for (ProBasicEquipment eq : collect) {
+        List<Double> formattedCftfxAvgList = cftfxAvgList.stream()
+                .map(d -> Double.parseDouble(String.format("%.2f", d)))
+                .collect(Collectors.toList());
 
-            // 获取当前年份的开始日期(1月1日)
-            LocalDate startOfYear = LocalDate.of(currentYear, 1, 1);
+        // 将【格式化后】的场站级别的数据放入Map
+        monthlyData.put("场站测风塔风速", formattedCftfsAvgList);
+        monthlyData.put("场站测风塔风向", formattedCftfxAvgList);
+        // --- 本次修改结束 ---
 
-            // 获取当前年份的结束日期(12月31日)
-            LocalDate endOfYear = LocalDate.of(currentYear, 12, 31);
 
-            // 使用 DateTimeFormatter 格式化日期为字符串
-            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        // =================================================================================
+        // 2. 循环处理每台风机的个性化数据
+        // =================================================================================
+        List<ProBasicEquipment> turbines = CacheContext.wtls.stream()
+                .filter(wt -> wpid.equals(wt.getWindpowerstationId()))
+                .collect(Collectors.toList());
 
-            // 转换为字符串
-            String startOfYearStr = startOfYear.format(formatter);
-            String endOfYearStr = endOfYear.format(formatter);
+        List<String> turbineMetrics = Arrays.asList("fsavg", "fxavg", "fspc", "fxpc");
 
+        for (ProBasicEquipment eq : turbines) {
             List<TurbineInfoDay> turbineList = turbineInfoDayService.getTurbineList(eq.getId(), startOfYearStr, endOfYearStr);
-            List<StationInfoDay> infoDays = stationInfoDayService.getTurbineList(wpid, startOfYearStr, endOfYearStr);
-            List<String> zb = new ArrayList<>();
-            zb.add("fsavg");
-            zb.add("cftfsavg");
-            zb.add("fspc");
-            zb.add("fxavg");
-            zb.add("cftfxavg");
-            zb.add("fxpc");
-
-            for (String z : zb) {
-                // 循环从1月到12月
+
+            Map<Integer, List<TurbineInfoDay>> turbineDataByMonth = turbineList.stream()
+                    .collect(Collectors.groupingBy(turbine ->
+                            turbine.getRecordDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().getMonthValue()
+                    ));
+
+            // 注意:这里获取的是未经格式化的原始平均值,用于后续偏差计算,以保证精度
+            List<Double> fsAvgList = calculateMonthlyAverages(turbineDataByMonth, day -> Optional.ofNullable(day.getPjfs()).map(Number::doubleValue).orElse(0.0));
+            List<Double> fxAvgList = calculateMonthlyAverages(turbineDataByMonth, day -> Optional.ofNullable(day.getFx()).map(Number::doubleValue).orElse(0.0));
+
+            for (String metric : turbineMetrics) {
                 List<Double> result = new ArrayList<>();
-                String zbwz = "";
+                String metricNameInChinese = "";
+
                 for (int month = 1; month <= 12; month++) {
-                    // 过滤 turbineList 中的记录,筛选出对应月份的数据
-                    int finalMonth = month;
-                    List<TurbineInfoDay> filteredList = turbineList.stream()
-                            .filter(turbine -> {
-                                // 获取 turbineInfoDay 的 recordDate(类型为 LocalDate)
-                                Date dateFromTurbine = turbine.getRecordDate();
-
-                                // 将 Date 转换为 LocalDate
-                                ZonedDateTime zonedDateTime = dateFromTurbine.toInstant().atZone(ZoneId.systemDefault());
-                                LocalDate recordDate = zonedDateTime.toLocalDate();
-
-                                // 获取记录的月份(注意,月份从 1 开始,1 表示1月)
-                                int recordMonth = recordDate.getMonthValue();
-
-                                // 判断记录的月份是否等于给定的 time
-                                return recordMonth == finalMonth;  // 比较 int 类型的月份和 time 变量
-                            })
-                            .collect(Collectors.toList());
-
-                    List<StationInfoDay> dayfilteredList = infoDays.stream()
-                            .filter(turbine -> {
-                                // 获取 turbineInfoDay 的 recordDate(类型为 LocalDate)
-                                LocalDate dateFromTurbine = turbine.getRecordDate();
-
-                                // 获取记录的月份(注意,月份从 1 开始,1 表示1月)
-                                int recordMonth = dateFromTurbine.getMonthValue();
-
-                                // 判断记录的月份是否等于给定的 time
-                                return recordMonth == finalMonth;  // 比较 int 类型的月份和 time 变量
-                            })
-                            .collect(Collectors.toList());
-
-                    // 风速
-                    double fsaverage = filteredList.stream()
-                            .mapToDouble(turbineInfoDay -> Optional.ofNullable(turbineInfoDay.getPjfs()).map(Number::doubleValue).orElse(0.0))
-                            .average()
-                            .orElse(0.0);  // 默认值0.0
-
-                    // 风向
-                    double fxaverage = filteredList.stream()
-                            .mapToDouble(turbineInfoDay -> Optional.ofNullable(turbineInfoDay.getFx()).map(Number::doubleValue).orElse(0.0))
-                            .average()
-                            .orElse(0.0);  // 默认值0.0
-
-                    // 测风塔风速
-                    double cftfsaverage = dayfilteredList.stream()
-                            .mapToDouble(turbineInfoDay -> Optional.ofNullable(turbineInfoDay.getCftfs()).map(Number::doubleValue).orElse(0.0))
-                            .average()
-                            .orElse(0.0); // 默认值0.0
-
-                    // 测风塔风向
-                    double cftfxaverage = dayfilteredList.stream()
-                            .mapToDouble(turbineInfoDay -> Optional.ofNullable(turbineInfoDay.getCftfx()).map(Number::doubleValue).orElse(0.0))
-                            .average()
-                            .orElse(0.0);  // 默认值0.0
-
-
-                    double zbsj = 0.0;
-
-                    if (z.toString().equals("fsavg")) {
-                        // 保留两位小数并转换回 double
-                        zbsj = Double.parseDouble(String.format("%.2f", fsaverage));
-                        zbwz = "风速";
-                    } else if (z.toString().equals("fxavg")) {
-                        zbsj = Double.parseDouble(String.format("%.2f", fxaverage));
-                        zbwz = "风向";
-                    } else if (z.toString().equals("cftfsavg")) {
-                        zbsj = Double.parseDouble(String.format("%.2f", cftfsaverage));
-                        zbwz = "测风塔风速";
-                    } else if (z.toString().equals("cftfxavg")) {
-                        zbsj = Double.parseDouble(String.format("%.2f", cftfxaverage));
-                        zbwz = "测风塔风向";
-                    } else if (z.toString().equals("fspc")) {
-                        zbsj = Deviation.calculateSpeedDeviation(
-                                fsaverage,
-                                cftfsaverage
-                        );
-                        zbwz = "风速偏差";
-                    } else if (z.toString().equals("fxpc")) {
-                        zbsj = Deviation.calculateDirectionDeviation(
-                                fxaverage,
-                                cftfxaverage
-                        );
-                        zbwz = "风向偏差";
+                    double value;
+                    // 使用未经格式化的原始数据进行计算
+                    double fsaverage = fsAvgList.get(month - 1);
+                    double fxaverage = fxAvgList.get(month - 1);
+                    double cftfsaverage = cftfsAvgList.get(month - 1); // 同样使用原始数据
+                    double cftfxaverage = cftfxAvgList.get(month - 1); // 同样使用原始数据
+
+                    switch (metric) {
+                        case "fsavg":
+                            value = fsaverage;
+                            metricNameInChinese = "风速";
+                            break;
+                        case "fxavg":
+                            value = fxaverage;
+                            metricNameInChinese = "风向";
+                            break;
+                        case "fspc":
+                            value = Deviation.calculateSpeedDeviation(fsaverage, cftfsaverage);
+                            metricNameInChinese = "风速偏差";
+                            break;
+                        case "fxpc":
+                            value = Deviation.calculateDirectionDeviation(fxaverage, cftfxaverage);
+                            metricNameInChinese = "风向偏差";
+                            break;
+                        default:
+                            value = 0.0;
                     }
-                    result.add(zbsj);
+                    // 在最终存入结果列表前,统一进行格式化
+                    result.add(Double.parseDouble(String.format("%.2f", value)));
                 }
-                monthlyData.put(eq.getAname() + zbwz, result);
+                monthlyData.put(eq.getAname() + metricNameInChinese, result);
             }
-
         }
 
         return monthlyData;
     }
 
+
     /**
      * 气象单机偏差分析
+     *
      * @param wpid
      * @return
      * @throws Exception
      */
-    public Object weathermachine(String wpid,int year) throws Exception {
-        // 获取当前日期
-        int currentYear = LocalDate.now().getYear();
-        currentYear= year;
+    public Object weathermachine(String wpid, int year) throws Exception {
+        LocalDate startOfYear = LocalDate.of(year, 1, 1);
+        LocalDate endOfYear = LocalDate.of(year, 12, 31);
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        String startOfYearStr = startOfYear.format(formatter);
+        String endOfYearStr = endOfYear.format(formatter);
 
-        List<ProBasicEquipment> collect = CacheContext.wtls.stream()
-                .filter(wt -> wpid.equals(wt.getWindpowerstationId()))
-                .collect(Collectors.toList());
+        Map<String, List<Double>> monthlyData = new LinkedHashMap<>();
 
-        Map<String, List> monthlyData = new LinkedHashMap<>();
+        // =================================================================================
+        // 1. 提取公共数据:一次性计算全场站的月度测风塔数据
+        // =================================================================================
+        List<StationInfoDay> stationInfoDays = stationInfoDayService.getTurbineList(wpid, startOfYearStr, endOfYearStr);
 
+        Map<Integer, List<StationInfoDay>> stationDataByMonth = stationInfoDays.stream()
+                .collect(Collectors.groupingBy(day -> day.getRecordDate().getMonthValue()));
 
-        // 风机循环:每台风机每个月一个 WindData 对象
-        for (ProBasicEquipment eq : collect) {
+        List<Double> cftfsAvgList = calculateMonthlyAverages(stationDataByMonth, day -> Optional.ofNullable(day.getCftfs()).map(Number::doubleValue).orElse(0.0));
+        List<Double> cftfxAvgList = calculateMonthlyAverages(stationDataByMonth, day -> Optional.ofNullable(day.getCftfx()).map(Number::doubleValue).orElse(0.0));
 
-            // 获取当前年份的开始日期(1月1日)
-            LocalDate startOfYear = LocalDate.of(currentYear, 1, 1);
+        // 将计算出的场站数据格式化为两位小数
+        List<Double> formattedCftfsAvgList = cftfsAvgList.stream()
+                .map(d -> Double.parseDouble(String.format("%.2f", d)))
+                .collect(Collectors.toList());
+
+        List<Double> formattedCftfxAvgList = cftfxAvgList.stream()
+                .map(d -> Double.parseDouble(String.format("%.2f", d)))
+                .collect(Collectors.toList());
+
+        // 将【格式化后】的场站级别的数据放入Map
+        monthlyData.put("场站测风塔风速", formattedCftfsAvgList);
+        monthlyData.put("场站测风塔风向", formattedCftfxAvgList);
+        // --- 本次修改结束 ---
 
-            // 获取当前年份的结束日期(12月31日)
-            LocalDate endOfYear = LocalDate.of(currentYear, 12, 31);
 
-            // 使用 DateTimeFormatter 格式化日期为字符串
-            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        // =================================================================================
+        // 2. 循环处理每台风机的个性化数据
+        // =================================================================================
+        List<ProBasicEquipment> turbines = CacheContext.wtls.stream()
+                .filter(wt -> wpid.equals(wt.getWindpowerstationId()))
+                .collect(Collectors.toList());
 
-            // 转换为字符串
-            String startOfYearStr = startOfYear.format(formatter);
-            String endOfYearStr = endOfYear.format(formatter);
+        List<String> turbineMetrics = Arrays.asList("fsavg", "fxavg", "fspc", "fxpc");
 
+        for (ProBasicEquipment eq : turbines) {
             List<TurbineInfoDay> turbineList = turbineInfoDayService.getTurbineList(eq.getId(), startOfYearStr, endOfYearStr);
-            List<StationInfoDay> infoDays = stationInfoDayService.getTurbineList(wpid, startOfYearStr, endOfYearStr);
-            List<String> zb = new ArrayList<>();
-            zb.add("fsavg");
-            zb.add("cftfsavg");
-            zb.add("fspc");
-            zb.add("fxavg");
-            zb.add("cftfxavg");
-            zb.add("fxpc");
-
-            for (String z : zb) {
-                // 循环从1月到12月
+
+            Map<Integer, List<TurbineInfoDay>> turbineDataByMonth = turbineList.stream()
+                    .collect(Collectors.groupingBy(turbine ->
+                            turbine.getRecordDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().getMonthValue()
+                    ));
+
+            // 注意:这里获取的是未经格式化的原始平均值,用于后续偏差计算,以保证精度
+            List<Double> fsAvgList = calculateMonthlyAverages(turbineDataByMonth, day -> Optional.ofNullable(day.getPjfs()).map(Number::doubleValue).orElse(0.0));
+            List<Double> fxAvgList = calculateMonthlyAverages(turbineDataByMonth, day -> Optional.ofNullable(day.getFx()).map(Number::doubleValue).orElse(0.0));
+
+            for (String metric : turbineMetrics) {
                 List<Double> result = new ArrayList<>();
-                String zbwz = "";
+                String metricNameInChinese = "";
+
                 for (int month = 1; month <= 12; month++) {
-                    // 过滤 turbineList 中的记录,筛选出对应月份的数据
-                    int finalMonth = month;
-                    List<TurbineInfoDay> filteredList = turbineList.stream()
-                            .filter(turbine -> {
-                                // 获取 turbineInfoDay 的 recordDate(类型为 LocalDate)
-                                Date dateFromTurbine = turbine.getRecordDate();
-
-                                // 将 Date 转换为 LocalDate
-                                ZonedDateTime zonedDateTime = dateFromTurbine.toInstant().atZone(ZoneId.systemDefault());
-                                LocalDate recordDate = zonedDateTime.toLocalDate();
-
-                                // 获取记录的月份(注意,月份从 1 开始,1 表示1月)
-                                int recordMonth = recordDate.getMonthValue();
-
-                                // 判断记录的月份是否等于给定的 time
-                                return recordMonth == finalMonth;  // 比较 int 类型的月份和 time 变量
-                            })
-                            .collect(Collectors.toList());
-
-                    List<StationInfoDay> dayfilteredList = infoDays.stream()
-                            .filter(turbine -> {
-                                // 获取 turbineInfoDay 的 recordDate(类型为 LocalDate)
-                                LocalDate dateFromTurbine = turbine.getRecordDate();
-
-                                // 获取记录的月份(注意,月份从 1 开始,1 表示1月)
-                                int recordMonth = dateFromTurbine.getMonthValue();
-
-                                // 判断记录的月份是否等于给定的 time
-                                return recordMonth == finalMonth;  // 比较 int 类型的月份和 time 变量
-                            })
-                            .collect(Collectors.toList());
-
-                    // 风速
-                    double fsaverage = filteredList.stream()
-                            .mapToDouble(turbineInfoDay -> Optional.ofNullable(turbineInfoDay.getPjfs()).map(Number::doubleValue).orElse(0.0))
-                            .average()
-                            .orElse(0.0);  // 默认值0.0
-
-                    // 风向
-                    double fxaverage = filteredList.stream()
-                            .mapToDouble(turbineInfoDay -> Optional.ofNullable(turbineInfoDay.getFx()).map(Number::doubleValue).orElse(0.0))
-                            .average()
-                            .orElse(0.0);  // 默认值0.0
-
-                    // 测风塔风速
-                    double cftfsaverage = dayfilteredList.stream()
-                            .mapToDouble(turbineInfoDay -> Optional.ofNullable(turbineInfoDay.getCftfs()).map(Number::doubleValue).orElse(0.0))
-                            .average()
-                            .orElse(0.0); // 默认值0.0
-
-                    // 测风塔风向
-                    double cftfxaverage = dayfilteredList.stream()
-                            .mapToDouble(turbineInfoDay -> Optional.ofNullable(turbineInfoDay.getCftfx()).map(Number::doubleValue).orElse(0.0))
-                            .average()
-                            .orElse(0.0);  // 默认值0.0
-
-
-                    double zbsj = 0.0;
-
-                    if (z.toString().equals("fsavg")) {
-                        // 保留两位小数并转换回 double
-                        zbsj = Double.parseDouble(String.format("%.2f", fsaverage));
-                        zbwz = "风速";
-                    } else if (z.toString().equals("fxavg")) {
-                        zbsj = Double.parseDouble(String.format("%.2f", fxaverage));
-                        zbwz = "风向";
-                    } else if (z.toString().equals("cftfsavg")) {
-                        zbsj = Double.parseDouble(String.format("%.2f", cftfsaverage));
-                        zbwz = "测风塔风速";
-                    } else if (z.toString().equals("cftfxavg")) {
-                        zbsj = Double.parseDouble(String.format("%.2f", cftfxaverage));
-                        zbwz = "测风塔风向";
-                    } else if (z.toString().equals("fspc")) {
-                        zbsj = Deviation.calculateSpeedDeviation(
-                                fsaverage,
-                                cftfsaverage
-                        );
-                        zbwz = "风速偏差";
-                    } else if (z.toString().equals("fxpc")) {
-                        zbsj = Deviation.calculateDirectionDeviation(
-                                fxaverage,
-                                cftfxaverage
-                        );
-                        zbwz = "风向偏差";
+                    double value;
+                    // 使用未经格式化的原始数据进行计算
+                    double fsaverage = fsAvgList.get(month - 1);
+                    double fxaverage = fxAvgList.get(month - 1);
+                    double cftfsaverage = cftfsAvgList.get(month - 1);
+                    double cftfxaverage = cftfxAvgList.get(month - 1);
+
+                    switch (metric) {
+                        case "fsavg":
+                            value = fsaverage;
+                            metricNameInChinese = "风速";
+                            break;
+                        case "fxavg":
+                            value = fxaverage;
+                            metricNameInChinese = "风向";
+                            break;
+                        case "fspc":
+                            value = Deviation.calculateSpeedDeviation(fsaverage, cftfsaverage);
+                            metricNameInChinese = "风速偏差";
+                            break;
+                        case "fxpc":
+                            value = Deviation.calculateDirectionDeviation(fxaverage, cftfxaverage);
+                            metricNameInChinese = "风向偏差";
+                            break;
+                        default:
+                            value = 0.0;
                     }
-                    result.add(zbsj);
+                    // 在最终存入结果列表前,统一进行格式化
+                    result.add(Double.parseDouble(String.format("%.2f", value)));
                 }
-                monthlyData.put(eq.getAname() + zbwz, result);
+                monthlyData.put(eq.getAname() + metricNameInChinese, result);
             }
-
         }
 
         return monthlyData;
     }
+
+
+    private <T> List<Double> calculateMonthlyAverages(Map<Integer, List<T>> dataByMonth, ToDoubleFunction<T> mapper) {
+        List<Double> monthlyAverages = new ArrayList<>();
+        for (int month = 1; month <= 12; month++) {
+            List<T> monthData = dataByMonth.getOrDefault(month, Collections.emptyList());
+            double average = monthData.stream()
+                    .mapToDouble(mapper)
+                    .average()
+                    .orElse(0.0);
+            monthlyAverages.add(average);
+        }
+        return monthlyAverages;
+    }
 }