package com.moral.api.service.impl; import com.moral.api.entity.RadarHourlySummary; import com.moral.api.mapper.RadarHourlySummaryMapper; import com.moral.api.service.HistorySecondRadarService; import com.moral.api.service.RadarHourlySummaryService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** *

* 雷达小时汇总表 服务实现类 *

* * @author moral * @since 2026-09-08 */ @Service public class RadarHourlySummaryServiceImpl extends ServiceImpl implements RadarHourlySummaryService { @Autowired private HistorySecondRadarService radarService; private static final double HEIGHT_STEP = 7.5; private static final int PEAK_SEARCH_LIMIT = 200; private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00:00"); @Override public void processLastHour() { LocalDateTime now = LocalDateTime.now(); LocalDateTime prev = now.minusHours(1).withMinute(0).withSecond(0).withNano(0); processHour(prev.format(FMT)); } @Override public void processHour(String hourStart) { String hourEnd = nextHour(hourStart); List rawList = radarService.queryRawDataByHour(hourStart, hourEnd); if (rawList.isEmpty()) { return ; } // 提取 a34004 / a34002 List a34004List = new ArrayList<>(); List a34002List = new ArrayList<>(); for (String json : rawList) { a34004List.add(extractJsonField(json, "a34004-Avg")); a34002List.add(extractJsonField(json, "a34002-Avg")); } double[] avg04 = averageByHeight(a34004List); double[] avg02 = averageByHeight(a34002List); R r04 = analyze(avg04); R r02 = analyze(avg02); RadarHourlySummary entity = new RadarHourlySummary(); entity.setTime(LocalDateTime.parse(hourStart, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); entity.setRadarData(buildRadarJson(avg04, avg02)); entity.setA34004PeakHeight(BigDecimal.valueOf(r04.peak)); entity.setA34004DropHeight(BigDecimal.valueOf(r04.drop)); entity.setA34002PeakHeight(BigDecimal.valueOf(r02.peak)); entity.setA34002DropHeight(BigDecimal.valueOf(r02.drop)); this.baseMapper.insert(entity); } // ======================== 算法 ======================== private double[] averageByHeight(List rawList) { List rows = new ArrayList<>(); int minLen = Integer.MAX_VALUE; for (String s : rawList) { double[] arr = parseToArray(s); rows.add(arr); if (arr.length < minLen) minLen = arr.length; } double[] avg = new double[minLen]; int n = rows.size(); for (int i = 0; i < minLen; i++) { double sum = 0; for (double[] row : rows) sum += row[i]; BigDecimal bd = new BigDecimal(String.valueOf(sum / n)); BigDecimal resultBd = bd.setScale(2, RoundingMode.HALF_UP); avg[i] =resultBd.doubleValue(); } return avg; } private R analyze(double[] values) { int searchEnd = Math.min(PEAK_SEARCH_LIMIT, values.length); int peakIdx = 0; double peakVal = values[0]; for (int i = 1; i < searchEnd; i++) { if (values[i] > peakVal) { peakVal = values[i]; peakIdx = i; } } double peakHeight = peakIdx * HEIGHT_STEP; System.out.println("最大值 》》》》》》》"+values[peakIdx]+" 》》》》最大高度>>>>>"+peakHeight+" 》》》》最大高度位置>>>>>"+peakIdx); int dropIdx = -1; if(PEAK_SEARCH_LIMIT-peakIdx == 1){ searchEnd = searchEnd+60; } double base = findBaseValue(values, peakIdx, searchEnd); for (int i = peakIdx + 1; i < searchEnd; i++) { if (values[i] <= base * 1.05) { dropIdx = i; break; } } double dropHeight = dropIdx > 0 ? dropIdx * HEIGHT_STEP : 0; System.out.println("最小值 》》》》》》》"+values[dropIdx]+" 》》》》最小高度>>>>>"+dropHeight+" 米 》》》》最小高度位置>>>>>"+dropIdx); return new R(peakHeight, dropHeight); } private double findBaseValue(double[] values, int peakIdx, int end) { List tail = new ArrayList<>(); for (int i = peakIdx + 1; i < end; i++) tail.add(values[i]); if (tail.isEmpty()) return 0; Collections.sort(tail); if (tail.size() >= 2) { double a = tail.get(0), b = tail.get(1); if (b - a > 2.0 || (a > 0 && b / a > 1.5)) return b; } return tail.get(0); } // ======================== 工具 ======================== private String extractJsonField(String json, String field) { String key = "\"" + field + "\""; int s = json.indexOf(key); if (s == -1) return ""; s = json.indexOf(":", s) + 1; while (s < json.length() && (json.charAt(s) == ' ' || json.charAt(s) == '"')) s++; int e = json.indexOf("\"", s); if (e == -1) e = json.indexOf(",", s); if (e == -1) e = json.indexOf("}", s); if (e == -1) return ""; while (e > s && json.charAt(e - 1) == '"') e--; return json.substring(s, e); } private double[] parseToArray(String raw) { if (raw == null || raw.isEmpty()) return new double[0]; String[] parts = raw.split("\\*"); double[] arr = new double[parts.length]; for (int i = 0; i < parts.length; i++) { try { arr[i] = Double.parseDouble(parts[i]); } catch (NumberFormatException e) { arr[i] = 0; } } return arr; } private String buildRadarJson(double[] a04, double[] a02) { StringBuilder sb = new StringBuilder("{\"a34004-Avg\":["); for (int i = 0; i < a04.length; i++) { if (i > 0) sb.append(","); sb.append(String.format("%.6f", a04[i])); } sb.append("],\"a34002-Avg\":["); for (int i = 0; i < a02.length; i++) { if (i > 0) sb.append(","); sb.append(String.format("%.6f", a02[i])); } sb.append("]}"); return sb.toString(); } private String nextHour(String timeStr) { LocalDateTime time = LocalDateTime.parse(timeStr, FMT); LocalDateTime nextTime = time.plusHours(1); return nextTime.format(FMT); } static class R { double peak, drop; R(double peak, double drop) { this.peak = peak; this.drop = drop; } } }