高低电压穿越功能优化

This commit is contained in:
wr
2025-03-27 10:41:04 +08:00
parent 7d5672809f
commit d7283c5628
30 changed files with 428 additions and 186 deletions

View File

@@ -1,35 +1,51 @@
package com.njcn.prepare.harmonic.service.mysql.Impl.event;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
import com.njcn.device.biz.commApi.CommLineClient;
import com.njcn.device.biz.pojo.dto.LineDTO;
import com.njcn.device.pms.pojo.param.MonitorTerminalParam;
import com.njcn.device.pq.api.DeptLineFeignClient;
import com.njcn.device.pq.api.LineFeignClient;
import com.njcn.device.pq.api.NewStationClient;
import com.njcn.device.pq.constant.Param;
import com.njcn.device.pq.pojo.po.NewStation;
import com.njcn.device.pq.pojo.vo.LineDetailDataVO;
import com.njcn.event.api.EventDetailFeignClient;
import com.njcn.event.api.TransientFeignClient;
import com.njcn.event.file.pojo.dto.WaveDataDTO;
import com.njcn.event.pojo.param.EventCountParam;
import com.njcn.event.pojo.po.RmpEventDetailPO;
import com.njcn.prepare.harmonic.mapper.mysql.event.SpThroughMapper;
import com.njcn.prepare.harmonic.pojo.param.SpThroughParam;
import com.njcn.prepare.harmonic.pojo.po.SpThroughPO;
import com.njcn.prepare.harmonic.pojo.vo.SpThroughVO;
import com.njcn.prepare.harmonic.service.mysql.event.SpThroughService;
import com.njcn.supervision.api.UserLedgerFeignClient;
import com.njcn.supervision.pojo.vo.user.NewUserReportVO;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.api.DictTreeFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.enums.DicTreeEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.system.pojo.vo.DictTreeVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 高低电压穿越 服务实现类
*
* @author guofeihu
* @since 2024-08-22
*/
@@ -38,43 +54,57 @@ import java.util.stream.Collectors;
public class SpThroughServiceImpl extends MppServiceImpl<SpThroughMapper, SpThroughPO> implements SpThroughService {
private final EventDetailFeignClient eventDetailFeignClient;
private final CommLineClient commLineClient;
private final NewStationClient newStationClient;
private final TransientFeignClient transientFeignClient;
private final DeptLineFeignClient deptLineFeignClient;
private final UserLedgerFeignClient userLedgerFeignClient;
private final LineFeignClient lineFeignClient;
private final DictTreeFeignClient dictTreeFeignClient;
private final DicDataFeignClient dicDataFeignClient;
@Override
@Transactional(rollbackFor = Exception.class)
public void record() {
DictData dip = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_DIP.getCode()).getData();
DictData rise = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_RISE.getCode()).getData();
DictTreeVO windFarms = dictTreeFeignClient.queryByCode(DicTreeEnum.Wind_Farms.getCode()).getData();
DictTreeVO powerStation = dictTreeFeignClient.queryByCode(DicTreeEnum.Power_Station.getCode()).getData();
LocalDateTime currentTime = LocalDateTime.now();
//获取最新的暂态事件信息(截至目前为止)
List<RmpEventDetailPO> evenStDetailPOS = eventDetailFeignClient.getNewEventDetailByTime(getLastTime(),currentTime).getData();
MonitorTerminalParam monitorTerminalParam = new MonitorTerminalParam();
monitorTerminalParam.setSystemType(0);
monitorTerminalParam.setType(0);
for(RmpEventDetailPO rmpEventDetailPO : evenStDetailPOS){
//获取监测点
LineDTO lineDTO = commLineClient.getLineDetail(rmpEventDetailPO.getMeasurementPointId()).getData();
if(lineDTO != null && lineDTO.getNewStationId() != null){
//监测点必须绑定新能源场站
NewStation newStation = newStationClient.selectById(lineDTO.getNewStationId()).getData();
if(newStation != null){
//事件不能重复统计(除非事件的暂降类型及变电站类型发生变化)
//获取带新能源场站的监测点
List<String> lineIds = deptLineFeignClient.getLineByDeptIdAndNewStation(null).getData();
if (CollUtil.isNotEmpty(lineIds)) {
List<LineDetailDataVO> lineDetailDataVOS = lineFeignClient.getLineDetailList(lineIds).getData();
Map<String, LineDetailDataVO> lineDetailDataMap = lineDetailDataVOS.stream().collect(Collectors.toMap(LineDetailDataVO::getLineId, Function.identity()));
List<String> objIds = lineDetailDataVOS.stream().map(LineDetailDataVO::getObyId).distinct().collect(Collectors.toList());
List<NewUserReportVO> userReportVOS = userLedgerFeignClient.getUserReportByIds(objIds).getData();
Map<String, Double> userReportMap = userReportVOS.stream().collect(Collectors.toMap(NewUserReportVO::getId, NewUserReportVO::getRatePower));
EventCountParam param = new EventCountParam();
param.setIds(lineIds);
param.setStartTime(getLastTime().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
param.setEndTime(currentTime.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
List<RmpEventDetailPO> evenStDetailPOS = eventDetailFeignClient.getNewEventDetailByTime(param).getData();
MonitorTerminalParam monitorTerminalParam = new MonitorTerminalParam();
monitorTerminalParam.setSystemType(0);
monitorTerminalParam.setType(0);
for (RmpEventDetailPO rmpEventDetailPO : evenStDetailPOS) {
if (lineDetailDataMap.containsKey(rmpEventDetailPO.getMeasurementPointId())) {
LineDetailDataVO line = lineDetailDataMap.get(rmpEventDetailPO.getMeasurementPointId());
LambdaQueryWrapper<SpThroughPO> lambdaQueryWrapper = new LambdaQueryWrapper();
lambdaQueryWrapper.eq(SpThroughPO::getEventId,rmpEventDetailPO.getEventId())
.eq(SpThroughPO::getEventType,rmpEventDetailPO.getEventType())
.eq(SpThroughPO::getStationType,newStation.getStationType())
.eq(SpThroughPO::getState,1);
if(this.baseMapper.selectList(lambdaQueryWrapper).isEmpty()){
lambdaQueryWrapper.eq(SpThroughPO::getEventId, rmpEventDetailPO.getEventId())
.eq(SpThroughPO::getEventType, rmpEventDetailPO.getEventType())
.eq(SpThroughPO::getStationType, line.getBigObjType())
.eq(SpThroughPO::getState, 1);
if (this.baseMapper.selectList(lambdaQueryWrapper).isEmpty()) {
//准备高低电压穿越实体bean
SpThroughPO spThroughPO = new SpThroughPO();
spThroughPO.setId(IdUtil.simpleUUID());
spThroughPO.setEventId(rmpEventDetailPO.getEventId());
spThroughPO.setEventType(rmpEventDetailPO.getEventType());
spThroughPO.setStationType(newStation.getStationType());
spThroughPO.setStationType(line.getBigObjType());
//默认该事件没有穿越
spThroughPO.setIsOrNot(0);
//设置波形查询的条件:事件ID
@@ -84,79 +114,83 @@ public class SpThroughServiceImpl extends MppServiceImpl<SpThroughMapper, SpThro
WaveDataDTO waveDataDTO = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ObjectInputStream ois = new ObjectInputStream(bis);
//强转成WaveDataDTO
waveDataDTO = (WaveDataDTO)ois.readObject();
waveDataDTO = (WaveDataDTO) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
//标称电压
if(lineDTO.getVoltageLevel()!=null){
Float voltageLevel = Float.parseFloat(lineDTO.getVoltageLevel());
if (line.getScale() != null) {
Float voltageLevel = Float.parseFloat(line.getScale());
//格式化数据源
List<List<Float>> newListRmsData = listRmsDataFormat(waveDataDTO);
//暂升事件
if(Param.UPPEREVENT.equals(rmpEventDetailPO.getEventType())){
if (rmpEventDetailPO.getEventType().equals(rise.getId())) {
//风电场
if(Param.WINDFARM.equals(newStation.getStationType())){
if(isThrough(waveDataDTO,125,130,500,voltageLevel.floatValue(),newListRmsData)
&& isThrough(waveDataDTO,120,125,1000,voltageLevel.floatValue(),newListRmsData)
&& isThrough(waveDataDTO,110,120,10000,voltageLevel.floatValue(),newListRmsData)){
if (line.getBigObjType().equals(windFarms.getId())) {
if (isThrough(waveDataDTO, 125, 130, 500, voltageLevel.floatValue(), newListRmsData)
&& isThrough(waveDataDTO, 120, 125, 1000, voltageLevel.floatValue(), newListRmsData)
&& isThrough(waveDataDTO, 110, 120, 10000, voltageLevel.floatValue(), newListRmsData)) {
spThroughPO.setIsOrNot(1);
}
}
//光伏电站
if(Param.PHOTOVOLTAICPOWER.equals(newStation.getStationType())){
if(isThrough(waveDataDTO,125,130,500,voltageLevel.floatValue(),newListRmsData)
&& isThrough(waveDataDTO,120,125,1000,voltageLevel.floatValue(),newListRmsData)
&& isThrough(waveDataDTO,110,120,10000,voltageLevel.floatValue(),newListRmsData)){
if (line.getBigObjType().equals(powerStation.getId())) {
if (isThrough(waveDataDTO, 125, 130, 500, voltageLevel.floatValue(), newListRmsData)
&& isThrough(waveDataDTO, 120, 125, 1000, voltageLevel.floatValue(), newListRmsData)
&& isThrough(waveDataDTO, 110, 120, 10000, voltageLevel.floatValue(), newListRmsData)) {
spThroughPO.setIsOrNot(1);
}
}
}
//暂降事件
if(Param.LOWEREVENT.equals(rmpEventDetailPO.getEventType())){
if (rmpEventDetailPO.getEventType().equals(dip.getId())) {
//风电场
if(Param.WINDFARM.equals(newStation.getStationType())){
if(isThrough(waveDataDTO,20,-1,625,voltageLevel.floatValue(),newListRmsData)){
if (line.getBigObjType().equals(windFarms.getId())) {
if (isThrough(waveDataDTO, 20, -1, 625, voltageLevel.floatValue(), newListRmsData)) {
spThroughPO.setIsOrNot(1);
}
}
//光伏电站
if(Param.PHOTOVOLTAICPOWER.equals(newStation.getStationType())){
if(isThrough(waveDataDTO,0,-1,150,voltageLevel.floatValue(),newListRmsData)
&& isThrough(waveDataDTO,20,-1,625,voltageLevel.floatValue(),newListRmsData)
&& isThrough(waveDataDTO,20,90,-1,voltageLevel.floatValue(),newListRmsData)){
if (line.getBigObjType().equals(powerStation.getId())) {
if (isThrough(waveDataDTO, 0, -1, 150, voltageLevel.floatValue(), newListRmsData)
&& isThrough(waveDataDTO, 20, -1, 625, voltageLevel.floatValue(), newListRmsData)
&& isThrough(waveDataDTO, 20, 90, -1, voltageLevel.floatValue(), newListRmsData)) {
spThroughPO.setIsOrNot(1);
}
}
}
spThroughPO.setCreateTime(currentTime);
this.baseMapper.insert(spThroughPO);
};
}
;
}
}
}
}
}
private boolean isThrough(WaveDataDTO waveDataDTO,int start,int end,int ms,float voltageLevel,List<List<Float>> newListRmsData){
private boolean isThrough(WaveDataDTO waveDataDTO, int start, int end, int ms, float voltageLevel, List<List<Float>> newListRmsData) {
boolean isThrough = false;
//格式化RMS源数据
float startVoltageLevel = voltageLevel * (start / 100F);
float endVoltageLevel = -1;
if(end!=-1){
if (end != -1) {
endVoltageLevel = voltageLevel * (end / 100F);
}
for (int i = 0; i < newListRmsData.size(); i++) {
for (int j = 1; j < newListRmsData.get(i).size(); j++) {
float curValue = newListRmsData.get(i).get(j);
//当电压达到目标值时
if(endVoltageLevel != -1 && startVoltageLevel < curValue && curValue <= endVoltageLevel){
isContinuity(newListRmsData,i+1,newListRmsData.get(i).get(0).intValue(),ms,j);
if (endVoltageLevel != -1 && startVoltageLevel < curValue && curValue <= endVoltageLevel) {
isContinuity(newListRmsData, i + 1, newListRmsData.get(i).get(0).intValue(), ms, j);
isThrough = true;
}else if(startVoltageLevel == curValue){
isContinuity(newListRmsData,i+1,newListRmsData.get(i).get(0).intValue(),ms,j);
} else if (startVoltageLevel == curValue) {
isContinuity(newListRmsData, i + 1, newListRmsData.get(i).get(0).intValue(), ms, j);
isThrough = true;
}
}
@@ -164,11 +198,11 @@ public class SpThroughServiceImpl extends MppServiceImpl<SpThroughMapper, SpThro
return isThrough;
}
private boolean isContinuity(List<List<Float>> newListRmsData,int index,int curms,int ms,int p){
private boolean isContinuity(List<List<Float>> newListRmsData, int index, int curms, int ms, int p) {
boolean isContinuity = false;
//记录电压有效毫秒数
Set<Integer> effectiveMs = new HashSet<>();
for (int k = curms + 1 ; k <= curms + ms; k++) {
for (int k = curms + 1; k <= curms + ms; k++) {
effectiveMs.add(k);
}
int count = 0;
@@ -176,18 +210,18 @@ public class SpThroughServiceImpl extends MppServiceImpl<SpThroughMapper, SpThro
for (int j = 0; j < newListRmsData.get(i).size(); j++) {
int curVallue = newListRmsData.get(i).get(0).intValue();
//如果当前相别的电压毫秒数在有效期范围内则记录下数字
if(effectiveMs.contains(curVallue) && checkListIsNull(newListRmsData.get(i),p)!=null){
count ++;
if (effectiveMs.contains(curVallue) && checkListIsNull(newListRmsData.get(i), p) != null) {
count++;
}
}
}
if(count >= effectiveMs.size()){
if (count >= effectiveMs.size()) {
isContinuity = true;
}
return isContinuity;
}
private Float checkListIsNull(List<Float> list ,int index){
private Float checkListIsNull(List<Float> list, int index) {
try {
return list.get(index);
} catch (Exception e) {
@@ -195,13 +229,19 @@ public class SpThroughServiceImpl extends MppServiceImpl<SpThroughMapper, SpThro
}
}
//格式化RMS数据:将listRmsData中的电压数据取出在根据pt变比组成新的RMS数据
private List<List<Float>> listRmsDataFormat(WaveDataDTO waveDataDTO){
/**
* @param waveDataDTO
* @Description: 格式化RMS数据:将listRmsData中的电压数据取出在根据pt变比组成新的RMS数据
* @return: java.util.List<java.util.List < java.lang.Float>>
* @Author: wr
* @Date: 2025/3/26 19:49
*/
private List<List<Float>> listRmsDataFormat(WaveDataDTO waveDataDTO) {
List<List<Float>> newListRmsData = new ArrayList<>();
List<Integer> indexs = new ArrayList<>();
//根据channelNames取出电压对应listRmsData数据中的数据索引
for (int i = 0; i < waveDataDTO.getChannelNames().size(); i++) {
if(waveDataDTO.getChannelNames().get(i).indexOf("电压")!=-1){
if (waveDataDTO.getChannelNames().get(i).indexOf("电压") != -1) {
indexs.add(i);
}
}
@@ -212,22 +252,27 @@ public class SpThroughServiceImpl extends MppServiceImpl<SpThroughMapper, SpThro
//数组第一个为时间
newCur.add(cur.get(0));
//便利电压数据的索引
for(Integer index : indexs){
for (Integer index : indexs) {
//根据PT变比算出新的数据(前端取的一次值,也是根据pt变比算出的,所以这边和前端保持一致)新增到新的数组中
newCur.add(cur.get(index) * Float.parseFloat((waveDataDTO.getPt() / 1000F)+""));
newCur.add(cur.get(index) * Float.parseFloat((waveDataDTO.getPt() / 1000F) + ""));
}
newListRmsData.add(newCur);
}
return newListRmsData;
}
//拿到最近一次插入高低电压穿越表信息的时间
private LocalDateTime getLastTime(){
/**
* 说明:
* 此方法是专门提供给event模块-高低压穿越模块中-获取最新一条暂态事件时间使用
*
* @return
*/
private LocalDateTime getLastTime() {
LambdaQueryWrapper<SpThroughPO> lambdaQueryWrapper = new LambdaQueryWrapper();
lambdaQueryWrapper.orderByDesc(SpThroughPO::getCreateTime);
Page<SpThroughPO> page = new Page<>(1, 1);
List<SpThroughPO> spThroughPOS = this.baseMapper.selectPage(page,lambdaQueryWrapper).getRecords();
if(!spThroughPOS.isEmpty()){
List<SpThroughPO> spThroughPOS = this.baseMapper.selectPage(page, lambdaQueryWrapper).getRecords();
if (!spThroughPOS.isEmpty()) {
return spThroughPOS.get(0).getCreateTime();
}
return null;
@@ -236,42 +281,63 @@ public class SpThroughServiceImpl extends MppServiceImpl<SpThroughMapper, SpThro
@Override
public SpThroughVO getDataByEventIds(SpThroughParam spThroughParam) {
SpThroughVO spThroughVO = new SpThroughVO();
LambdaQueryWrapper<SpThroughPO> upperLambdaQueryWrapper = new LambdaQueryWrapper();
upperLambdaQueryWrapper.in(SpThroughPO::getEventId,spThroughParam.getEventIds())
.eq(SpThroughPO::getIsOrNot,1)
.eq(SpThroughPO::getStationType,spThroughParam.getStationType().equals("1")?Param.WINDFARM:Param.PHOTOVOLTAICPOWER)
.eq(SpThroughPO::getState,1)
.eq(SpThroughPO::getEventType,Param.UPPEREVENT);
Integer upperCount = this.baseMapper.selectCount(upperLambdaQueryWrapper);
spThroughVO.setHighPressure(upperCount == 0?"0":upperCount.toString());
LambdaQueryWrapper<SpThroughPO> lowLambdaQueryWrapper = new LambdaQueryWrapper();
lowLambdaQueryWrapper.in(SpThroughPO::getEventId,spThroughParam.getEventIds())
.eq(SpThroughPO::getIsOrNot,1)
.eq(SpThroughPO::getStationType,spThroughParam.getStationType().equals("1")?Param.WINDFARM:Param.PHOTOVOLTAICPOWER)
.eq(SpThroughPO::getState,1)
.eq(SpThroughPO::getEventType,Param.LOWEREVENT);
Integer lowCount = this.baseMapper.selectCount(lowLambdaQueryWrapper);
spThroughVO.setLowPressure(lowCount == 0?"0":lowCount.toString());
spThroughVO.setLowPressure("0");
spThroughVO.setHighPressure("0");
String treeId = dicTreeId(spThroughParam);
DictData dip = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_DIP.getCode()).getData();
if (ObjectUtil.isNotNull(dip)) {
spThroughVO.setHighPressure(eventCount(spThroughParam, treeId, dip) + "");
}
DictData rise = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_RISE.getCode()).getData();
if (ObjectUtil.isNotNull(rise)) {
spThroughVO.setLowPressure(eventCount(spThroughParam, treeId, rise) + "");
}
return spThroughVO;
}
private Integer eventCount(SpThroughParam spThroughParam, String dictTreeId, DictData rise) {
LambdaQueryWrapper<SpThroughPO> lowLambdaQueryWrapper = new LambdaQueryWrapper();
lowLambdaQueryWrapper.in(SpThroughPO::getEventId, spThroughParam.getEventIds())
.eq(SpThroughPO::getIsOrNot, 1)
.eq(SpThroughPO::getStationType, dictTreeId)
.eq(SpThroughPO::getState, 1)
.eq(SpThroughPO::getEventType, rise.getId());
return this.baseMapper.selectCount(lowLambdaQueryWrapper);
}
/**
* 说明:
* 此方法是专门提供给event模块-高低压穿越模块中-根据区域获取暂态事件列表使用
* 根据区域获取各个子区域高低电压穿越次数是基于sp_through表中记录来的 那么在根据区域获取暂态事件列表数据也应该基于sp_through表中记录来
* 因为如果不基于sp_through表中记录来 那么根据区域获取暂态事件可能数据非常多且可能一部分的事件数据并没有被定时任务(record方法)所执行
*
* @param spThroughParam
* @return
*/
@Override
public List<String> formatEventIds(SpThroughParam spThroughParam) {
LambdaQueryWrapper<SpThroughPO> lambdaQueryWrapper = new LambdaQueryWrapper();
lambdaQueryWrapper.in(SpThroughPO::getEventId,spThroughParam.getEventIds())
.eq(SpThroughPO::getIsOrNot,1)
.eq(SpThroughPO::getStationType,spThroughParam.getStationType().equals("1")?Param.WINDFARM:Param.PHOTOVOLTAICPOWER)
.eq(SpThroughPO::getState,1);
lambdaQueryWrapper.in(SpThroughPO::getEventId, spThroughParam.getEventIds())
.eq(SpThroughPO::getIsOrNot, 1)
.eq(SpThroughPO::getStationType, dicTreeId(spThroughParam))
.eq(SpThroughPO::getState, 1);
List<SpThroughPO> spThroughPOS = this.baseMapper.selectList(lambdaQueryWrapper);
return spThroughPOS.stream().map(SpThroughPO::getEventId).collect(Collectors.toList());
}
private String dicTreeId(SpThroughParam spThroughParam) {
String dictTreeId = "";
if (spThroughParam.getStationType().equals("1")) {
DictTreeVO windFarms = dictTreeFeignClient.queryByCode(DicTreeEnum.Wind_Farms.getCode()).getData();
if (ObjectUtil.isNotNull(windFarms)) {
dictTreeId = windFarms.getId();
}
} else {
DictTreeVO powerStation = dictTreeFeignClient.queryByCode(DicTreeEnum.Power_Station.getCode()).getData();
if (ObjectUtil.isNotNull(powerStation)) {
dictTreeId = powerStation.getId();
}
}
return dictTreeId;
}
}