parent
cfd8dda870
commit
bc008b0174
|
|
@ -11,6 +11,7 @@ import com.gunshi.project.hsz.common.model.so.JcskSyRPageSo;
|
||||||
import com.gunshi.project.hsz.common.model.so.OsmoticDetailQuerySo;
|
import com.gunshi.project.hsz.common.model.so.OsmoticDetailQuerySo;
|
||||||
import com.gunshi.project.hsz.common.model.so.OsmoticDetailQuerySo;
|
import com.gunshi.project.hsz.common.model.so.OsmoticDetailQuerySo;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
@ -362,4 +363,25 @@ GROUP BY dm
|
||||||
</script>
|
</script>
|
||||||
""")
|
""")
|
||||||
Page<JcskSyR> artificialPage(Page<Object> page,@Param("dto") JcskSyRPageSo page1);
|
Page<JcskSyR> artificialPage(Page<Object> page,@Param("dto") JcskSyRPageSo page1);
|
||||||
|
|
||||||
|
@Select("""
|
||||||
|
WITH ranked_data AS (
|
||||||
|
SELECT
|
||||||
|
tm,
|
||||||
|
rz,
|
||||||
|
ABS(EXTRACT(HOUR FROM tm) + EXTRACT(MINUTE FROM tm)/60.0 - 8) as time_diff,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY DATE(tm) ORDER BY ABS(EXTRACT(HOUR FROM tm) + EXTRACT(MINUTE FROM tm)/60.0 - 8)) as rn
|
||||||
|
FROM st_rsvr_r
|
||||||
|
WHERE stcd = #{stcd}
|
||||||
|
AND tm >= #{dto.dateTimeRangeSo.start}
|
||||||
|
AND tm <= #{dto.dateTimeRangeSo.end}
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
TO_CHAR(DATE(tm) + INTERVAL '8 hours', 'YYYY-MM-DD HH24:MI:SS') as tm,
|
||||||
|
rz
|
||||||
|
FROM ranked_data
|
||||||
|
WHERE rn = 1
|
||||||
|
ORDER BY tm
|
||||||
|
""")
|
||||||
|
List<StRzVo> qeury8AmRz(@Param("dto") OsmoticQuerySo dto, @Param("stcd") String stcd);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
package com.gunshi.project.hsz.controller;
|
||||||
|
|
||||||
|
import com.gunshi.core.result.R;
|
||||||
|
import com.gunshi.project.hsz.common.model.vo.OsmoticPressDetailVo;
|
||||||
|
import com.gunshi.project.hsz.entity.dto.ProjectSafeCalculateDto;
|
||||||
|
import com.gunshi.project.hsz.entity.dto.ProjectSaveReportDto;
|
||||||
|
import com.gunshi.project.hsz.entity.dto.SyRegressionDataDto;
|
||||||
|
import com.gunshi.project.hsz.entity.vo.ForecastResultVo;
|
||||||
|
import com.gunshi.project.hsz.model.ForecastTask;
|
||||||
|
import com.gunshi.project.hsz.model.RegressionEquation;
|
||||||
|
import com.gunshi.project.hsz.model.SyRegressionData;
|
||||||
|
import com.gunshi.project.hsz.service.ForecastResultsService;
|
||||||
|
import com.gunshi.project.hsz.service.JcskSyRService;
|
||||||
|
import com.gunshi.project.hsz.service.SyRegressionDataService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Tag(name = "工程安全监测")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(value="/projectSafe")
|
||||||
|
public class ProjectSafeAnalyseController {
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JcskSyRService jcskSyRService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SyRegressionDataService syRegressionDataService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ForecastResultsService forecastResultsService;
|
||||||
|
|
||||||
|
@Operation(summary = "多项式回归")
|
||||||
|
@PostMapping("/caculate")
|
||||||
|
public R<Map<String, RegressionEquation>> calculate(@RequestBody ProjectSafeCalculateDto dto){
|
||||||
|
Map<String, RegressionEquation> ans = jcskSyRService.calculate(dto);
|
||||||
|
return R.ok(ans);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "预报")
|
||||||
|
@PostMapping("/report")
|
||||||
|
public R<List<OsmoticPressDetailVo>> report(@RequestBody ProjectSaveReportDto projectSaveReportDto){
|
||||||
|
ForecastTask forecastTask = projectSaveReportDto.getForecastTask();
|
||||||
|
List<ForecastResultVo> voList = forecastResultsService.getHumanForecastResult(forecastTask);
|
||||||
|
SyRegressionData syRegressionData = new SyRegressionData();
|
||||||
|
syRegressionData.setDvcd(projectSaveReportDto.getDvcd());
|
||||||
|
syRegressionData.setOrder(projectSaveReportDto.getOrder());
|
||||||
|
List<SyRegressionData> queryReg = syRegressionDataService.queryData(syRegressionData);//获取方程组
|
||||||
|
if(queryReg.isEmpty()){
|
||||||
|
return R.ok(null);
|
||||||
|
}
|
||||||
|
//计算
|
||||||
|
List<OsmoticPressDetailVo> res = forecastResultsService.calculateY(queryReg.get(0),voList);
|
||||||
|
return R.ok(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "保存多线程回归方程")
|
||||||
|
@PostMapping("/save")
|
||||||
|
public R<Boolean> save(@RequestBody SyRegressionDataDto dto){
|
||||||
|
if(!dto.getList().isEmpty()){
|
||||||
|
syRegressionDataService.saveBatch(dto.getList());
|
||||||
|
}
|
||||||
|
return R.ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "删除多线程回归方程")
|
||||||
|
@PostMapping("/del")
|
||||||
|
public R<Boolean> delete(@RequestBody SyRegressionDataDto dto){
|
||||||
|
if(!dto.getList().isEmpty()){
|
||||||
|
syRegressionDataService.removeBatchByIds(dto.getList());
|
||||||
|
}
|
||||||
|
return R.ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "查找多线程回归方程")
|
||||||
|
public R<List<SyRegressionData>> list(@RequestBody SyRegressionData dto){
|
||||||
|
List<SyRegressionData> res = syRegressionDataService.queryData(dto);
|
||||||
|
return R.ok(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
package com.gunshi.project.hsz.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.gunshi.core.result.R;
|
||||||
|
import com.gunshi.project.hsz.common.model.JcskGnssR;
|
||||||
|
import com.gunshi.project.hsz.common.model.JcskSyB;
|
||||||
|
import com.gunshi.project.hsz.common.model.so.JcskGnssRPageSo;
|
||||||
|
import com.gunshi.project.hsz.common.validate.markers.Insert;
|
||||||
|
import com.gunshi.project.hsz.common.validate.markers.Update;
|
||||||
|
import com.gunshi.project.hsz.entity.so.SyDataCheckRulePageSo;
|
||||||
|
import com.gunshi.project.hsz.model.SyDataCheckRule;
|
||||||
|
import com.gunshi.project.hsz.service.SyDataCheckRuleService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Tag(name = "渗压数据清洗规则")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(value="/syDataCheckRule")
|
||||||
|
public class SyDataCheckRuleController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SyDataCheckRuleService syDataCheckRuleService;
|
||||||
|
|
||||||
|
|
||||||
|
@Operation(summary = "分页")
|
||||||
|
@PostMapping("/page")
|
||||||
|
public R<Page<SyDataCheckRule>> page(@RequestBody @Validated SyDataCheckRulePageSo page) {
|
||||||
|
return R.ok(syDataCheckRuleService.pageQuery(page));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Operation(summary = "新增")
|
||||||
|
@PostMapping("/insert")
|
||||||
|
public R<SyDataCheckRule> insert(@Validated(Insert.class) @RequestBody SyDataCheckRule dto) {
|
||||||
|
return R.ok(syDataCheckRuleService.saveData(dto));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "修改")
|
||||||
|
@PostMapping("/update")
|
||||||
|
public R<Boolean> update(@Validated(Update.class) @RequestBody SyDataCheckRule dto) {
|
||||||
|
return R.ok(syDataCheckRuleService.updateData(dto));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "删除")
|
||||||
|
@GetMapping("/del/{id}")
|
||||||
|
public R<Boolean> del(@Schema(name = "id") @PathVariable("id") Serializable id) {
|
||||||
|
if (Objects.isNull(syDataCheckRuleService.getById(id))) {
|
||||||
|
throw new IllegalArgumentException("当前数据不存在");
|
||||||
|
}
|
||||||
|
return R.ok(syDataCheckRuleService.removeById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.gunshi.project.hsz.entity.dto;
|
||||||
|
|
||||||
|
import com.gunshi.db.dto.DateTimeRangeSo;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ProjectSafeCalculateDto {
|
||||||
|
|
||||||
|
|
||||||
|
private DateTimeRangeSo dateTimeRangeSo;//时间范围
|
||||||
|
|
||||||
|
private String dvcd;//测点编号
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.gunshi.project.hsz.entity.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import com.gunshi.project.hsz.model.ForecastTask;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ProjectSaveReportDto {
|
||||||
|
|
||||||
|
private ForecastTask forecastTask;
|
||||||
|
|
||||||
|
private String dvcd;
|
||||||
|
|
||||||
|
private Integer order;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.gunshi.project.hsz.entity.dto;
|
||||||
|
|
||||||
|
import com.gunshi.project.hsz.model.SyRegressionData;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SyRegressionDataDto {
|
||||||
|
|
||||||
|
|
||||||
|
List<SyRegressionData> list;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.gunshi.project.hsz.entity.so;
|
||||||
|
|
||||||
|
|
||||||
|
import com.gunshi.db.dto.PageSo;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SyDataCheckRulePageSo {
|
||||||
|
|
||||||
|
|
||||||
|
@NotNull(message = "分页参数不能为空")
|
||||||
|
@Schema(description = "分页参数")
|
||||||
|
private PageSo pageSo;
|
||||||
|
|
||||||
|
private String dvcd;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.gunshi.project.hsz.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.gunshi.project.hsz.model.SyDataCheckRule;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface SyDataCheckRuleMapper extends BaseMapper<SyDataCheckRule> {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.gunshi.project.hsz.mapper;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.gunshi.project.hsz.model.SyRegressionData;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface SyRegressionDataMapper extends BaseMapper<SyRegressionData> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
package com.gunshi.project.hsz.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线性回归方程实体类
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class RegressionEquation {
|
||||||
|
/**
|
||||||
|
* 方程阶数
|
||||||
|
*/
|
||||||
|
private int order;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方程系数(从常数项到最高次项)
|
||||||
|
* 例如:对于二次方程 y = ax² + bx + c,coefficients = [c, b, a]
|
||||||
|
*/
|
||||||
|
private List<BigDecimal> coefficients;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相关系数 R²
|
||||||
|
*/
|
||||||
|
private BigDecimal rSquared;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据点数
|
||||||
|
*/
|
||||||
|
private int dataCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方程字符串表示
|
||||||
|
*/
|
||||||
|
private String equationString;
|
||||||
|
|
||||||
|
public RegressionEquation(int order, List<BigDecimal> coefficients, BigDecimal rSquared, int dataCount) {
|
||||||
|
this.order = order;
|
||||||
|
this.coefficients = coefficients;
|
||||||
|
this.rSquared = rSquared;
|
||||||
|
this.dataCount = dataCount;
|
||||||
|
this.equationString = generateEquationString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成方程字符串
|
||||||
|
*/
|
||||||
|
private String generateEquationString() {
|
||||||
|
StringBuilder sb = new StringBuilder("y = ");
|
||||||
|
|
||||||
|
for (int i = coefficients.size() - 1; i >= 0; i--) {
|
||||||
|
BigDecimal coeff = coefficients.get(i);
|
||||||
|
if (coeff.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 符号处理
|
||||||
|
if (sb.length() > 4 && coeff.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
sb.append(" + ");
|
||||||
|
} else if (sb.length() > 4 && coeff.compareTo(BigDecimal.ZERO) < 0) {
|
||||||
|
sb.append(" - ");
|
||||||
|
coeff = coeff.abs();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 系数和变量
|
||||||
|
if (i == 0) {
|
||||||
|
// 常数项
|
||||||
|
sb.append(String.format("%.4f", coeff));
|
||||||
|
} else {
|
||||||
|
// 非常数项
|
||||||
|
if (coeff.compareTo(BigDecimal.ONE) != 0 && coeff.compareTo(BigDecimal.ONE.negate()) != 0) {
|
||||||
|
sb.append(String.format("%.4f", coeff));
|
||||||
|
}
|
||||||
|
sb.append("x");
|
||||||
|
if (i > 1) {
|
||||||
|
sb.append("^").append(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据x值预测y值
|
||||||
|
*/
|
||||||
|
public BigDecimal predict(BigDecimal x) {
|
||||||
|
BigDecimal result = BigDecimal.ZERO;
|
||||||
|
BigDecimal xPower = BigDecimal.ONE;
|
||||||
|
|
||||||
|
for (int i = 0; i < coefficients.size(); i++) {
|
||||||
|
result = result.add(coefficients.get(i).multiply(xPower));
|
||||||
|
xPower = xPower.multiply(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("%s", equationString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.gunshi.project.hsz.model;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
|
import com.gunshi.project.hsz.common.validate.markers.Insert;
|
||||||
|
import com.gunshi.project.hsz.common.validate.markers.Update;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 描述: 数据检查规则表
|
||||||
|
* author: xusan
|
||||||
|
* date: 2024-12-19 10:00:00
|
||||||
|
*/
|
||||||
|
@Schema(description = "数据检查规则表")
|
||||||
|
@Data
|
||||||
|
@TableName("public.sy_data_check_rule")
|
||||||
|
public class SyDataCheckRule implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
@Schema(description = "id")
|
||||||
|
@NotNull(message = "id不能为空", groups = {Update.class})
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测点编号
|
||||||
|
*/
|
||||||
|
@TableField(value = "dvcd")
|
||||||
|
@Schema(description = "测点编号")
|
||||||
|
@NotBlank(message = "测点编号不能为空", groups = {Insert.class, Update.class})
|
||||||
|
@Size(max = 255, message = "测点编号最大长度要小于 255")
|
||||||
|
private String dvcd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 库水位大于多少
|
||||||
|
*/
|
||||||
|
@TableField(value = "rz")
|
||||||
|
@Schema(description = "库水位大于多少")
|
||||||
|
private BigDecimal rz;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渗压水位小于多少
|
||||||
|
*/
|
||||||
|
@TableField(value = "sy_value")
|
||||||
|
@Schema(description = "渗压水位小于多少")
|
||||||
|
private BigDecimal syValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用 0:否 1:是
|
||||||
|
*/
|
||||||
|
@TableField(value = "is_available")
|
||||||
|
@Schema(description = "是否启用 0:否 1:是")
|
||||||
|
private Integer isAvailable;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
package com.gunshi.project.hsz.model;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
|
import com.gunshi.core.dateformat.DateFormatString;
|
||||||
|
import com.gunshi.project.hsz.common.validate.markers.Insert;
|
||||||
|
import com.gunshi.project.hsz.common.validate.markers.Update;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 描述: 回归方程数据表
|
||||||
|
* author: xusan
|
||||||
|
* date: 2024-12-19 10:00:00
|
||||||
|
*/
|
||||||
|
@Schema(description = "回归方程数据表")
|
||||||
|
@Data
|
||||||
|
@TableName("public.sy_regression_data")
|
||||||
|
public class SyRegressionData implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
@Schema(description = "id")
|
||||||
|
@NotNull(message = "id不能为空", groups = {Update.class})
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测点编号
|
||||||
|
*/
|
||||||
|
@TableField(value = "dvcd")
|
||||||
|
@Schema(description = "测点编号")
|
||||||
|
@NotBlank(message = "测点编号不能为空", groups = {Insert.class, Update.class})
|
||||||
|
@Size(max = 50, message = "测点编号最大长度要小于 50")
|
||||||
|
private String dvcd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "starttime")
|
||||||
|
@Schema(description = "开始时间")
|
||||||
|
@NotNull(message = "开始时间不能为空", groups = {Insert.class, Update.class})
|
||||||
|
@JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8")
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "endtime")
|
||||||
|
@Schema(description = "结束时间")
|
||||||
|
@NotNull(message = "结束时间不能为空", groups = {Insert.class, Update.class})
|
||||||
|
@JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8")
|
||||||
|
private Date endTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回归方程
|
||||||
|
*/
|
||||||
|
@TableField(value = "regressionequation")
|
||||||
|
@Schema(description = "回归方程")
|
||||||
|
private String regressionEquation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序(一阶-四阶)
|
||||||
|
*/
|
||||||
|
@TableField(value = "_order")
|
||||||
|
@Schema(description = "排序(一阶-四阶)")
|
||||||
|
private Integer order;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间(如果表中有此字段可以添加)
|
||||||
|
*/
|
||||||
|
@TableField(value = "create_time")
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
@JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8")
|
||||||
|
private Date createTime;
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ import com.gunshi.model.vo.FloodAlgorithemVo;
|
||||||
import com.gunshi.project.hsz.common.model.StPptnR;
|
import com.gunshi.project.hsz.common.model.StPptnR;
|
||||||
import com.gunshi.project.hsz.common.model.StRsvrR;
|
import com.gunshi.project.hsz.common.model.StRsvrR;
|
||||||
import com.gunshi.project.hsz.common.model.StStbprpB;
|
import com.gunshi.project.hsz.common.model.StStbprpB;
|
||||||
|
import com.gunshi.project.hsz.common.model.vo.OsmoticPressDetailVo;
|
||||||
import com.gunshi.project.hsz.entity.vo.ForeRainStatVo;
|
import com.gunshi.project.hsz.entity.vo.ForeRainStatVo;
|
||||||
import com.gunshi.project.hsz.entity.vo.ForeRainTimeVo;
|
import com.gunshi.project.hsz.entity.vo.ForeRainTimeVo;
|
||||||
import com.gunshi.project.hsz.entity.vo.ForecastResultVo;
|
import com.gunshi.project.hsz.entity.vo.ForecastResultVo;
|
||||||
|
|
@ -24,6 +25,7 @@ import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
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.Instant;
|
||||||
|
|
@ -1137,4 +1139,195 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
||||||
}
|
}
|
||||||
return maps;
|
return maps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<OsmoticPressDetailVo> calculateY(SyRegressionData syRegressionData, List<ForecastResultVo> voList) {
|
||||||
|
//过滤出预测时间的数据
|
||||||
|
List<ForecastResultVo> collect = voList.stream().filter(o -> {
|
||||||
|
return o.getIspreDrp().equals("1");
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
//获取方程组
|
||||||
|
String regressionEquation = syRegressionData.getRegressionEquation();
|
||||||
|
List<OsmoticPressDetailVo> res = new ArrayList<>();
|
||||||
|
|
||||||
|
//进行计算
|
||||||
|
for (ForecastResultVo forecastResultVo : collect) {
|
||||||
|
// 获取预测水位值作为x
|
||||||
|
BigDecimal x = forecastResultVo.getYcSwHValue();
|
||||||
|
if (x == null) {
|
||||||
|
continue; // 如果x为空,跳过计算
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据回归方程计算y值
|
||||||
|
BigDecimal y = calculateRegressionValue(regressionEquation, x);
|
||||||
|
|
||||||
|
// 构建返回结果
|
||||||
|
OsmoticPressDetailVo detailVo = new OsmoticPressDetailVo();
|
||||||
|
detailVo.setTm(forecastResultVo.getTm()); // 监测时间
|
||||||
|
detailVo.setValue(y); // 计算得到的监测值
|
||||||
|
detailVo.setRz(x); // 库水位(使用预测水位值)
|
||||||
|
|
||||||
|
res.add(detailVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按时间升序排列
|
||||||
|
res.sort((o1, o2) -> {
|
||||||
|
if (o1.getTm() == null && o2.getTm() == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (o1.getTm() == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (o2.getTm() == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return o1.getTm().compareTo(o2.getTm());
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据回归方程计算y值
|
||||||
|
* @param equation 回归方程字符串
|
||||||
|
* @param x 自变量x的值
|
||||||
|
* @return 计算得到的y值
|
||||||
|
*/
|
||||||
|
private BigDecimal calculateRegressionValue(String equation, BigDecimal x) {
|
||||||
|
if (equation == null || equation.trim().isEmpty()) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理方程字符串,移除空格和y=
|
||||||
|
String cleanEquation = equation.replace("y =", "").replace(" ", "").toLowerCase();
|
||||||
|
|
||||||
|
try {
|
||||||
|
BigDecimal result;
|
||||||
|
// 根据方程的形式判断阶数并计算
|
||||||
|
if (cleanEquation.contains("x^4")) {
|
||||||
|
result = calculateFourthOrder(cleanEquation, x);
|
||||||
|
} else if (cleanEquation.contains("x^3")) {
|
||||||
|
result = calculateThirdOrder(cleanEquation, x);
|
||||||
|
} else if (cleanEquation.contains("x^2")) {
|
||||||
|
result = calculateSecondOrder(cleanEquation, x);
|
||||||
|
} else {
|
||||||
|
result = calculateFirstOrder(cleanEquation, x);
|
||||||
|
}
|
||||||
|
// 四舍五入保留两位小数
|
||||||
|
return result.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 计算异常时返回0
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算一阶线性方程 y = ax + b
|
||||||
|
*/
|
||||||
|
private BigDecimal calculateFirstOrder(String equation, BigDecimal x) {
|
||||||
|
// 解析方程系数,格式如:0.0455x+94.2395
|
||||||
|
String[] parts = equation.split("x");
|
||||||
|
if (parts.length < 2) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal a = parseCoefficient(parts[0]);
|
||||||
|
BigDecimal b = parseCoefficient(parts[1]);
|
||||||
|
|
||||||
|
return a.multiply(x).add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算二阶方程 y = ax^2 + bx + c
|
||||||
|
*/
|
||||||
|
private BigDecimal calculateSecondOrder(String equation, BigDecimal x) {
|
||||||
|
// 解析方程系数,格式如:-68.4211x^2+16312.8684x-972224.1397
|
||||||
|
String[] parts = equation.split("x");
|
||||||
|
if (parts.length < 3) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal a = parseCoefficient(parts[0]);
|
||||||
|
BigDecimal b = parseCoefficient(parts[1].replace("^2", ""));
|
||||||
|
BigDecimal c = parseCoefficient(parts[2]);
|
||||||
|
|
||||||
|
BigDecimal x2 = x.multiply(x); // x^2
|
||||||
|
return a.multiply(x2).add(b.multiply(x)).add(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算三阶方程 y = ax^3 + bx^2 + cx + d
|
||||||
|
*/
|
||||||
|
private BigDecimal calculateThirdOrder(String equation, BigDecimal x) {
|
||||||
|
// 解析方程系数,格式如:-2291.6667x^3+819497.9167x^2-97683901.8750x+3881297151.1650
|
||||||
|
String[] parts = equation.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 d = parseCoefficient(parts[3]);
|
||||||
|
|
||||||
|
BigDecimal x2 = x.multiply(x); // x^2
|
||||||
|
BigDecimal x3 = x2.multiply(x); // x^3
|
||||||
|
|
||||||
|
return a.multiply(x3).add(b.multiply(x2)).add(c.multiply(x)).add(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算四阶方程 y = ax^4 + bx^3 + cx^2 + 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");
|
||||||
|
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 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
|
||||||
|
|
||||||
|
return a.multiply(x4).add(b.multiply(x3)).add(c.multiply(x2)).add(d.multiply(x)).add(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析系数,处理正负号和数字格式
|
||||||
|
*/
|
||||||
|
private BigDecimal parseCoefficient(String coeffStr) {
|
||||||
|
if (coeffStr == null || coeffStr.isEmpty()) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理空字符串情况
|
||||||
|
if (coeffStr.equals("+") || coeffStr.equals("-")) {
|
||||||
|
coeffStr += "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理没有显式数字的情况,如:x^2+x+1 中的第一个x系数为1
|
||||||
|
if (coeffStr.equals("")) {
|
||||||
|
return BigDecimal.ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new BigDecimal(coeffStr);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// 如果解析失败,尝试处理特殊情况
|
||||||
|
if (coeffStr.equals("+")) {
|
||||||
|
return BigDecimal.ONE;
|
||||||
|
} else if (coeffStr.equals("-")) {
|
||||||
|
return BigDecimal.ONE.negate();
|
||||||
|
}
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,15 @@ import com.gunshi.project.hsz.entity.dto.ArtificialJcskSyDeleteDto;
|
||||||
import com.gunshi.project.hsz.common.model.so.JcskSyRPageSo;
|
import com.gunshi.project.hsz.common.model.so.JcskSyRPageSo;
|
||||||
import com.gunshi.project.hsz.common.model.so.OsmoticDetailQuerySo;
|
import com.gunshi.project.hsz.common.model.so.OsmoticDetailQuerySo;
|
||||||
import com.gunshi.project.hsz.common.model.so.OsmoticQuerySo;
|
import com.gunshi.project.hsz.common.model.so.OsmoticQuerySo;
|
||||||
|
import com.gunshi.project.hsz.entity.dto.ProjectSafeCalculateDto;
|
||||||
import com.gunshi.project.hsz.entity.vo.*;
|
import com.gunshi.project.hsz.entity.vo.*;
|
||||||
import com.gunshi.project.hsz.common.mapper.JcskSlBMapper;
|
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.JcskSyREightAm;
|
||||||
|
import com.gunshi.project.hsz.model.RegressionEquation;
|
||||||
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;
|
||||||
|
|
@ -30,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.Duration;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
|
|
@ -776,4 +781,98 @@ public class JcskSyRService extends ServiceImpl<JcskSyRMapper, JcskSyR> {
|
||||||
int delete = this.baseMapper.delete(queryWrapper);
|
int delete = this.baseMapper.delete(queryWrapper);
|
||||||
return delete > 0;
|
return delete > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AttResBaseService attResBaseService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多项式方程计算
|
||||||
|
* @param dto
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Map<String, RegressionEquation> calculate(ProjectSafeCalculateDto dto) {
|
||||||
|
LambdaQueryWrapper<JcskSyB> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
Map<String, RegressionEquation> res = new HashMap<>();
|
||||||
|
//根据dvcd查询stcd和mpcd
|
||||||
|
queryWrapper.eq(JcskSyB::getDvcd, dto.getDvcd());
|
||||||
|
JcskSyB jcskSyB = jcskSyBService.getBaseMapper().selectOne(queryWrapper);
|
||||||
|
String stcd = jcskSyB.getStcd();
|
||||||
|
String mpcd = jcskSyB.getMpcd();
|
||||||
|
//取得这个时间段得所有八点得数据
|
||||||
|
LambdaQueryWrapper<JcskSyREightAm> eightAmLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
eightAmLambdaQueryWrapper.eq(JcskSyREightAm::getStcd, stcd);
|
||||||
|
eightAmLambdaQueryWrapper.eq(JcskSyREightAm::getMpcd, mpcd);
|
||||||
|
eightAmLambdaQueryWrapper.ge(JcskSyREightAm::getMstm,dto.getDateTimeRangeSo().getStart());
|
||||||
|
eightAmLambdaQueryWrapper.le(JcskSyREightAm::getMstm,dto.getDateTimeRangeSo().getEnd());
|
||||||
|
eightAmLambdaQueryWrapper.orderByAsc(JcskSyREightAm::getMstm);
|
||||||
|
List<JcskSyREightAm> jcskSyREightAms = jcskSyREightAmMapper.selectList(eightAmLambdaQueryWrapper);
|
||||||
|
AttResBase attResBase = attResBaseService.list().get(0);
|
||||||
|
OsmoticQuerySo querySo = new OsmoticQuerySo();
|
||||||
|
querySo.setDateTimeRangeSo(dto.getDateTimeRangeSo());
|
||||||
|
List<StRzVo> stRzVos = baseMapper.qeury8AmRz(querySo,attResBase.getStcd());
|
||||||
|
Map<String, BigDecimal> rzMap = stRzVos.stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
StRzVo::getTm, // key: 时间
|
||||||
|
StRzVo::getRz, // value: 水位
|
||||||
|
(existing, replacement) -> existing // 如果key冲突,保留已存在的
|
||||||
|
));
|
||||||
|
//组合成为 时间 库水位 管道水位的数据
|
||||||
|
List<OsmoticPressDetailVo> data = new ArrayList<>();
|
||||||
|
for (JcskSyREightAm eightAm : jcskSyREightAms) {
|
||||||
|
OsmoticPressDetailVo detailVo = new OsmoticPressDetailVo();
|
||||||
|
|
||||||
|
// 设置监测时间和监测值(管道水位)
|
||||||
|
String mstmStr = eightAm.getMstm().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
detailVo.setTm(mstmStr);
|
||||||
|
detailVo.setValue(eightAm.getSpprwl());
|
||||||
|
|
||||||
|
// 查找对应的库水位
|
||||||
|
BigDecimal rzValue = findClosestRzValue(rzMap, mstmStr);
|
||||||
|
detailVo.setRz(rzValue);
|
||||||
|
data.add(detailVo);
|
||||||
|
}
|
||||||
|
if(data.isEmpty()){
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
RegressionEquation first = RegressionAnalysis.calculateLinear(data);
|
||||||
|
RegressionEquation second = RegressionAnalysis.calculateQuadratic(data);
|
||||||
|
RegressionEquation three = RegressionAnalysis.calculateCubic(data);
|
||||||
|
RegressionEquation four = RegressionAnalysis.calculateQuartic(data);
|
||||||
|
res.put("first", first);
|
||||||
|
res.put("second", second);
|
||||||
|
res.put("three", three);
|
||||||
|
res.put("four", four);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找最接近的库水位值
|
||||||
|
*/
|
||||||
|
private BigDecimal findClosestRzValue(Map<String, BigDecimal> rzMap, String targetTimeStr) {
|
||||||
|
// 如果直接匹配到,直接返回
|
||||||
|
if (rzMap.containsKey(targetTimeStr)) {
|
||||||
|
return rzMap.get(targetTimeStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有直接匹配,查找最接近的时间
|
||||||
|
LocalDateTime targetTime = LocalDateTime.parse(targetTimeStr,
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
|
||||||
|
String closestTime = null;
|
||||||
|
long minDiff = Long.MAX_VALUE;
|
||||||
|
|
||||||
|
for (String timeStr : rzMap.keySet()) {
|
||||||
|
LocalDateTime time = LocalDateTime.parse(timeStr,
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
|
||||||
|
long diff = Math.abs(Duration.between(targetTime, time).toMinutes());
|
||||||
|
|
||||||
|
if (diff < minDiff) {
|
||||||
|
minDiff = diff;
|
||||||
|
closestTime = timeStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closestTime != null ? rzMap.get(closestTime) : BigDecimal.ZERO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package com.gunshi.project.hsz.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.gunshi.project.hsz.common.model.JcskSyB;
|
||||||
|
import com.gunshi.project.hsz.entity.so.SyDataCheckRulePageSo;
|
||||||
|
import com.gunshi.project.hsz.mapper.StZvarlBMapper;
|
||||||
|
import com.gunshi.project.hsz.mapper.SyDataCheckRuleMapper;
|
||||||
|
import com.gunshi.project.hsz.model.StZvarlB;
|
||||||
|
import com.gunshi.project.hsz.model.SyDataCheckRule;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class SyDataCheckRuleService extends ServiceImpl<SyDataCheckRuleMapper, SyDataCheckRule> {
|
||||||
|
|
||||||
|
public Page<SyDataCheckRule> pageQuery(SyDataCheckRulePageSo page) {
|
||||||
|
LambdaQueryWrapper<SyDataCheckRule> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
if(!StringUtils.isBlank(page.getDvcd())){
|
||||||
|
queryWrapper.eq(SyDataCheckRule::getDvcd,page.getDvcd());
|
||||||
|
}
|
||||||
|
Page<SyDataCheckRule> syDataCheckRulePage = this.baseMapper.selectPage(page.getPageSo().toPage(), queryWrapper);
|
||||||
|
return syDataCheckRulePage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SyDataCheckRule saveData(SyDataCheckRule dto) {
|
||||||
|
LambdaQueryWrapper<SyDataCheckRule> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(SyDataCheckRule::getDvcd,dto.getDvcd());
|
||||||
|
SyDataCheckRule syDataCheckRule = this.baseMapper.selectOne(queryWrapper);
|
||||||
|
if(syDataCheckRule != null){
|
||||||
|
throw new IllegalArgumentException("对不起,该测点已配置清洗策略");
|
||||||
|
}
|
||||||
|
save(dto);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean updateData(SyDataCheckRule dto) {
|
||||||
|
LambdaQueryWrapper<SyDataCheckRule> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(SyDataCheckRule::getDvcd,dto.getDvcd());
|
||||||
|
queryWrapper.ne(SyDataCheckRule::getId,dto.getId());
|
||||||
|
SyDataCheckRule syDataCheckRule = this.baseMapper.selectOne(queryWrapper);
|
||||||
|
if(syDataCheckRule != null){
|
||||||
|
throw new IllegalArgumentException("对不起,该测点已配置清洗策略");
|
||||||
|
}
|
||||||
|
boolean flag = updateById(dto);
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.gunshi.project.hsz.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.gunshi.project.hsz.mapper.StZvarlBMapper;
|
||||||
|
import com.gunshi.project.hsz.mapper.SyRegressionDataMapper;
|
||||||
|
import com.gunshi.project.hsz.model.StZvarlB;
|
||||||
|
import com.gunshi.project.hsz.model.SyRegressionData;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class SyRegressionDataService extends ServiceImpl<SyRegressionDataMapper, SyRegressionData> {
|
||||||
|
|
||||||
|
|
||||||
|
public List<SyRegressionData> queryData(SyRegressionData dto) {
|
||||||
|
LambdaQueryWrapper<SyRegressionData> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
if(dto.getDvcd() != null){
|
||||||
|
queryWrapper.eq(SyRegressionData::getDvcd, dto.getDvcd());
|
||||||
|
}
|
||||||
|
if(dto.getOrder() != null){
|
||||||
|
queryWrapper.eq(SyRegressionData::getOrder, dto.getOrder());
|
||||||
|
}
|
||||||
|
List<SyRegressionData> syRegressionData = this.baseMapper.selectList(queryWrapper);
|
||||||
|
return syRegressionData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,204 @@
|
||||||
|
package com.gunshi.project.hsz.util;
|
||||||
|
|
||||||
|
import com.gunshi.project.hsz.common.model.vo.OsmoticPressDetailVo;
|
||||||
|
import com.gunshi.project.hsz.model.RegressionEquation;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工程安全分析-线性回归方程计算
|
||||||
|
*/
|
||||||
|
public class ProjectCalculateUtil {
|
||||||
|
|
||||||
|
private static List<OsmoticPressDetailVo> filterValidData(List<OsmoticPressDetailVo> data) {
|
||||||
|
return data.stream()
|
||||||
|
.filter(vo -> vo.getRz() != null && vo.getValue() != null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigDecimal calculateRSquared(List<OsmoticPressDetailVo> data,
|
||||||
|
List<BigDecimal> coefficients,
|
||||||
|
BigDecimal meanY) {
|
||||||
|
BigDecimal ssTot = BigDecimal.ZERO;
|
||||||
|
BigDecimal ssRes = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
for (OsmoticPressDetailVo vo : data) {
|
||||||
|
BigDecimal x = vo.getRz();
|
||||||
|
BigDecimal y = vo.getValue();
|
||||||
|
BigDecimal yPredicted = predictWithCoefficients(x, coefficients);
|
||||||
|
|
||||||
|
BigDecimal diffActual = y.subtract(meanY);
|
||||||
|
ssTot = ssTot.add(diffActual.multiply(diffActual));
|
||||||
|
|
||||||
|
BigDecimal diffResidual = y.subtract(yPredicted);
|
||||||
|
ssRes = ssRes.add(diffResidual.multiply(diffResidual));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssTot.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
return BigDecimal.ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BigDecimal.ONE.subtract(ssRes.divide(ssTot, 30, RoundingMode.HALF_UP));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigDecimal predictWithCoefficients(BigDecimal x, List<BigDecimal> coefficients) {
|
||||||
|
BigDecimal result = BigDecimal.ZERO;
|
||||||
|
BigDecimal xPower = BigDecimal.ONE;
|
||||||
|
|
||||||
|
for (BigDecimal coeff : coefficients) {
|
||||||
|
result = result.add(coeff.multiply(xPower));
|
||||||
|
xPower = xPower.multiply(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigDecimal calculateDeterminant3x3(BigDecimal a11, BigDecimal a12, BigDecimal a13,
|
||||||
|
BigDecimal a21, BigDecimal a22, BigDecimal a23,
|
||||||
|
BigDecimal a31, BigDecimal a32, BigDecimal a33) {
|
||||||
|
return a11.multiply(a22.multiply(a33).subtract(a23.multiply(a32)))
|
||||||
|
.subtract(a12.multiply(a21.multiply(a33).subtract(a23.multiply(a31))))
|
||||||
|
.add(a13.multiply(a21.multiply(a32).subtract(a22.multiply(a31))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算线性回归方程(1阶) 库水位x轴,检测值y轴
|
||||||
|
*/
|
||||||
|
public static RegressionEquation calculateLinear(List<OsmoticPressDetailVo> data) {
|
||||||
|
List<OsmoticPressDetailVo> validData = filterValidData(data);
|
||||||
|
if (validData.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("没有有效的数据点进行计算");
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = validData.size();
|
||||||
|
|
||||||
|
BigDecimal sumX = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumY = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumXY = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumX2 = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumY2 = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
for (OsmoticPressDetailVo vo : validData) {
|
||||||
|
BigDecimal x = vo.getRz();
|
||||||
|
BigDecimal y = vo.getValue();
|
||||||
|
|
||||||
|
sumX = sumX.add(x);
|
||||||
|
sumY = sumY.add(y);
|
||||||
|
sumXY = sumXY.add(x.multiply(y));
|
||||||
|
sumX2 = sumX2.add(x.multiply(x));
|
||||||
|
sumY2 = sumY2.add(y.multiply(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal nBig = new BigDecimal(n);
|
||||||
|
BigDecimal meanX = sumX.divide(nBig, 30, RoundingMode.HALF_UP);
|
||||||
|
BigDecimal meanY = sumY.divide(nBig, 30, RoundingMode.HALF_UP);
|
||||||
|
|
||||||
|
BigDecimal numerator = sumXY.subtract(nBig.multiply(meanX).multiply(meanY));
|
||||||
|
BigDecimal denominator = sumX2.subtract(nBig.multiply(meanX).multiply(meanX));
|
||||||
|
|
||||||
|
if (denominator.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
throw new IllegalArgumentException("数据点x值相同,无法计算斜率");
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal slope = numerator.divide(denominator, 30, RoundingMode.HALF_UP);
|
||||||
|
BigDecimal intercept = meanY.subtract(slope.multiply(meanX));
|
||||||
|
|
||||||
|
// 计算R²
|
||||||
|
BigDecimal rSquared = calculateRSquared(validData,
|
||||||
|
List.of(intercept, slope), meanY);
|
||||||
|
|
||||||
|
// 系数列表:[常数项, 一次项系数]
|
||||||
|
List<BigDecimal> coefficients = List.of(
|
||||||
|
intercept.setScale(10, RoundingMode.HALF_UP),
|
||||||
|
slope.setScale(10, RoundingMode.HALF_UP)
|
||||||
|
);
|
||||||
|
|
||||||
|
return new RegressionEquation(1, coefficients, rSquared, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算二次回归方程(2阶)
|
||||||
|
*/
|
||||||
|
public static RegressionEquation calculateQuadratic(List<OsmoticPressDetailVo> data) {
|
||||||
|
List<OsmoticPressDetailVo> validData = filterValidData(data);
|
||||||
|
if (validData.size() < 3) {
|
||||||
|
throw new IllegalArgumentException("二次回归至少需要3个数据点");
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = validData.size();
|
||||||
|
|
||||||
|
BigDecimal sumX = BigDecimal.ZERO, sumY = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumX2 = BigDecimal.ZERO, sumX3 = BigDecimal.ZERO, sumX4 = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumXY = BigDecimal.ZERO, sumX2Y = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
for (OsmoticPressDetailVo vo : validData) {
|
||||||
|
BigDecimal x = vo.getRz();
|
||||||
|
BigDecimal y = vo.getValue();
|
||||||
|
|
||||||
|
BigDecimal x2 = x.multiply(x);
|
||||||
|
BigDecimal x3 = x2.multiply(x);
|
||||||
|
BigDecimal x4 = x3.multiply(x);
|
||||||
|
|
||||||
|
sumX = sumX.add(x);
|
||||||
|
sumY = sumY.add(y);
|
||||||
|
sumX2 = sumX2.add(x2);
|
||||||
|
sumX3 = sumX3.add(x3);
|
||||||
|
sumX4 = sumX4.add(x4);
|
||||||
|
sumXY = sumXY.add(x.multiply(y));
|
||||||
|
sumX2Y = sumX2Y.add(x2.multiply(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal nBig = new BigDecimal(n);
|
||||||
|
|
||||||
|
// 使用克莱姆法则求解
|
||||||
|
BigDecimal det = calculateDeterminant3x3(
|
||||||
|
nBig, sumX, sumX2,
|
||||||
|
sumX, sumX2, sumX3,
|
||||||
|
sumX2, sumX3, sumX4
|
||||||
|
);
|
||||||
|
|
||||||
|
if (det.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
throw new IllegalArgumentException("矩阵奇异,无法求解二次回归方程");
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal detA0 = calculateDeterminant3x3(
|
||||||
|
sumY, sumX, sumX2,
|
||||||
|
sumXY, sumX2, sumX3,
|
||||||
|
sumX2Y, sumX3, sumX4
|
||||||
|
);
|
||||||
|
|
||||||
|
BigDecimal detA1 = calculateDeterminant3x3(
|
||||||
|
nBig, sumY, sumX2,
|
||||||
|
sumX, sumXY, sumX3,
|
||||||
|
sumX2, sumX2Y, sumX4
|
||||||
|
);
|
||||||
|
|
||||||
|
BigDecimal detA2 = calculateDeterminant3x3(
|
||||||
|
nBig, sumX, sumY,
|
||||||
|
sumX, sumX2, sumXY,
|
||||||
|
sumX2, sumX3, sumX2Y
|
||||||
|
);
|
||||||
|
|
||||||
|
BigDecimal a0 = detA0.divide(det, 30, RoundingMode.HALF_UP);
|
||||||
|
BigDecimal a1 = detA1.divide(det, 30, RoundingMode.HALF_UP);
|
||||||
|
BigDecimal a2 = detA2.divide(det, 30, RoundingMode.HALF_UP);
|
||||||
|
|
||||||
|
// 计算R²
|
||||||
|
BigDecimal meanY = sumY.divide(nBig, 30, RoundingMode.HALF_UP);
|
||||||
|
BigDecimal rSquared = calculateRSquared(validData,
|
||||||
|
List.of(a0, a1, a2), meanY);
|
||||||
|
|
||||||
|
// 系数列表:[常数项, 一次项系数, 二次项系数]
|
||||||
|
List<BigDecimal> coefficients = List.of(
|
||||||
|
a0.setScale(10, RoundingMode.HALF_UP),
|
||||||
|
a1.setScale(10, RoundingMode.HALF_UP),
|
||||||
|
a2.setScale(10, RoundingMode.HALF_UP)
|
||||||
|
);
|
||||||
|
|
||||||
|
return new RegressionEquation(2, coefficients, rSquared, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,581 @@
|
||||||
|
package com.gunshi.project.hsz.util;
|
||||||
|
|
||||||
|
import com.gunshi.project.hsz.common.model.vo.OsmoticPressDetailVo;
|
||||||
|
import com.gunshi.project.hsz.model.RegressionEquation;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.MathContext;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回归分析工具类
|
||||||
|
*/
|
||||||
|
public class RegressionAnalysis {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算线性回归方程(1阶)
|
||||||
|
*/
|
||||||
|
public static RegressionEquation calculateLinear(List<OsmoticPressDetailVo> data) {
|
||||||
|
int n = 0;
|
||||||
|
BigDecimal rSquared = null;
|
||||||
|
List<BigDecimal> coefficients = null;
|
||||||
|
try {
|
||||||
|
List<OsmoticPressDetailVo> validData = filterValidData(data);
|
||||||
|
if (validData.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("没有有效的数据点进行计算");
|
||||||
|
}
|
||||||
|
|
||||||
|
n = validData.size();
|
||||||
|
|
||||||
|
BigDecimal sumX = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumY = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumXY = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumX2 = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumY2 = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
for (OsmoticPressDetailVo vo : validData) {
|
||||||
|
BigDecimal x = vo.getRz();
|
||||||
|
BigDecimal y = vo.getValue();
|
||||||
|
|
||||||
|
sumX = sumX.add(x);
|
||||||
|
sumY = sumY.add(y);
|
||||||
|
sumXY = sumXY.add(x.multiply(y));
|
||||||
|
sumX2 = sumX2.add(x.multiply(x));
|
||||||
|
sumY2 = sumY2.add(y.multiply(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal nBig = new BigDecimal(n);
|
||||||
|
BigDecimal meanX = sumX.divide(nBig, 100, RoundingMode.HALF_UP);
|
||||||
|
BigDecimal meanY = sumY.divide(nBig, 100, RoundingMode.HALF_UP);
|
||||||
|
|
||||||
|
BigDecimal numerator = sumXY.subtract(nBig.multiply(meanX).multiply(meanY));
|
||||||
|
BigDecimal denominator = sumX2.subtract(nBig.multiply(meanX).multiply(meanX));
|
||||||
|
|
||||||
|
if (denominator.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
throw new IllegalArgumentException("数据点x值相同,无法计算斜率");
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal slope = numerator.divide(denominator, 100, RoundingMode.HALF_UP);
|
||||||
|
BigDecimal intercept = meanY.subtract(slope.multiply(meanX));
|
||||||
|
|
||||||
|
// 计算R²
|
||||||
|
rSquared = calculateRSquared(validData, List.of(intercept, slope), meanY);
|
||||||
|
|
||||||
|
// 系数列表:[常数项, 一次项系数] - 不进行四舍五入
|
||||||
|
coefficients = List.of(intercept, slope);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RegressionEquation(1, coefficients, rSquared, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算二次回归方程(2阶)
|
||||||
|
*/
|
||||||
|
public static RegressionEquation calculateQuadratic(List<OsmoticPressDetailVo> data) {
|
||||||
|
int n = 0;
|
||||||
|
BigDecimal rSquared = null;
|
||||||
|
List<BigDecimal> coefficients = null;
|
||||||
|
try {
|
||||||
|
List<OsmoticPressDetailVo> validData = filterValidData(data);
|
||||||
|
if (validData.size() < 3) {
|
||||||
|
throw new IllegalArgumentException("二次回归至少需要3个数据点");
|
||||||
|
}
|
||||||
|
|
||||||
|
n = validData.size();
|
||||||
|
|
||||||
|
// 计算各项和
|
||||||
|
BigDecimal sumX = BigDecimal.ZERO, sumY = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumX2 = BigDecimal.ZERO, sumX3 = BigDecimal.ZERO, sumX4 = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumXY = BigDecimal.ZERO, sumX2Y = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
for (OsmoticPressDetailVo vo : validData) {
|
||||||
|
BigDecimal x = vo.getRz();
|
||||||
|
BigDecimal y = vo.getValue();
|
||||||
|
|
||||||
|
BigDecimal x2 = x.multiply(x);
|
||||||
|
BigDecimal x3 = x2.multiply(x);
|
||||||
|
BigDecimal x4 = x3.multiply(x);
|
||||||
|
|
||||||
|
sumX = sumX.add(x);
|
||||||
|
sumY = sumY.add(y);
|
||||||
|
sumX2 = sumX2.add(x2);
|
||||||
|
sumX3 = sumX3.add(x3);
|
||||||
|
sumX4 = sumX4.add(x4);
|
||||||
|
sumXY = sumXY.add(x.multiply(y));
|
||||||
|
sumX2Y = sumX2Y.add(x2.multiply(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal nBig = new BigDecimal(n);
|
||||||
|
|
||||||
|
// 使用克莱姆法则求解
|
||||||
|
BigDecimal det = calculateDeterminant3x3(
|
||||||
|
nBig, sumX, sumX2,
|
||||||
|
sumX, sumX2, sumX3,
|
||||||
|
sumX2, sumX3, sumX4
|
||||||
|
);
|
||||||
|
|
||||||
|
if (det.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
throw new IllegalArgumentException("矩阵奇异,无法求解二次回归方程");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 求解常数项 a
|
||||||
|
BigDecimal detA = calculateDeterminant3x3(
|
||||||
|
sumY, sumX, sumX2,
|
||||||
|
sumXY, sumX2, sumX3,
|
||||||
|
sumX2Y, sumX3, sumX4
|
||||||
|
);
|
||||||
|
|
||||||
|
// 求解一次项系数 b
|
||||||
|
BigDecimal detB = calculateDeterminant3x3(
|
||||||
|
nBig, sumY, sumX2,
|
||||||
|
sumX, sumXY, sumX3,
|
||||||
|
sumX2, sumX2Y, sumX4
|
||||||
|
);
|
||||||
|
|
||||||
|
// 求解二次项系数 c
|
||||||
|
BigDecimal detC = calculateDeterminant3x3(
|
||||||
|
nBig, sumX, sumY,
|
||||||
|
sumX, sumX2, sumXY,
|
||||||
|
sumX2, sumX3, sumX2Y
|
||||||
|
);
|
||||||
|
|
||||||
|
BigDecimal a = detA.divide(det, 100, RoundingMode.HALF_UP); // 常数项
|
||||||
|
BigDecimal b = detB.divide(det, 100, RoundingMode.HALF_UP); // 一次项系数
|
||||||
|
BigDecimal c = detC.divide(det, 100, RoundingMode.HALF_UP); // 二次项系数
|
||||||
|
|
||||||
|
// 计算R²
|
||||||
|
BigDecimal meanY = sumY.divide(nBig, 100, RoundingMode.HALF_UP);
|
||||||
|
rSquared = calculateRSquared(validData, List.of(a, b, c), meanY);
|
||||||
|
|
||||||
|
// 系数列表:[常数项, 一次项系数, 二次项系数] - 不进行四舍五入
|
||||||
|
coefficients = List.of(a, b, c);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RegressionEquation(2, coefficients, rSquared, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算三次回归方程(3阶)- 优化版本
|
||||||
|
*/
|
||||||
|
public static RegressionEquation calculateCubic(List<OsmoticPressDetailVo> data) {
|
||||||
|
int n = 0;
|
||||||
|
List<BigDecimal> coefficientsList = null;
|
||||||
|
BigDecimal rSquared = null;
|
||||||
|
try {
|
||||||
|
List<OsmoticPressDetailVo> validData = filterValidData(data);
|
||||||
|
if (validData.size() < 4) {
|
||||||
|
throw new IllegalArgumentException("三次回归至少需要4个数据点");
|
||||||
|
}
|
||||||
|
|
||||||
|
n = validData.size();
|
||||||
|
|
||||||
|
// 使用中心化数据提高数值稳定性
|
||||||
|
BigDecimal meanX = calculateMean(validData, OsmoticPressDetailVo::getRz);
|
||||||
|
|
||||||
|
// 计算各项和(使用中心化数据)
|
||||||
|
BigDecimal sumX = BigDecimal.ZERO, sumY = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumX2 = BigDecimal.ZERO, sumX3 = BigDecimal.ZERO, sumX4 = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumX5 = BigDecimal.ZERO, sumX6 = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumXY = BigDecimal.ZERO, sumX2Y = BigDecimal.ZERO, sumX3Y = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
for (OsmoticPressDetailVo vo : validData) {
|
||||||
|
BigDecimal x = vo.getRz().subtract(meanX); // 中心化
|
||||||
|
BigDecimal y = vo.getValue();
|
||||||
|
|
||||||
|
BigDecimal x2 = x.multiply(x);
|
||||||
|
BigDecimal x3 = x2.multiply(x);
|
||||||
|
BigDecimal x4 = x3.multiply(x);
|
||||||
|
BigDecimal x5 = x4.multiply(x);
|
||||||
|
BigDecimal x6 = x5.multiply(x);
|
||||||
|
|
||||||
|
sumX = sumX.add(x);
|
||||||
|
sumY = sumY.add(y);
|
||||||
|
sumX2 = sumX2.add(x2);
|
||||||
|
sumX3 = sumX3.add(x3);
|
||||||
|
sumX4 = sumX4.add(x4);
|
||||||
|
sumX5 = sumX5.add(x5);
|
||||||
|
sumX6 = sumX6.add(x6);
|
||||||
|
sumXY = sumXY.add(x.multiply(y));
|
||||||
|
sumX2Y = sumX2Y.add(x2.multiply(y));
|
||||||
|
sumX3Y = sumX3Y.add(x3.multiply(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal nBig = new BigDecimal(n);
|
||||||
|
|
||||||
|
// 构建正规方程组(中心化后的矩阵条件数更好)
|
||||||
|
BigDecimal[][] matrix = {
|
||||||
|
{nBig, sumX, sumX2, sumX3},
|
||||||
|
{sumX, sumX2, sumX3, sumX4},
|
||||||
|
{sumX2, sumX3, sumX4, sumX5},
|
||||||
|
{sumX3, sumX4, sumX5, sumX6}
|
||||||
|
};
|
||||||
|
|
||||||
|
BigDecimal[] vector = {sumY, sumXY, sumX2Y, sumX3Y};
|
||||||
|
|
||||||
|
// 使用改进的高斯消元法
|
||||||
|
BigDecimal[] centeredCoefficients = solveLinearSystemImproved(matrix, vector);
|
||||||
|
|
||||||
|
if (centeredCoefficients == null) {
|
||||||
|
throw new IllegalArgumentException("无法求解三次回归方程");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将中心化系数转换回原始坐标
|
||||||
|
BigDecimal[] originalCoefficients = convertToOriginalCoefficients(centeredCoefficients, meanX);
|
||||||
|
|
||||||
|
// 计算R²
|
||||||
|
BigDecimal meanY = sumY.divide(nBig, MathContext.DECIMAL128);
|
||||||
|
coefficientsList = Arrays.asList(originalCoefficients);
|
||||||
|
rSquared = calculateRSquared(validData, coefficientsList, meanY);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RegressionEquation(3, coefficientsList, rSquared, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将中心化系数转换回原始坐标
|
||||||
|
*/
|
||||||
|
private static BigDecimal[] convertToOriginalCoefficients(BigDecimal[] centeredCoeffs, BigDecimal meanX) {
|
||||||
|
// 对于三次多项式:y = a + b(x - μ) + c(x - μ)² + d(x - μ)³
|
||||||
|
// 展开后:y = (a - bμ + cμ² - dμ³) + (b - 2cμ + 3dμ²)x + (c - 3dμ)x² + d x³
|
||||||
|
|
||||||
|
BigDecimal a = centeredCoeffs[0];
|
||||||
|
BigDecimal b = centeredCoeffs[1];
|
||||||
|
BigDecimal c = centeredCoeffs[2];
|
||||||
|
BigDecimal d = centeredCoeffs[3];
|
||||||
|
|
||||||
|
BigDecimal mu = meanX;
|
||||||
|
BigDecimal mu2 = mu.multiply(mu);
|
||||||
|
BigDecimal mu3 = mu2.multiply(mu);
|
||||||
|
|
||||||
|
BigDecimal newA = a.subtract(b.multiply(mu))
|
||||||
|
.add(c.multiply(mu2))
|
||||||
|
.subtract(d.multiply(mu3));
|
||||||
|
|
||||||
|
BigDecimal newB = b.subtract(BigDecimal.valueOf(2).multiply(c).multiply(mu))
|
||||||
|
.add(BigDecimal.valueOf(3).multiply(d).multiply(mu2));
|
||||||
|
|
||||||
|
BigDecimal newC = c.subtract(BigDecimal.valueOf(3).multiply(d).multiply(mu));
|
||||||
|
BigDecimal newD = d;
|
||||||
|
|
||||||
|
return new BigDecimal[]{newA, newB, newC, newD};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带完全主元的高斯消元法,提高数值稳定性
|
||||||
|
*/
|
||||||
|
private static BigDecimal[] solveLinearSystemWithPivot(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++) {
|
||||||
|
System.arraycopy(matrix[i], 0, a[i], 0, n);
|
||||||
|
b[i] = vector[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] rowPerm = new int[n];
|
||||||
|
int[] colPerm = new int[n];
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
rowPerm[i] = i;
|
||||||
|
colPerm[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完全主元高斯消元
|
||||||
|
for (int k = 0; k < n; k++) {
|
||||||
|
// 寻找主元
|
||||||
|
int maxRow = k, maxCol = k;
|
||||||
|
BigDecimal maxVal = a[rowPerm[k]][colPerm[k]].abs();
|
||||||
|
|
||||||
|
for (int i = k; i < n; i++) {
|
||||||
|
for (int j = k; j < n; j++) {
|
||||||
|
BigDecimal current = a[rowPerm[i]][colPerm[j]].abs();
|
||||||
|
if (current.compareTo(maxVal) > 0) {
|
||||||
|
maxVal = current;
|
||||||
|
maxRow = i;
|
||||||
|
maxCol = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 交换行
|
||||||
|
if (maxRow != k) {
|
||||||
|
int temp = rowPerm[k];
|
||||||
|
rowPerm[k] = rowPerm[maxRow];
|
||||||
|
rowPerm[maxRow] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 交换列
|
||||||
|
if (maxCol != k) {
|
||||||
|
int temp = colPerm[k];
|
||||||
|
colPerm[k] = colPerm[maxCol];
|
||||||
|
colPerm[maxCol] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主元为0,矩阵奇异
|
||||||
|
if (a[rowPerm[k]][colPerm[k]].compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 消元
|
||||||
|
for (int i = k + 1; i < n; i++) {
|
||||||
|
BigDecimal factor = a[rowPerm[i]][colPerm[k]].divide(a[rowPerm[k]][colPerm[k]], 100, RoundingMode.HALF_UP);
|
||||||
|
for (int j = k; j < n; j++) {
|
||||||
|
a[rowPerm[i]][colPerm[j]] = a[rowPerm[i]][colPerm[j]].subtract(
|
||||||
|
factor.multiply(a[rowPerm[k]][colPerm[j]]));
|
||||||
|
}
|
||||||
|
b[rowPerm[i]] = b[rowPerm[i]].subtract(factor.multiply(b[rowPerm[k]]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回代
|
||||||
|
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[rowPerm[i]][colPerm[j]].multiply(x[colPerm[j]]));
|
||||||
|
}
|
||||||
|
x[colPerm[i]] = b[rowPerm[i]].subtract(sum).divide(a[rowPerm[i]][colPerm[i]], 100, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复原始顺序
|
||||||
|
BigDecimal[] result = new BigDecimal[n];
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
result[i] = x[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 其他辅助方法
|
||||||
|
private static List<OsmoticPressDetailVo> filterValidData(List<OsmoticPressDetailVo> data) {
|
||||||
|
return data.stream()
|
||||||
|
.filter(vo -> vo.getRz() != null && vo.getValue() != null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigDecimal calculateDeterminant3x3(BigDecimal a11, BigDecimal a12, BigDecimal a13,
|
||||||
|
BigDecimal a21, BigDecimal a22, BigDecimal a23,
|
||||||
|
BigDecimal a31, BigDecimal a32, BigDecimal a33) {
|
||||||
|
return a11.multiply(a22.multiply(a33).subtract(a23.multiply(a32)))
|
||||||
|
.subtract(a12.multiply(a21.multiply(a33).subtract(a23.multiply(a31))))
|
||||||
|
.add(a13.multiply(a21.multiply(a32).subtract(a22.multiply(a31))));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static BigDecimal predictWithCoefficients(BigDecimal x, List<BigDecimal> coefficients) {
|
||||||
|
BigDecimal result = BigDecimal.ZERO;
|
||||||
|
BigDecimal xPower = BigDecimal.ONE;
|
||||||
|
|
||||||
|
for (BigDecimal coeff : coefficients) {
|
||||||
|
result = result.add(coeff.multiply(xPower));
|
||||||
|
xPower = xPower.multiply(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算四次回归方程(4阶)
|
||||||
|
*/
|
||||||
|
public static RegressionEquation calculateQuartic(List<OsmoticPressDetailVo> data) {
|
||||||
|
int n = 0;
|
||||||
|
List<BigDecimal> coeffsList = null;
|
||||||
|
BigDecimal rSquared = null;
|
||||||
|
try {
|
||||||
|
List<OsmoticPressDetailVo> validData = filterValidData(data);
|
||||||
|
if (validData.size() < 5) {
|
||||||
|
throw new IllegalArgumentException("四次回归至少需要5个数据点");
|
||||||
|
}
|
||||||
|
|
||||||
|
n = validData.size();
|
||||||
|
|
||||||
|
// 计算各项和:sumX, sumY, sumX2, sumX3, sumX4, sumX5, sumX6, sumX7, sumX8, sumXY, sumX2Y, sumX3Y, sumX4Y
|
||||||
|
BigDecimal sumX = BigDecimal.ZERO, sumY = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumX2 = BigDecimal.ZERO, sumX3 = BigDecimal.ZERO, sumX4 = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumX5 = BigDecimal.ZERO, sumX6 = BigDecimal.ZERO, sumX7 = BigDecimal.ZERO, sumX8 = BigDecimal.ZERO;
|
||||||
|
BigDecimal sumXY = BigDecimal.ZERO, sumX2Y = BigDecimal.ZERO, sumX3Y = BigDecimal.ZERO, sumX4Y = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
for (OsmoticPressDetailVo vo : validData) {
|
||||||
|
BigDecimal x = vo.getRz();
|
||||||
|
BigDecimal y = vo.getValue();
|
||||||
|
|
||||||
|
BigDecimal x2 = x.multiply(x);
|
||||||
|
BigDecimal x3 = x2.multiply(x);
|
||||||
|
BigDecimal x4 = x3.multiply(x);
|
||||||
|
BigDecimal x5 = x4.multiply(x);
|
||||||
|
BigDecimal x6 = x5.multiply(x);
|
||||||
|
BigDecimal x7 = x6.multiply(x);
|
||||||
|
BigDecimal x8 = x7.multiply(x);
|
||||||
|
|
||||||
|
sumX = sumX.add(x);
|
||||||
|
sumY = sumY.add(y);
|
||||||
|
sumX2 = sumX2.add(x2);
|
||||||
|
sumX3 = sumX3.add(x3);
|
||||||
|
sumX4 = sumX4.add(x4);
|
||||||
|
sumX5 = sumX5.add(x5);
|
||||||
|
sumX6 = sumX6.add(x6);
|
||||||
|
sumX7 = sumX7.add(x7);
|
||||||
|
sumX8 = sumX8.add(x8);
|
||||||
|
sumXY = sumXY.add(x.multiply(y));
|
||||||
|
sumX2Y = sumX2Y.add(x2.multiply(y));
|
||||||
|
sumX3Y = sumX3Y.add(x3.multiply(y));
|
||||||
|
sumX4Y = sumX4Y.add(x4.multiply(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal nBig = new BigDecimal(n);
|
||||||
|
|
||||||
|
// 构建正规方程组的系数矩阵
|
||||||
|
BigDecimal[][] matrix = {
|
||||||
|
{nBig, sumX, sumX2, sumX3, sumX4}, // 第1行
|
||||||
|
{sumX, sumX2, sumX3, sumX4, sumX5}, // 第2行
|
||||||
|
{sumX2, sumX3, sumX4, sumX5, sumX6}, // 第3行
|
||||||
|
{sumX3, sumX4, sumX5, sumX6, sumX7}, // 第4行
|
||||||
|
{sumX4, sumX5, sumX6, sumX7, sumX8} // 第5行
|
||||||
|
};
|
||||||
|
|
||||||
|
// 构建右侧向量
|
||||||
|
BigDecimal[] vector = {sumY, sumXY, sumX2Y, sumX3Y, sumX4Y};
|
||||||
|
|
||||||
|
// 使用改进的高斯消元法求解系数 [a, b, c, d, e]
|
||||||
|
BigDecimal[] coefficients = solveLinearSystemImproved(matrix, vector);
|
||||||
|
if (coefficients == null) {
|
||||||
|
throw new IllegalArgumentException("无法求解四次回归方程(矩阵奇异)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算R²
|
||||||
|
BigDecimal meanY = sumY.divide(nBig, MathContext.DECIMAL128);
|
||||||
|
coeffsList = Arrays.asList(coefficients);
|
||||||
|
rSquared = calculateRSquared(validData, coeffsList, meanY);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RegressionEquation(4, coeffsList, rSquared, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 改进的线性方程组求解器(部分主元高斯消元)
|
||||||
|
* 用于解决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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 辅助方法(已存在,无需修改) ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算均值(高精度)
|
||||||
|
*/
|
||||||
|
private static BigDecimal calculateMean(List<OsmoticPressDetailVo> data,
|
||||||
|
java.util.function.Function<OsmoticPressDetailVo, BigDecimal> extractor) {
|
||||||
|
BigDecimal sum = BigDecimal.ZERO;
|
||||||
|
for (OsmoticPressDetailVo vo : data) {
|
||||||
|
sum = sum.add(extractor.apply(vo));
|
||||||
|
}
|
||||||
|
return sum.divide(new BigDecimal(data.size()), MathContext.DECIMAL128);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算R²
|
||||||
|
*/
|
||||||
|
private static BigDecimal calculateRSquared(List<OsmoticPressDetailVo> data,
|
||||||
|
List<BigDecimal> coefficients,
|
||||||
|
BigDecimal meanY) {
|
||||||
|
BigDecimal ssTot = BigDecimal.ZERO;
|
||||||
|
BigDecimal ssRes = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
for (OsmoticPressDetailVo vo : data) {
|
||||||
|
BigDecimal x = vo.getRz();
|
||||||
|
BigDecimal y = vo.getValue();
|
||||||
|
BigDecimal yPredicted = predictWithCoefficients(x, coefficients);
|
||||||
|
|
||||||
|
BigDecimal diffActual = y.subtract(meanY);
|
||||||
|
ssTot = ssTot.add(diffActual.multiply(diffActual));
|
||||||
|
|
||||||
|
BigDecimal diffResidual = y.subtract(yPredicted);
|
||||||
|
ssRes = ssRes.add(diffResidual.multiply(diffResidual));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssTot.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
return BigDecimal.ONE; // 总平方和为0,拟合完美
|
||||||
|
}
|
||||||
|
return BigDecimal.ONE.subtract(ssRes.divide(ssTot, MathContext.DECIMAL128), MathContext.DECIMAL128);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue