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;
|
|
/**
|
* <p>
|
* 雷达小时汇总表 服务实现类
|
* </p>
|
*
|
* @author moral
|
* @since 2026-09-08
|
*/
|
@Service
|
public class RadarHourlySummaryServiceImpl extends ServiceImpl<RadarHourlySummaryMapper, RadarHourlySummary> 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<String> rawList = radarService.queryRawDataByHour(hourStart, hourEnd);
|
if (rawList.isEmpty()) {
|
return ;
|
}
|
|
// 提取 a34004 / a34002
|
List<String> a34004List = new ArrayList<>();
|
List<String> 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<String> rawList) {
|
List<double[]> 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<Double> 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; }
|
}
|
|
}
|