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