回归修改
parent
1af30dc3e9
commit
29f4658d91
|
|
@ -11,12 +11,12 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@MapperScan({
|
||||
"com.gunshi.project.hsz.datasync.mapper",
|
||||
"com.gunshi.project.hsz.datasync.mapper.jcsk",
|
||||
"com.gunshi.project.hsz.datasync.rsvrWaterLevel",
|
||||
"com.gunshi.project.hsz.datasync.config",
|
||||
"com.gunshi.project.hsz.datasync.flow",
|
||||
"com.gunshi.project.hsz.datasync.gnss",
|
||||
"com.gunshi.project.hsz.datasync.rainfall",
|
||||
"com.gunshi.project.hsz.datasync.gate",
|
||||
"com.gunshi.project.hsz.datasync.riverWaterLevel",
|
||||
"com.gunshi.project.hsz.datasync.seepage",
|
||||
"com.gunshi.project.hsz.datasync.waterLevel",
|
||||
})
|
||||
public class Main {
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ public class ForecastResultsController {
|
|||
|
||||
//收集实际数据和
|
||||
List<ForecastResultVo> collect = voList.stream().filter(o -> {
|
||||
return o.getYcRkQValue() != null;
|
||||
return o.getRealRkQValue() != null;
|
||||
}).collect(Collectors.toList());
|
||||
BigDecimal rkVValue = BigDecimal.ZERO;
|
||||
for (ForecastResultVo entity : collect) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.gunshi.project.hsz.model;
|
|||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -45,7 +46,7 @@ public class RegressionEquation {
|
|||
}
|
||||
|
||||
/**
|
||||
* 生成方程字符串
|
||||
* 生成方程字符串(使用数学符号)
|
||||
*/
|
||||
private String generateEquationString() {
|
||||
StringBuilder sb = new StringBuilder("y = ");
|
||||
|
|
@ -64,18 +65,19 @@ public class RegressionEquation {
|
|||
coeff = coeff.abs();
|
||||
}
|
||||
|
||||
// 系数和变量
|
||||
// 系数和变量 - 保留至少20位小数
|
||||
if (i == 0) {
|
||||
// 常数项
|
||||
sb.append(String.format("%.4f", coeff));
|
||||
// 常数项 - 保留至少20位小数
|
||||
sb.append(coeff.setScale(20, RoundingMode.HALF_UP).toPlainString());
|
||||
} else {
|
||||
// 非常数项
|
||||
// 非常数项 - 保留至少20位小数
|
||||
if (coeff.compareTo(BigDecimal.ONE) != 0 && coeff.compareTo(BigDecimal.ONE.negate()) != 0) {
|
||||
sb.append(String.format("%.4f", coeff));
|
||||
sb.append(coeff.setScale(20, RoundingMode.HALF_UP).toPlainString());
|
||||
}
|
||||
sb.append("x");
|
||||
if (i > 1) {
|
||||
sb.append("^").append(i);
|
||||
// 使用Unicode上标数字
|
||||
sb.append(getSuperscript(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -83,6 +85,30 @@ public class RegressionEquation {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数字的Unicode上标表示
|
||||
*/
|
||||
private String getSuperscript(int number) {
|
||||
String numStr = String.valueOf(number);
|
||||
StringBuilder superscript = new StringBuilder();
|
||||
for (char c : numStr.toCharArray()) {
|
||||
switch (c) {
|
||||
case '0': superscript.append('⁰'); break;
|
||||
case '1': superscript.append('¹'); break;
|
||||
case '2': superscript.append('²'); break;
|
||||
case '3': superscript.append('³'); break;
|
||||
case '4': superscript.append('⁴'); break;
|
||||
case '5': superscript.append('⁵'); break;
|
||||
case '6': superscript.append('⁶'); break;
|
||||
case '7': superscript.append('⁷'); break;
|
||||
case '8': superscript.append('⁸'); break;
|
||||
case '9': superscript.append('⁹'); break;
|
||||
default: superscript.append(c);
|
||||
}
|
||||
}
|
||||
return superscript.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据x值预测y值
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@ import java.math.BigDecimal;
|
|||
import java.math.RoundingMode;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -42,7 +40,8 @@ import java.util.stream.Collectors;
|
|||
@Service
|
||||
@Slf4j
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, ForecastResults> {
|
||||
public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, ForecastResults>
|
||||
{
|
||||
|
||||
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
|
|
@ -86,8 +85,8 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
|
||||
|
||||
/**
|
||||
* @param forecastTask
|
||||
* @description: 自动洪水预测
|
||||
* @param forecastTask
|
||||
* @return: java.util.List<com.gunshi.model.vo.FloodAlgorithemVo>
|
||||
* @auther: cxw
|
||||
* @date: 2024-07-30, 周二, 14:40:45
|
||||
|
|
@ -99,8 +98,8 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
/**
|
||||
* @param forecastTask
|
||||
* @description: 获取人工交互洪水预报结果
|
||||
* @param forecastTask
|
||||
* @return: java.util.List<com.gunshi.project.xyt.entity.vo.ForecastResultVo>
|
||||
* @auther: cxw
|
||||
* @date: 2024-07-31, 周三, 11:09:24
|
||||
|
|
@ -124,19 +123,9 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
return voList;
|
||||
}
|
||||
|
||||
private Date addMinites(Date date, Integer minite) {
|
||||
Instant instant = date.toInstant().plus(minite, ChronoUnit.MINUTES);
|
||||
return Date.from(instant);
|
||||
}
|
||||
|
||||
private Date deleteMinites(Date date, Integer minite) {
|
||||
Instant instant = date.toInstant().minus(minite, ChronoUnit.MINUTES);
|
||||
return Date.from(instant);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param forecastTask
|
||||
* @description: 组装洪水预报ForecastResultVo
|
||||
* @param forecastTask
|
||||
* @return: java.util.List<com.gunshi.project.xyt.entity.vo.ForecastResultVo>
|
||||
* @auther: cxw
|
||||
* @date: 2024-08-05, 周一, 17:14:52
|
||||
|
|
@ -160,8 +149,6 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
Date nowHourTime = forecastTask.getNowTime();
|
||||
Date startTime = forecastTask.getStartTime();
|
||||
Date endTime = forecastTask.getEndTime();
|
||||
//TODO 由于endTime为整点数据,而监测时间为整点数据过五分
|
||||
endTime = addMinites(endTime, 5);
|
||||
// 获取整个时间线的降雨数据
|
||||
List<StPptnR> pptnRAllList = new ArrayList<>();
|
||||
List<StPptnR> pptnRFutureList = new ArrayList<>();
|
||||
|
|
@ -196,7 +183,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
// 获取预报数据
|
||||
try {
|
||||
pptnRFutureList = getForecastDrpData(nowHourTime, attResBase.getStcd());
|
||||
if (CollectionUtils.isEmpty(pptnRFutureList)) {
|
||||
if(CollectionUtils.isEmpty(pptnRFutureList)) {
|
||||
isHaveFuturePPtn = false;
|
||||
log.error("该时间无预报数据");
|
||||
}
|
||||
|
|
@ -270,11 +257,6 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
List<StZvarlB> zvarlBS = stZvarlBService.list(new QueryWrapper<StZvarlB>().eq("stcd", attResBase.getStcd()).orderBy(true, true, "rz"));
|
||||
// 水位历史数据
|
||||
List<StRsvrR> rsvrRRealList = stRsvrRService.list(new QueryWrapper<StRsvrR>().eq("stcd", attResBase.getStcd()).ge("tm", startTime).le("tm", endTime));
|
||||
//TODO 将过五分数据转为整点数据
|
||||
rsvrRRealList.stream().forEach(o -> {
|
||||
// 转换为 Instant 操作后再转回 Date
|
||||
o.setTm(deleteMinites(o.getTm(), 5));
|
||||
});
|
||||
List<StRsvrR> resultList = reorganizeRsvrRData(rsvrRRealList, dt);
|
||||
List<Date[]> periods = splitByDay8To8(startTime, endTime);
|
||||
// v:累计降雨
|
||||
|
|
@ -334,7 +316,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
for (int i = voList.size() - 1; i >= 0; i--) {
|
||||
int index = lastRArr.size() - 1 - (voList.size() - 1 - i);
|
||||
lastRArr.set(index, voList.get(i).getR().doubleValue());
|
||||
if (index <= 0) {
|
||||
if(index <= 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -422,6 +404,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
|
||||
|
||||
private List<Map<String, Object>> excuteForecastDebug(ForecastTask forecastTask) throws Exception {
|
||||
List<ForecastResultVo> voList = new ArrayList<>();
|
||||
// 获取配置参数
|
||||
|
|
@ -475,7 +458,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
// 获取预报数据
|
||||
try {
|
||||
pptnRFutureList = getForecastDrpData(nowHourTime, attResBase.getStcd());
|
||||
if (CollectionUtils.isEmpty(pptnRFutureList)) {
|
||||
if(CollectionUtils.isEmpty(pptnRFutureList)) {
|
||||
isHaveFuturePPtn = false;
|
||||
log.error("该时间无预报数据");
|
||||
}
|
||||
|
|
@ -609,13 +592,13 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
for (int i = voList.size() - 1; i >= 0; i--) {
|
||||
int index = lastRArr.size() - 1 - (voList.size() - 1 - i);
|
||||
lastRArr.set(index, voList.get(i).getR().doubleValue());
|
||||
if (index <= 0) {
|
||||
if(index <= 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 预测执行
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
Map<String,Object> map = new HashMap<>();
|
||||
map.put("in period" + k, sdf.format(period[0]));
|
||||
map.put("in K" + k, forecastPa.getK().doubleValue());
|
||||
map.put("in pa0" + k, forecastPa.getPa0().doubleValue());
|
||||
|
|
@ -715,24 +698,24 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
/**
|
||||
* @description: 根据水位计算库容
|
||||
* @param zvarlBS 库容曲线
|
||||
* @param resultVo vo
|
||||
* @param rz 当前水位
|
||||
* @description: 根据水位计算库容
|
||||
* @return: void
|
||||
* @auther: cxw
|
||||
* @date: 2024-10-14, 周一, 09:36:13
|
||||
*/
|
||||
private void calculateCap(List<StZvarlB> zvarlBS, ForecastResultVo resultVo, BigDecimal rz) {
|
||||
if (CollectionUtils.isNotEmpty(zvarlBS)) {
|
||||
private void calculateCap(List<StZvarlB> zvarlBS, ForecastResultVo resultVo, BigDecimal rz){
|
||||
if(CollectionUtils.isNotEmpty(zvarlBS)){
|
||||
BigDecimal maxRz = zvarlBS.stream().max(Comparator.comparing(StZvarlB::getRz)).get().getRz();
|
||||
BigDecimal minRz = zvarlBS.stream().min(Comparator.comparing(StZvarlB::getRz)).get().getRz();
|
||||
if (rz.compareTo(minRz) < 0 || rz.compareTo(maxRz) > 0) {
|
||||
if(rz.compareTo(minRz) < 0 || rz.compareTo(maxRz) > 0){
|
||||
return;
|
||||
}
|
||||
Map<BigDecimal, BigDecimal> stZvalMap = zvarlBS.stream().collect(Collectors.toMap(StZvarlB::getRz, StZvarlB::getW, (existing, replacement) -> existing));
|
||||
List<BigDecimal> list = zvarlBS.stream().map(StZvarlB::getRz).sorted().collect(Collectors.toList());
|
||||
resultVo.setNowCap(DataHandleUtil.calcData(rz, stZvalMap, list));
|
||||
resultVo.setNowCap(DataHandleUtil.calcData(rz,stZvalMap,list));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -764,7 +747,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
tm = tm.replaceAll(" ", "").replaceAll("-", "");
|
||||
List<RainGrib2Layer> gribList = forecastService.getGribData(tm, false);
|
||||
if (CollectionUtils.isEmpty(gribList)) {
|
||||
if(CollectionUtils.isEmpty(gribList)){
|
||||
return pptnRFutureList;
|
||||
}
|
||||
//24小时每个网格的总量
|
||||
|
|
@ -797,9 +780,9 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
/**
|
||||
* @description: 根据△T来整编实际水位数据
|
||||
* @param rsvrRRealList
|
||||
* @param dt
|
||||
* @description: 根据△T来整编实际水位数据
|
||||
* @return: java.util.List<com.gunshi.project.xyt.model.StRsvrR>
|
||||
* @auther: cxw
|
||||
*/
|
||||
|
|
@ -854,13 +837,13 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
/**
|
||||
* @description: 根据△T来整编雨量数据
|
||||
* @param filterList
|
||||
* @param dt
|
||||
* @param startTm
|
||||
* @param endTm
|
||||
* @param nowHourTime
|
||||
* @param isHaveFuturePPtn
|
||||
* @description: 根据△T来整编雨量数据
|
||||
* @return: java.util.List<com.gunshi.project.xyt.model.StPptnR>
|
||||
* @auther: cxw
|
||||
*/
|
||||
|
|
@ -886,7 +869,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
// 使用时间一直往后加时间
|
||||
while (dataTm.compareTo(endTm) < 0) {
|
||||
// 当数据时间超过实时数据的最大时间并且没有预测雨量数据时,跳出
|
||||
if (dataTm.compareTo(nowHourTime) >= 0 && !isHaveFuturePPtn) {
|
||||
if(dataTm.compareTo(nowHourTime) >= 0 && !isHaveFuturePPtn){
|
||||
break;
|
||||
}
|
||||
// 时间加1小时,得到应该拆数据的时间,后面往前推
|
||||
|
|
@ -925,7 +908,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
calendar.add(Calendar.MINUTE, -(int) (dt * 60));
|
||||
stPptnRHalfForecast.setTm(calendar.getTime());
|
||||
stPptnRHalfReal.setTm(calendar.getTime());
|
||||
if (BigDecimal.ONE.compareTo(BigDecimal.valueOf(dt)) != 0) {
|
||||
if(BigDecimal.ONE.compareTo(BigDecimal.valueOf(dt)) != 0){
|
||||
// 存半小时数据
|
||||
stPptnRHalfForecast.setDrp("0.00");
|
||||
listForForecast.add(stPptnRHalfForecast);
|
||||
|
|
@ -948,10 +931,10 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
/**
|
||||
* @description: 将两个时间按照早八点分割成多段
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @description: 将两个时间按照早八点分割成多段
|
||||
* @return: java.util.List<java.util.Date [ ]>
|
||||
* @return: java.util.List<java.util.Date[]>
|
||||
* @auther: cxw
|
||||
*/
|
||||
public static List<Date[]> splitByDay8To8(Date startDate, Date endDate) {
|
||||
|
|
@ -1011,21 +994,21 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
/**
|
||||
* @param forecastProject
|
||||
* @description: 处理voList,获取预报最大属性值
|
||||
* @param forecastProject
|
||||
* @return: void
|
||||
* @auther: cxw
|
||||
* @date: 2024-08-07, 周三, 15:52:19
|
||||
*/
|
||||
public void handleVoList(ForecastProject forecastProject) {
|
||||
Map<String, Object> paramMap = forecastUseparamService.getMap(new QueryWrapper<ForecastUseparam>().eq("param_code", "dt"));
|
||||
if (paramMap != null) {
|
||||
if(paramMap != null){
|
||||
BigDecimal dt = new BigDecimal(paramMap.get("param_value").toString());// 时间间隔:小时h
|
||||
BigDecimal ycMaxSwH = BigDecimal.ZERO;// 预报最高调洪水位
|
||||
BigDecimal ycMaxRkQ = BigDecimal.ZERO;// 预报最大入库流量
|
||||
BigDecimal ycMaxCkQ = BigDecimal.ZERO;// 预报最大下泄流量
|
||||
BigDecimal ycSumRkQ = BigDecimal.ZERO;// 预报入库流量累计和
|
||||
for (ForecastResultVo vo : forecastProject.getVoList()) {
|
||||
for (ForecastResultVo vo : forecastProject.getVoList()){
|
||||
BigDecimal ycSwHValue = vo.getYcSwHValue();
|
||||
if (ycSwHValue.compareTo(ycMaxSwH) > 0) {
|
||||
ycMaxSwH = ycSwHValue;
|
||||
|
|
@ -1053,7 +1036,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
// x1,y1和x2,y2的间隔必须要大于网格的最小长宽,才能相交
|
||||
BigDecimal dh = layer.getDh();// 单位高度
|
||||
BigDecimal dw = layer.getDw();// 单位宽度
|
||||
if (dw.compareTo(BigDecimal.valueOf(x2 - x1)) > 0 || dh.compareTo(BigDecimal.valueOf(y2 - y1)) > 0) {
|
||||
if(dw.compareTo(BigDecimal.valueOf(x2 - x1)) > 0 || dh.compareTo(BigDecimal.valueOf(y2 - y1)) > 0){
|
||||
throw new IllegalArgumentException("Geom参数区域范围不足预测降雨网格最小单位!!!");
|
||||
}
|
||||
// 校验数据是否在最大允许范围(预测降雨所划定区域)
|
||||
|
|
@ -1203,12 +1186,12 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
|
||||
try {
|
||||
BigDecimal result;
|
||||
// 根据方程的形式判断阶数并计算
|
||||
if (cleanEquation.contains("x^4")) {
|
||||
// 根据方程的形式判断阶数并计算(支持数学符号和传统符号)
|
||||
if (cleanEquation.contains("x⁴") || cleanEquation.contains("x^4")) {
|
||||
result = calculateFourthOrder(cleanEquation, x);
|
||||
} else if (cleanEquation.contains("x^3")) {
|
||||
} else if (cleanEquation.contains("x³") || cleanEquation.contains("x^3")) {
|
||||
result = calculateThirdOrder(cleanEquation, x);
|
||||
} else if (cleanEquation.contains("x^2")) {
|
||||
} else if (cleanEquation.contains("x²") || cleanEquation.contains("x^2")) {
|
||||
result = calculateSecondOrder(cleanEquation, x);
|
||||
} else {
|
||||
result = calculateFirstOrder(cleanEquation, x);
|
||||
|
|
@ -1221,7 +1204,6 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 计算一阶线性方程 y = ax + b
|
||||
*/
|
||||
|
|
@ -1239,63 +1221,69 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
/**
|
||||
* 计算二阶方程 y = ax^2 + bx + c
|
||||
* 计算二阶方程 y = ax² + bx + c
|
||||
*/
|
||||
private BigDecimal calculateSecondOrder(String equation, BigDecimal x) {
|
||||
// 解析方程系数,格式如:-68.4211x^2+16312.8684x-972224.1397
|
||||
String[] parts = equation.split("x");
|
||||
// 解析方程系数,格式如:-68.4211x²+16312.8684x-972224.1397
|
||||
// 支持两种格式:x² 和 x^2
|
||||
String normalizedEquation = equation.replace("x^2", "x²");
|
||||
String[] parts = normalizedEquation.split("x");
|
||||
if (parts.length < 3) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
BigDecimal a = parseCoefficient(parts[0]);
|
||||
BigDecimal b = parseCoefficient(parts[1].replace("^2", ""));
|
||||
BigDecimal b = parseCoefficient(parts[1].replace("²", ""));
|
||||
BigDecimal c = parseCoefficient(parts[2]);
|
||||
|
||||
BigDecimal x2 = x.multiply(x); // x^2
|
||||
BigDecimal x2 = x.multiply(x); // x²
|
||||
return a.multiply(x2).add(b.multiply(x)).add(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算三阶方程 y = ax^3 + bx^2 + cx + d
|
||||
* 计算三阶方程 y = ax³ + bx² + cx + d
|
||||
*/
|
||||
private BigDecimal calculateThirdOrder(String equation, BigDecimal x) {
|
||||
// 解析方程系数,格式如:-2291.6667x^3+819497.9167x^2-97683901.8750x+3881297151.1650
|
||||
String[] parts = equation.split("x");
|
||||
// 解析方程系数,格式如:-2291.6667x³+819497.9167x²-97683901.8750x+3881297151.1650
|
||||
// 支持两种格式:x³ 和 x^3, x² 和 x^2
|
||||
String normalizedEquation = equation.replace("x^3", "x³").replace("x^2", "x²");
|
||||
String[] parts = normalizedEquation.split("x");
|
||||
if (parts.length < 4) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
BigDecimal a = parseCoefficient(parts[0]);
|
||||
BigDecimal b = parseCoefficient(parts[1].replace("^3", "").replace("^2", ""));
|
||||
BigDecimal c = parseCoefficient(parts[2].replace("^2", ""));
|
||||
BigDecimal b = parseCoefficient(parts[1].replace("³", "").replace("²", ""));
|
||||
BigDecimal c = parseCoefficient(parts[2].replace("²", ""));
|
||||
BigDecimal d = parseCoefficient(parts[3]);
|
||||
|
||||
BigDecimal x2 = x.multiply(x); // x^2
|
||||
BigDecimal x3 = x2.multiply(x); // x^3
|
||||
BigDecimal x2 = x.multiply(x); // x²
|
||||
BigDecimal x3 = x2.multiply(x); // x³
|
||||
|
||||
return a.multiply(x3).add(b.multiply(x2)).add(c.multiply(x)).add(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算四阶方程 y = ax^4 + bx^3 + cx^2 + dx + e
|
||||
* 计算四阶方程 y = ax⁴ + bx³ + cx² + dx + e
|
||||
*/
|
||||
private BigDecimal calculateFourthOrder(String equation, BigDecimal x) {
|
||||
// 解析方程系数,格式如:-5.9039x^4+523.5482x^3+316095.2736x^2-57676816.2672x+2688986002.6804
|
||||
String[] parts = equation.split("x");
|
||||
// 解析方程系数,格式如:-5.9039x⁴+523.5482x³+316095.2736x²-57676816.2672x+2688986002.6804
|
||||
// 支持两种格式:x⁴ 和 x^4, x³ 和 x^3, x² 和 x^2
|
||||
String normalizedEquation = equation.replace("x^4", "x⁴").replace("x^3", "x³").replace("x^2", "x²");
|
||||
String[] parts = normalizedEquation.split("x");
|
||||
if (parts.length < 5) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
BigDecimal a = parseCoefficient(parts[0]);
|
||||
BigDecimal b = parseCoefficient(parts[1].replace("^4", "").replace("^3", ""));
|
||||
BigDecimal c = parseCoefficient(parts[2].replace("^3", "").replace("^2", ""));
|
||||
BigDecimal d = parseCoefficient(parts[3].replace("^2", ""));
|
||||
BigDecimal b = parseCoefficient(parts[1].replace("⁴", "").replace("³", ""));
|
||||
BigDecimal c = parseCoefficient(parts[2].replace("³", "").replace("²", ""));
|
||||
BigDecimal d = parseCoefficient(parts[3].replace("²", ""));
|
||||
BigDecimal e = parseCoefficient(parts[4]);
|
||||
|
||||
BigDecimal x2 = x.multiply(x); // x^2
|
||||
BigDecimal x3 = x2.multiply(x); // x^3
|
||||
BigDecimal x4 = x3.multiply(x); // x^4
|
||||
BigDecimal x2 = x.multiply(x); // x²
|
||||
BigDecimal x3 = x2.multiply(x); // x³
|
||||
BigDecimal x4 = x3.multiply(x); // x⁴
|
||||
|
||||
return a.multiply(x4).add(b.multiply(x3)).add(c.multiply(x2)).add(d.multiply(x)).add(e);
|
||||
}
|
||||
|
|
@ -1313,7 +1301,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
coeffStr += "1";
|
||||
}
|
||||
|
||||
// 处理没有显式数字的情况,如:x^2+x+1 中的第一个x系数为1
|
||||
// 处理没有显式数字的情况,如:x²+x+1 中的第一个x系数为1
|
||||
if (coeffStr.equals("")) {
|
||||
return BigDecimal.ONE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,10 +19,7 @@ import com.gunshi.project.hsz.common.mapper.JcskSlBMapper;
|
|||
import com.gunshi.project.hsz.mapper.JcskSyREightAmMapper;
|
||||
import com.gunshi.project.hsz.common.mapper.JcskSyRMapper;
|
||||
import com.gunshi.project.hsz.common.model.JcskSyB;
|
||||
import com.gunshi.project.hsz.model.AttResBase;
|
||||
import com.gunshi.project.hsz.model.JcskSyREightAm;
|
||||
import com.gunshi.project.hsz.model.RegressionEquation;
|
||||
import com.gunshi.project.hsz.model.SyRegressionData;
|
||||
import com.gunshi.project.hsz.model.*;
|
||||
import com.gunshi.project.hsz.util.*;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
|
@ -69,6 +66,9 @@ public class JcskSyRService extends ServiceImpl<JcskSyRMapper, JcskSyR> {
|
|||
@Autowired
|
||||
private SyRegressionDataService syRegressionDataService;
|
||||
|
||||
@Autowired
|
||||
private SyDataCheckRuleService syDataCheckRuleService;
|
||||
|
||||
|
||||
|
||||
public Page<JcskSyR> pageQuery(JcskSyRPageSo page) {
|
||||
|
|
@ -824,6 +824,9 @@ public class JcskSyRService extends ServiceImpl<JcskSyRMapper, JcskSyR> {
|
|||
//组合成为 时间 库水位 管道水位的数据
|
||||
List<OsmoticPressDetailVo> data = new ArrayList<>();
|
||||
for (JcskSyREightAm eightAm : jcskSyREightAms) {
|
||||
if(eightAm.getMstm() == null || eightAm.getSpprwl() == null){
|
||||
continue;
|
||||
}
|
||||
OsmoticPressDetailVo detailVo = new OsmoticPressDetailVo();
|
||||
|
||||
// 设置监测时间和监测值(管道水位)
|
||||
|
|
@ -833,7 +836,23 @@ public class JcskSyRService extends ServiceImpl<JcskSyRMapper, JcskSyR> {
|
|||
|
||||
// 查找对应的库水位
|
||||
BigDecimal rzValue = findClosestRzValue(rzMap, mstmStr);
|
||||
if(rzValue == null){
|
||||
continue;
|
||||
}
|
||||
detailVo.setRz(rzValue);
|
||||
//获取数据清洗规则
|
||||
SyDataCheckRule rule = syDataCheckRuleService.getByDvcd(dto.getDvcd());
|
||||
if(rule != null && rule.getIsAvailable() == 1){
|
||||
//校验这条数据是否符合规则
|
||||
if(rzValue.compareTo(rule.getRz()) >=0){
|
||||
//如果当前库水位大于等于设置库水位,则跳过这条数据
|
||||
continue;
|
||||
}
|
||||
if(eightAm.getSpprwl().compareTo(rule.getSyValue()) <=0){
|
||||
//如果当前监测值小于等于设置值,则跳过这套数据
|
||||
continue;
|
||||
}
|
||||
}
|
||||
data.add(detailVo);
|
||||
}
|
||||
if(data.isEmpty()){
|
||||
|
|
|
|||
|
|
@ -51,4 +51,10 @@ public class SyDataCheckRuleService extends ServiceImpl<SyDataCheckRuleMapper, S
|
|||
boolean flag = updateById(dto);
|
||||
return flag;
|
||||
}
|
||||
|
||||
public SyDataCheckRule getByDvcd(String dvcd) {
|
||||
LambdaQueryWrapper<SyDataCheckRule> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(SyDataCheckRule::getDvcd,dvcd);
|
||||
return this.baseMapper.selectOne(queryWrapper);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,19 +103,19 @@ public class PaDataTask {
|
|||
forecastPaService.remove(new QueryWrapper<ForecastPa>().eq("tm", sdfDay.format(nowTime)).eq("stcd", attResBase.getResCode()));
|
||||
// 获取最新pa
|
||||
ForecastPa forecastPaLast = forecastPaService.getOne(new QueryWrapper<ForecastPa>().eq("stcd", skStcd).orderBy(true, false, "tm").last("limit 1"));
|
||||
// 补数据时解开
|
||||
// if(ObjectUtils.isEmpty(forecastPaLast)){
|
||||
// forecastPaLast = new ForecastPa();
|
||||
// forecastPaLast.setStcd(skStcd);
|
||||
// forecastPaLast.setTm("2024-01-01");
|
||||
// forecastPaLast.setK(new BigDecimal(0.97));
|
||||
// forecastPaLast.setPa0(BigDecimal.ZERO);
|
||||
// forecastPaLast.setIm(new BigDecimal(120));
|
||||
// forecastPaLast.setPt0(BigDecimal.ZERO);
|
||||
// forecastPaLast.setPa(BigDecimal.ZERO);
|
||||
// forecastPaLast.setChtm(new Date());
|
||||
//
|
||||
// }
|
||||
// 补数据时解开
|
||||
if(ObjectUtils.isEmpty(forecastPaLast)){
|
||||
forecastPaLast = new ForecastPa();
|
||||
forecastPaLast.setStcd(skStcd);
|
||||
forecastPaLast.setTm("2024-01-01");
|
||||
forecastPaLast.setK(new BigDecimal(0.97));
|
||||
forecastPaLast.setPa0(BigDecimal.ZERO);
|
||||
forecastPaLast.setIm(new BigDecimal(120));
|
||||
forecastPaLast.setPt0(BigDecimal.ZERO);
|
||||
forecastPaLast.setPa(BigDecimal.ZERO);
|
||||
forecastPaLast.setChtm(new Date());
|
||||
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(paramList) && CollectionUtils.isNotEmpty(kList) && ObjectUtils.isNotEmpty(forecastPaLast) && !forecastPaLast.getTm().equals(sdfDay.format(nowTime))) {
|
||||
Calendar calendar2 = Calendar.getInstance();
|
||||
calendar2.setTime(sdfDay.parse(forecastPaLast.getTm()));
|
||||
|
|
|
|||
|
|
@ -584,6 +584,7 @@ public class RegressionAnalysis {
|
|||
return calculateCubic(data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将中心化四次系数转换回原始坐标
|
||||
*/
|
||||
|
|
@ -620,75 +621,6 @@ public class RegressionAnalysis {
|
|||
return new BigDecimal[]{A, B, C, D, E};
|
||||
}
|
||||
|
||||
/**
|
||||
* 改进的线性方程组求解器(部分主元高斯消元)
|
||||
* 用于解决n元一次方程组 Ax = b
|
||||
*/
|
||||
private static BigDecimal[] solveLinearSystemImproved(BigDecimal[][] matrix, BigDecimal[] vector) {
|
||||
int n = vector.length;
|
||||
|
||||
// 复制矩阵和向量(避免修改原数据)
|
||||
BigDecimal[][] a = new BigDecimal[n][n];
|
||||
BigDecimal[] b = new BigDecimal[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
a[i] = matrix[i].clone();
|
||||
b[i] = vector[i];
|
||||
}
|
||||
|
||||
// 部分主元高斯消元:逐行处理,选择当前列的最大绝对值元素作为主元
|
||||
for (int k = 0; k < n; k++) {
|
||||
// 找到当前列(k列)中绝对值最大的行(maxRow)
|
||||
int maxRow = k;
|
||||
BigDecimal maxVal = a[k][k].abs(); // 初始为当前对角线元素
|
||||
for (int i = k + 1; i < n; i++) {
|
||||
BigDecimal current = a[i][k].abs();
|
||||
if (current.compareTo(maxVal) > 0) {
|
||||
maxVal = current;
|
||||
maxRow = i;
|
||||
}
|
||||
}
|
||||
|
||||
// 交换行(将最大主元所在行交换到当前行k)
|
||||
if (maxRow != k) {
|
||||
BigDecimal[] tempRow = a[k];
|
||||
a[k] = a[maxRow];
|
||||
a[maxRow] = tempRow;
|
||||
|
||||
BigDecimal tempB = b[k];
|
||||
b[k] = b[maxRow];
|
||||
b[maxRow] = tempB;
|
||||
}
|
||||
|
||||
// 检查主元是否为0(矩阵奇异)
|
||||
if (a[k][k].compareTo(BigDecimal.ZERO) == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 消元:将第k列下方的元素消为0
|
||||
for (int i = k + 1; i < n; i++) {
|
||||
BigDecimal factor = a[i][k].divide(a[k][k], MathContext.DECIMAL128); // 除法保留高精度
|
||||
for (int j = k; j < n; j++) {
|
||||
a[i][j] = a[i][j].subtract(factor.multiply(a[k][j], MathContext.DECIMAL128), MathContext.DECIMAL128);
|
||||
}
|
||||
b[i] = b[i].subtract(factor.multiply(b[k], MathContext.DECIMAL128), MathContext.DECIMAL128);
|
||||
}
|
||||
}
|
||||
|
||||
// 回代:从最后一行开始,依次求解每个变量
|
||||
BigDecimal[] x = new BigDecimal[n];
|
||||
for (int i = n - 1; i >= 0; i--) {
|
||||
BigDecimal sum = BigDecimal.ZERO;
|
||||
for (int j = i + 1; j < n; j++) {
|
||||
sum = sum.add(a[i][j].multiply(x[j], MathContext.DECIMAL128), MathContext.DECIMAL128);
|
||||
}
|
||||
x[i] = b[i].subtract(sum, MathContext.DECIMAL128)
|
||||
.divide(a[i][i], MathContext.DECIMAL128); // 除法保留高精度
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 计算R²
|
||||
|
|
@ -717,7 +649,6 @@ public class RegressionAnalysis {
|
|||
return BigDecimal.ONE.subtract(ssRes.divide(ssTot, MathContext.DECIMAL128), MathContext.DECIMAL128);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查所有数据点的x值是否相同
|
||||
*/
|
||||
|
|
@ -744,4 +675,73 @@ public class RegressionAnalysis {
|
|||
return sum.divide(new BigDecimal(data.size()), MathContext.DECIMAL128);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成回归方程字符串(使用数学符号表示)
|
||||
*/
|
||||
public static String generateEquationString(int order, List<BigDecimal> coefficients) {
|
||||
StringBuilder sb = new StringBuilder("y = ");
|
||||
|
||||
for (int i = 0; i < coefficients.size(); i++) {
|
||||
BigDecimal coeff = coefficients.get(i);
|
||||
if (coeff.compareTo(BigDecimal.ZERO) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理符号
|
||||
if (i > 0) {
|
||||
if (coeff.compareTo(BigDecimal.ZERO) > 0) {
|
||||
sb.append(" + ");
|
||||
} else {
|
||||
sb.append(" - ");
|
||||
coeff = coeff.abs();
|
||||
}
|
||||
}
|
||||
|
||||
// 处理系数
|
||||
if (i == 0 || coeff.compareTo(BigDecimal.ONE) != 0) {
|
||||
// 格式化系数,避免科学计数法
|
||||
String coeffStr = coeff.toPlainString();
|
||||
// 去除不必要的尾随零
|
||||
if (coeffStr.contains(".")) {
|
||||
coeffStr = coeffStr.replaceAll("0+$", "").replaceAll("\\.$", "");
|
||||
}
|
||||
sb.append(coeffStr);
|
||||
}
|
||||
|
||||
// 处理x的幂次
|
||||
if (i > 0) {
|
||||
sb.append("x");
|
||||
if (i > 1) {
|
||||
// 使用Unicode上标数字
|
||||
sb.append(getSuperscript(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数字的Unicode上标表示
|
||||
*/
|
||||
private static String getSuperscript(int number) {
|
||||
String numStr = String.valueOf(number);
|
||||
StringBuilder superscript = new StringBuilder();
|
||||
for (char c : numStr.toCharArray()) {
|
||||
switch (c) {
|
||||
case '0': superscript.append('⁰'); break;
|
||||
case '1': superscript.append('¹'); break;
|
||||
case '2': superscript.append('²'); break;
|
||||
case '3': superscript.append('³'); break;
|
||||
case '4': superscript.append('⁴'); break;
|
||||
case '5': superscript.append('⁵'); break;
|
||||
case '6': superscript.append('⁶'); break;
|
||||
case '7': superscript.append('⁷'); break;
|
||||
case '8': superscript.append('⁸'); break;
|
||||
case '9': superscript.append('⁹'); break;
|
||||
default: superscript.append(c);
|
||||
}
|
||||
}
|
||||
return superscript.toString();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue