|
|
@@ -27,6 +27,7 @@ import com.ufo.project.data.domain.vo.ShortTermPowerForecastReportQuery;
|
|
|
import com.ufo.project.data.domain.vo.ShortTermPowerForecastReportVO;
|
|
|
import com.ufo.project.data.service.IShortTermPowerForecastReportService;
|
|
|
import com.ufo.project.forecast.shortterm.power.domain.DataShortTermPowerForecastIssued;
|
|
|
+import com.ufo.project.forecast.shortterm.power.domain.ForecastPowerAverage;
|
|
|
import com.ufo.project.forecast.shortterm.power.service.IDataShortTermPowerForecastIssuedService;
|
|
|
import com.ufo.project.model.domain.DataElectricityLocal;
|
|
|
import com.ufo.project.model.service.IDataElectricityLocalService;
|
|
|
@@ -85,8 +86,9 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
// 2. 获取预测功率数据
|
|
|
long utcStartTime = parseLong(startTime);
|
|
|
long utcEndTime = parseLong(endTime);
|
|
|
- List<DataShortTermPowerForecastIssued> forecastList = powerForecastIssuedService.selectByTimeRange(
|
|
|
+ List<ForecastPowerAverage> forecastList = powerForecastIssuedService.selectAveragePowerByTimeRange(
|
|
|
entityId, utcStartTime, utcEndTime);
|
|
|
+ this.dataShortTermPowerForecastIssued2Gmt8(forecastList);
|
|
|
|
|
|
// 3. 按基准类型分组
|
|
|
switch (type)
|
|
|
@@ -102,21 +104,32 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void dataShortTermPowerForecastIssued2Gmt8(List<ForecastPowerAverage> forecastList)
|
|
|
+ {
|
|
|
+ for (ForecastPowerAverage record : forecastList)
|
|
|
+ {
|
|
|
+ ZonedDateTime forecastZdt = ZonedDateTime.ofInstant(Instant.ofEpochSecond(record.getForecastTime()),
|
|
|
+ ZoneId.systemDefault());
|
|
|
+ ZonedDateTime forecastGmt8 = forecastZdt.withZoneSameInstant(ZONE_SHANGHAI);
|
|
|
+ record.setForecastTime(forecastGmt8.toEpochSecond());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 构建日报
|
|
|
*/
|
|
|
private List<ShortTermPowerForecastReportVO> buildDailyReport(List<DataElectricityLocal> actualList,
|
|
|
- List<DataShortTermPowerForecastIssued> forecastList)
|
|
|
+ List<ForecastPowerAverage> forecastList)
|
|
|
{
|
|
|
Map<String, List<DataElectricityLocal>> dailyMap = groupByDay(actualList);
|
|
|
- Map<String, List<DataShortTermPowerForecastIssued>> forecastDailyMap = groupForecastByDay(forecastList);
|
|
|
+ Map<String, List<ForecastPowerAverage>> forecastDailyMap = groupForecastByDay(forecastList);
|
|
|
|
|
|
List<ShortTermPowerForecastReportVO> result = new ArrayList<>();
|
|
|
for (Entry<String, List<DataElectricityLocal>> entry : dailyMap.entrySet())
|
|
|
{
|
|
|
String day = entry.getKey();
|
|
|
List<DataElectricityLocal> records = entry.getValue();
|
|
|
- List<DataShortTermPowerForecastIssued> forecastRecords = forecastDailyMap.getOrDefault(day, Collections.emptyList());
|
|
|
+ List<ForecastPowerAverage> forecastRecords = forecastDailyMap.getOrDefault(day, Collections.emptyList());
|
|
|
|
|
|
ShortTermPowerForecastReportVO vo = new ShortTermPowerForecastReportVO();
|
|
|
vo.setTime(day);
|
|
|
@@ -130,17 +143,17 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
* 构建月报
|
|
|
*/
|
|
|
private List<ShortTermPowerForecastReportVO> buildMonthlyReport(List<DataElectricityLocal> actualList,
|
|
|
- List<DataShortTermPowerForecastIssued> forecastList)
|
|
|
+ List<ForecastPowerAverage> forecastList)
|
|
|
{
|
|
|
Map<String, List<DataElectricityLocal>> monthlyMap = groupByMonth(actualList);
|
|
|
- Map<String, List<DataShortTermPowerForecastIssued>> forecastMonthlyMap = groupForecastByMonth(forecastList);
|
|
|
+ Map<String, List<ForecastPowerAverage>> forecastMonthlyMap = groupForecastByMonth(forecastList);
|
|
|
|
|
|
List<ShortTermPowerForecastReportVO> result = new ArrayList<>();
|
|
|
for (Entry<String, List<DataElectricityLocal>> entry : monthlyMap.entrySet())
|
|
|
{
|
|
|
String month = entry.getKey();
|
|
|
List<DataElectricityLocal> records = entry.getValue();
|
|
|
- List<DataShortTermPowerForecastIssued> forecastRecords =
|
|
|
+ List<ForecastPowerAverage> forecastRecords =
|
|
|
forecastMonthlyMap.getOrDefault(month, Collections.emptyList());
|
|
|
|
|
|
ShortTermPowerForecastReportVO vo = new ShortTermPowerForecastReportVO();
|
|
|
@@ -155,17 +168,17 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
* 构建年报
|
|
|
*/
|
|
|
private List<ShortTermPowerForecastReportVO> buildYearlyReport(List<DataElectricityLocal> actualList,
|
|
|
- List<DataShortTermPowerForecastIssued> forecastList)
|
|
|
+ List<ForecastPowerAverage> forecastList)
|
|
|
{
|
|
|
Map<String, List<DataElectricityLocal>> yearlyMap = groupByYear(actualList);
|
|
|
- Map<String, List<DataShortTermPowerForecastIssued>> forecastYearlyMap = groupForecastByYear(forecastList);
|
|
|
+ Map<String, List<ForecastPowerAverage>> forecastYearlyMap = groupForecastByYear(forecastList);
|
|
|
|
|
|
List<ShortTermPowerForecastReportVO> result = new ArrayList<>();
|
|
|
for (Entry<String, List<DataElectricityLocal>> entry : yearlyMap.entrySet())
|
|
|
{
|
|
|
String year = entry.getKey();
|
|
|
List<DataElectricityLocal> records = entry.getValue();
|
|
|
- List<DataShortTermPowerForecastIssued> forecastRecords =
|
|
|
+ List<ForecastPowerAverage> forecastRecords =
|
|
|
forecastYearlyMap.getOrDefault(year, Collections.emptyList());
|
|
|
|
|
|
ShortTermPowerForecastReportVO vo = new ShortTermPowerForecastReportVO();
|
|
|
@@ -180,8 +193,11 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
* 计算指标(日报/月报/年报通用)
|
|
|
*/
|
|
|
private void computeDailyMetrics(ShortTermPowerForecastReportVO vo,
|
|
|
- List<DataElectricityLocal> actualRecords, List<DataShortTermPowerForecastIssued> forecastRecords)
|
|
|
+ List<DataElectricityLocal> actualRecords, List<ForecastPowerAverage> forecastRecords)
|
|
|
{
|
|
|
+ // 预先构建预测数据映射(避免各方法重复调用 buildForecastMap)
|
|
|
+ Map<Long, BigDecimal> forecastMap = buildForecastMap(forecastRecords);
|
|
|
+
|
|
|
// 1. operatingCapacity: 筛选 device_status = 0 AND grid_status = 1, MAX(actual_power) / 1000
|
|
|
BigDecimal operatingCapacity = computeOperatingCapacity(actualRecords);
|
|
|
vo.setOperatingCapacity(operatingCapacity);
|
|
|
@@ -191,23 +207,23 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
vo.setActualPower(actualPower);
|
|
|
|
|
|
// 3. forecastPower: AVG(power) / 1000
|
|
|
- BigDecimal forecastPower = computeForecastPower(forecastRecords);
|
|
|
+ BigDecimal forecastPower = computeForecastPower(forecastMap);
|
|
|
vo.setForecastPower(forecastPower);
|
|
|
|
|
|
// 4. RMSE
|
|
|
- BigDecimal rmse = computeRmse(actualRecords, forecastRecords);
|
|
|
+ BigDecimal rmse = computeRmse(actualRecords, forecastMap);
|
|
|
vo.setRootMeanSquareError(rmse);
|
|
|
|
|
|
// 5. MAE
|
|
|
- BigDecimal mae = computeMae(actualRecords, forecastRecords);
|
|
|
+ BigDecimal mae = computeMae(actualRecords, forecastMap);
|
|
|
vo.setMeanAbsoluteError(mae);
|
|
|
|
|
|
// 6. correlationCoefficientR
|
|
|
- BigDecimal corr = computeCorrelation(actualRecords, forecastRecords);
|
|
|
+ BigDecimal corr = computeCorrelation(actualRecords, forecastMap);
|
|
|
vo.setCorrelationCoefficientR(corr);
|
|
|
|
|
|
// 7. maximumErrorPassRate: 基于逐点校验的合格率
|
|
|
- BigDecimal passRate = computeMaximumErrorPassRate(actualRecords, forecastRecords, operatingCapacity);
|
|
|
+ BigDecimal passRate = computeMaximumErrorPassRate(actualRecords, forecastMap, operatingCapacity);
|
|
|
vo.setMaximumErrorPassRate(passRate);
|
|
|
}
|
|
|
|
|
|
@@ -261,62 +277,43 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
/**
|
|
|
* 计算预测功率
|
|
|
*/
|
|
|
- private BigDecimal computeForecastPower(List<DataShortTermPowerForecastIssued> records)
|
|
|
+ private BigDecimal computeForecastPower(Map<Long, BigDecimal> forecastMap)
|
|
|
{
|
|
|
- BigDecimal sum = BigDecimal.ZERO;
|
|
|
- int count = 0;
|
|
|
- for (DataShortTermPowerForecastIssued r : records)
|
|
|
- {
|
|
|
- String power = r.getPower();
|
|
|
- if (StringUtils.isNotEmpty(power))
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- sum = sum.add(new BigDecimal(power.trim()));
|
|
|
- count++;
|
|
|
- }
|
|
|
- catch (NumberFormatException e)
|
|
|
- {
|
|
|
- // skip
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (count == 0)
|
|
|
+ if (forecastMap == null || forecastMap.isEmpty())
|
|
|
{
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
- return sum.divide(new BigDecimal(1000)).divide(BigDecimal.valueOf(count), 3, RoundingMode.HALF_UP);
|
|
|
+ BigDecimal sum = forecastMap.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ BigDecimal avg = sum.divide(BigDecimal.valueOf(forecastMap.size()), 10, RoundingMode.HALF_UP);
|
|
|
+ return avg.divide(new BigDecimal(1000), 3, RoundingMode.HALF_UP);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 计算RMSE
|
|
|
*/
|
|
|
private BigDecimal computeRmse(List<DataElectricityLocal> actualRecords,
|
|
|
- List<DataShortTermPowerForecastIssued> forecastRecords)
|
|
|
+ Map<Long, BigDecimal> forecastMap)
|
|
|
{
|
|
|
- // 按时间戳聚合预测数据(以分钟级时间戳为key)
|
|
|
- Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
|
|
|
-
|
|
|
if (forecastMap.isEmpty())
|
|
|
{
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
|
|
|
- double sumSquaredError = 0.0;
|
|
|
+ BigDecimal sumSquaredError = BigDecimal.ZERO;
|
|
|
int count = 0;
|
|
|
+ BigDecimal thousand = BigDecimal.valueOf(1000);
|
|
|
|
|
|
for (DataElectricityLocal r : actualRecords)
|
|
|
{
|
|
|
- if (r.getTm() == null) continue;
|
|
|
+ if (r.getTm() == null || r.getActualPower() == null) continue;
|
|
|
+
|
|
|
Long ts = r.getTm().getTime() / 1000;
|
|
|
- Double fp = forecastMap.get(ts);
|
|
|
+ BigDecimal fp = forecastMap.get(ts);
|
|
|
if (fp == null) continue;
|
|
|
|
|
|
- Double ap = r.getActualPower();
|
|
|
- if (ap == null) continue;
|
|
|
-
|
|
|
- double diffMW = (ap - fp) / 1000.0;
|
|
|
- sumSquaredError += diffMW * diffMW;
|
|
|
+ BigDecimal ap = BigDecimal.valueOf(r.getActualPower());
|
|
|
+ BigDecimal diffMW = ap.subtract(fp).divide(thousand, 10, RoundingMode.HALF_UP);
|
|
|
+ sumSquaredError = sumSquaredError.add(diffMW.multiply(diffMW));
|
|
|
count++;
|
|
|
}
|
|
|
|
|
|
@@ -325,7 +322,9 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
|
|
|
- double rmse = Math.sqrt(sumSquaredError / count);
|
|
|
+ BigDecimal meanSquaredError = sumSquaredError.divide(BigDecimal.valueOf(count), 10, RoundingMode.HALF_UP);
|
|
|
+ // 用 Math.sqrt 开方(平方根无法用 BigDecimal 精确表示,转为 double 计算后格式化)
|
|
|
+ double rmse = Math.sqrt(meanSquaredError.doubleValue());
|
|
|
return BigDecimal.valueOf(rmse).setScale(3, RoundingMode.HALF_UP);
|
|
|
}
|
|
|
|
|
|
@@ -333,30 +332,28 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
* 计算MAE
|
|
|
*/
|
|
|
private BigDecimal computeMae(List<DataElectricityLocal> actualRecords,
|
|
|
- List<DataShortTermPowerForecastIssued> forecastRecords)
|
|
|
+ Map<Long, BigDecimal> forecastMap)
|
|
|
{
|
|
|
- Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
|
|
|
-
|
|
|
if (forecastMap.isEmpty())
|
|
|
{
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
|
|
|
- double sumAbsError = 0.0;
|
|
|
+ BigDecimal sumAbsError = BigDecimal.ZERO;
|
|
|
int count = 0;
|
|
|
+ BigDecimal thousand = BigDecimal.valueOf(1000);
|
|
|
|
|
|
for (DataElectricityLocal r : actualRecords)
|
|
|
{
|
|
|
- if (r.getTm() == null) continue;
|
|
|
+ if (r.getTm() == null || r.getActualPower() == null) continue;
|
|
|
+
|
|
|
Long ts = r.getTm().getTime() / 1000;
|
|
|
- Double fp = forecastMap.get(ts);
|
|
|
+ BigDecimal fp = forecastMap.get(ts);
|
|
|
if (fp == null) continue;
|
|
|
|
|
|
- Double ap = r.getActualPower();
|
|
|
- if (ap == null) continue;
|
|
|
-
|
|
|
- double absErrorMW = Math.abs(ap - fp) / 1000.0;
|
|
|
- sumAbsError += absErrorMW;
|
|
|
+ BigDecimal ap = BigDecimal.valueOf(r.getActualPower());
|
|
|
+ BigDecimal absErrorMW = ap.subtract(fp).abs().divide(thousand, 10, RoundingMode.HALF_UP);
|
|
|
+ sumAbsError = sumAbsError.add(absErrorMW);
|
|
|
count++;
|
|
|
}
|
|
|
|
|
|
@@ -365,39 +362,38 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
|
|
|
- double mae = sumAbsError / count;
|
|
|
- return BigDecimal.valueOf(mae).setScale(3, RoundingMode.HALF_UP);
|
|
|
+ BigDecimal mae = sumAbsError.divide(BigDecimal.valueOf(count), 3, RoundingMode.HALF_UP);
|
|
|
+ return mae;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 计算相关性系数 R
|
|
|
*/
|
|
|
private BigDecimal computeCorrelation(List<DataElectricityLocal> actualRecords,
|
|
|
- List<DataShortTermPowerForecastIssued> forecastRecords)
|
|
|
+ Map<Long, BigDecimal> forecastMap)
|
|
|
{
|
|
|
- Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
|
|
|
-
|
|
|
if (forecastMap.isEmpty())
|
|
|
{
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
|
|
|
- // 收集成对数据
|
|
|
- List<Double> xList = new ArrayList<>();
|
|
|
- List<Double> yList = new ArrayList<>();
|
|
|
+ // 收集成对数据(MW)
|
|
|
+ List<BigDecimal> xList = new ArrayList<>();
|
|
|
+ List<BigDecimal> yList = new ArrayList<>();
|
|
|
+ BigDecimal thousand = BigDecimal.valueOf(1000);
|
|
|
|
|
|
for (DataElectricityLocal r : actualRecords)
|
|
|
{
|
|
|
- if (r.getTm() == null) continue;
|
|
|
+ if (r.getTm() == null || r.getActualPower() == null) continue;
|
|
|
+
|
|
|
Long ts = r.getTm().getTime() / 1000;
|
|
|
- Double fp = forecastMap.get(ts);
|
|
|
+ BigDecimal fp = forecastMap.get(ts);
|
|
|
if (fp == null) continue;
|
|
|
|
|
|
- Double ap = r.getActualPower();
|
|
|
- if (ap == null) continue;
|
|
|
-
|
|
|
- xList.add(ap / 1000.0);
|
|
|
- yList.add(fp / 1000.0);
|
|
|
+ BigDecimal ap = BigDecimal.valueOf(r.getActualPower()).divide(thousand, 10, RoundingMode.HALF_UP);
|
|
|
+ BigDecimal fy = fp.divide(thousand, 10, RoundingMode.HALF_UP);
|
|
|
+ xList.add(ap);
|
|
|
+ yList.add(fy);
|
|
|
}
|
|
|
|
|
|
int n = xList.size();
|
|
|
@@ -406,31 +402,36 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
|
|
|
+ BigDecimal nBd = BigDecimal.valueOf(n);
|
|
|
// 计算均值
|
|
|
- double meanX = xList.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
|
|
|
- double meanY = yList.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
|
|
|
+ BigDecimal sumX = xList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ BigDecimal sumY = yList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ BigDecimal meanX = sumX.divide(nBd, 10, RoundingMode.HALF_UP);
|
|
|
+ BigDecimal meanY = sumY.divide(nBd, 10, RoundingMode.HALF_UP);
|
|
|
|
|
|
- // 计算相关系数
|
|
|
- double numerator = 0.0;
|
|
|
- double sumSqX = 0.0;
|
|
|
- double sumSqY = 0.0;
|
|
|
+ // 计算相关系数:逐步累加,保持精度
|
|
|
+ BigDecimal numerator = BigDecimal.ZERO;
|
|
|
+ BigDecimal sumSqX = BigDecimal.ZERO;
|
|
|
+ BigDecimal sumSqY = BigDecimal.ZERO;
|
|
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
{
|
|
|
- double dx = xList.get(i) - meanX;
|
|
|
- double dy = yList.get(i) - meanY;
|
|
|
- numerator += dx * dy;
|
|
|
- sumSqX += dx * dx;
|
|
|
- sumSqY += dy * dy;
|
|
|
+ BigDecimal dx = xList.get(i).subtract(meanX);
|
|
|
+ BigDecimal dy = yList.get(i).subtract(meanY);
|
|
|
+ numerator = numerator.add(dx.multiply(dy));
|
|
|
+ sumSqX = sumSqX.add(dx.multiply(dx));
|
|
|
+ sumSqY = sumSqY.add(dy.multiply(dy));
|
|
|
}
|
|
|
|
|
|
- double denominator = Math.sqrt(sumSqX * sumSqY);
|
|
|
- if (denominator == 0.0)
|
|
|
+ BigDecimal denominatorSquared = sumSqX.multiply(sumSqY);
|
|
|
+ if (denominatorSquared.compareTo(BigDecimal.ZERO) == 0)
|
|
|
{
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
|
|
|
- double r = numerator / denominator;
|
|
|
+ // 用 Math.sqrt 开方(平方根无法用 BigDecimal 精确表示)
|
|
|
+ double denominator = Math.sqrt(denominatorSquared.doubleValue());
|
|
|
+ double r = numerator.doubleValue() / denominator;
|
|
|
return BigDecimal.valueOf(r).setScale(3, RoundingMode.HALF_UP);
|
|
|
}
|
|
|
|
|
|
@@ -438,7 +439,7 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
* 计算最大误差合格率
|
|
|
*/
|
|
|
private BigDecimal computeMaximumErrorPassRate(List<DataElectricityLocal> actualRecords,
|
|
|
- List<DataShortTermPowerForecastIssued> forecastRecords,
|
|
|
+ Map<Long, BigDecimal> forecastMap,
|
|
|
BigDecimal operatingCapacity)
|
|
|
{
|
|
|
if (operatingCapacity == null || operatingCapacity.compareTo(BigDecimal.ZERO) == 0)
|
|
|
@@ -452,65 +453,67 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
|
|
|
- double thresholdValue;
|
|
|
+ BigDecimal thresholdValue;
|
|
|
try
|
|
|
{
|
|
|
- thresholdValue = Double.parseDouble(threshold);
|
|
|
+ thresholdValue = new BigDecimal(threshold.trim());
|
|
|
}
|
|
|
catch (NumberFormatException e)
|
|
|
{
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
|
|
|
- double capacityMW = operatingCapacity.doubleValue();
|
|
|
- double passCount = 0;
|
|
|
- double totalCount = 0;
|
|
|
-
|
|
|
- // 基于时间戳逐点校验:ABS(actual - forecast) / 开机容量 <= 阈值
|
|
|
- Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
|
|
|
+ BigDecimal passCount = BigDecimal.ZERO;
|
|
|
+ BigDecimal totalCount = BigDecimal.ZERO;
|
|
|
+ BigDecimal thousand = BigDecimal.valueOf(1000);
|
|
|
|
|
|
for (DataElectricityLocal r : actualRecords)
|
|
|
{
|
|
|
if (r.getTm() == null || r.getActualPower() == null) continue;
|
|
|
|
|
|
Long ts = r.getTm().getTime() / 1000;
|
|
|
- Double fp = forecastMap.get(ts);
|
|
|
+ BigDecimal fp = forecastMap.get(ts);
|
|
|
if (fp == null) continue;
|
|
|
|
|
|
- totalCount++;
|
|
|
- double errorMW = Math.abs(r.getActualPower() - fp) / 1000.0;
|
|
|
- if (errorMW <= thresholdValue * capacityMW)
|
|
|
+ totalCount = totalCount.add(BigDecimal.ONE);
|
|
|
+ BigDecimal errorMW = BigDecimal.valueOf(r.getActualPower())
|
|
|
+ .subtract(fp)
|
|
|
+ .abs()
|
|
|
+ .divide(thousand, 10, RoundingMode.HALF_UP);
|
|
|
+ BigDecimal allowed = thresholdValue.multiply(operatingCapacity);
|
|
|
+ if (errorMW.compareTo(allowed) <= 0)
|
|
|
{
|
|
|
- passCount++;
|
|
|
+ passCount = passCount.add(BigDecimal.ONE);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (totalCount == 0)
|
|
|
+ if (totalCount.compareTo(BigDecimal.ZERO) == 0)
|
|
|
{
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
|
|
|
- double rate = (passCount / totalCount) * 100.0;
|
|
|
- return BigDecimal.valueOf(rate).setScale(3, RoundingMode.HALF_UP);
|
|
|
+ BigDecimal rate = passCount.divide(totalCount, 10, RoundingMode.HALF_UP)
|
|
|
+ .multiply(BigDecimal.valueOf(100));
|
|
|
+ return rate.setScale(3, RoundingMode.HALF_UP);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 构建预测数据映射:时间戳(秒) -> power(kW)
|
|
|
*/
|
|
|
- private Map<Long, Double> buildForecastMap(List<DataShortTermPowerForecastIssued> records)
|
|
|
+ private Map<Long, BigDecimal> buildForecastMap(List<ForecastPowerAverage> records)
|
|
|
{
|
|
|
- Map<Long, Double> map = new LinkedHashMap<>();
|
|
|
+ Map<Long, BigDecimal> map = new LinkedHashMap<>();
|
|
|
if (records == null) return map;
|
|
|
|
|
|
- for (DataShortTermPowerForecastIssued r : records)
|
|
|
+ for (ForecastPowerAverage r : records)
|
|
|
{
|
|
|
if (r.getForecastTime() == null) continue;
|
|
|
- String power = r.getPower();
|
|
|
- if (StringUtils.isEmpty(power)) continue;
|
|
|
+ BigDecimal power = r.getAvgPower();
|
|
|
+ if (power == null) continue;
|
|
|
|
|
|
try
|
|
|
{
|
|
|
- map.put(r.getForecastTime(), Double.parseDouble(power.trim()));
|
|
|
+ map.put(r.getForecastTime(), power);
|
|
|
}
|
|
|
catch (NumberFormatException e)
|
|
|
{
|
|
|
@@ -571,8 +574,8 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
/**
|
|
|
* 按日分组预测数据
|
|
|
*/
|
|
|
- private Map<String, List<DataShortTermPowerForecastIssued>> groupForecastByDay(
|
|
|
- List<DataShortTermPowerForecastIssued> records)
|
|
|
+ private Map<String, List<ForecastPowerAverage>> groupForecastByDay(
|
|
|
+ List<ForecastPowerAverage> records)
|
|
|
{
|
|
|
return records.stream()
|
|
|
.filter(r -> r.getForecastTime() != null)
|
|
|
@@ -588,8 +591,8 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
/**
|
|
|
* 按月分组预测数据
|
|
|
*/
|
|
|
- private Map<String, List<DataShortTermPowerForecastIssued>> groupForecastByMonth(
|
|
|
- List<DataShortTermPowerForecastIssued> records)
|
|
|
+ private Map<String, List<ForecastPowerAverage>> groupForecastByMonth(
|
|
|
+ List<ForecastPowerAverage> records)
|
|
|
{
|
|
|
return records.stream()
|
|
|
.filter(r -> r.getForecastTime() != null)
|
|
|
@@ -608,8 +611,8 @@ public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerF
|
|
|
/**
|
|
|
* 按年分组预测数据
|
|
|
*/
|
|
|
- private Map<String, List<DataShortTermPowerForecastIssued>> groupForecastByYear(
|
|
|
- List<DataShortTermPowerForecastIssued> records)
|
|
|
+ private Map<String, List<ForecastPowerAverage>> groupForecastByYear(
|
|
|
+ List<ForecastPowerAverage> records)
|
|
|
{
|
|
|
return records.stream()
|
|
|
.filter(r -> r.getForecastTime() != null)
|