波形解析相关
This commit is contained in:
@@ -5,9 +5,11 @@ import com.njcn.common.pojo.enums.common.LogEnum;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import com.njcn.common.utils.LogUtil;
|
||||
import com.njcn.gather.tool.wave.param.WaveParseParam;
|
||||
import com.njcn.gather.tool.wave.pojo.param.WaveComtradeParseParam;
|
||||
import com.njcn.gather.tool.wave.pojo.param.WaveParseParam;
|
||||
import com.njcn.gather.tool.wave.service.WaveService;
|
||||
import com.njcn.gather.tool.wave.vo.WaveParseResultVO;
|
||||
import com.njcn.gather.tool.wave.pojo.vo.WaveComtradeResultVO;
|
||||
import com.njcn.gather.tool.wave.pojo.vo.WaveParseResultVO;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
import com.njcn.web.utils.HttpResultUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -15,11 +17,19 @@ import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
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.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 波形查看接口。
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "波形查看")
|
||||
@RestController
|
||||
@@ -27,16 +37,44 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequiredArgsConstructor
|
||||
public class WaveController extends BaseController {
|
||||
|
||||
/** 波形解析服务。 */
|
||||
private final WaveService waveService;
|
||||
|
||||
/**
|
||||
* 解析文本波形内容。
|
||||
*
|
||||
* @param param 波形解析参数
|
||||
* @return 波形解析结果
|
||||
*/
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("解析波形文本")
|
||||
@ApiImplicitParam(name = "param", value = "波形解析参数", required = true, dataType = "WaveParseParam")
|
||||
@PostMapping("/parse")
|
||||
public HttpResult<WaveParseResultVO> parse(@RequestBody WaveParseParam param) {
|
||||
String methodDescribe = getMethodDescribe("parse");
|
||||
LogUtil.njcnDebug(log, "{},开始解析波形文本", methodDescribe);
|
||||
LogUtil.njcnDebug(log, "{},开始解析文本波形", methodDescribe);
|
||||
WaveParseResultVO result = waveService.parse(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 COMTRADE 波形文件。
|
||||
*
|
||||
* @param cfgFile cfg 文件
|
||||
* @param datFile dat 文件
|
||||
* @param param 解析参数
|
||||
* @return COMTRADE 解析结果
|
||||
* @throws IOException 读取上传文件流失败时抛出
|
||||
*/
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("解析 COMTRADE 波形文件")
|
||||
@PostMapping("/parseComtrade")
|
||||
public HttpResult<WaveComtradeResultVO> parseComtrade(@RequestParam("cfgFile") MultipartFile cfgFile,
|
||||
@RequestParam("datFile") MultipartFile datFile,
|
||||
@ModelAttribute WaveComtradeParseParam param) throws IOException {
|
||||
String methodDescribe = getMethodDescribe("parseComtrade");
|
||||
LogUtil.njcnDebug(log, "{},开始解析 COMTRADE 波形文件", methodDescribe);
|
||||
WaveComtradeResultVO result = waveService.parseComtrade(cfgFile.getInputStream(), datFile.getInputStream(), param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package com.njcn.gather.tool.wave.param;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@ApiModel("波形解析参数")
|
||||
public class WaveParseParam {
|
||||
|
||||
@ApiModelProperty(value = "波形文本内容,支持单列幅值、单行多值或双列时间/幅值数据", required = true)
|
||||
private String waveformText;
|
||||
|
||||
@ApiModelProperty(value = "分隔符,默认 AUTO 自动识别,支持直接传入具体字符,也支持 TAB 或 SPACE")
|
||||
private String separator;
|
||||
|
||||
@ApiModelProperty(value = "是否包含 X 轴列,true 表示文本中显式传入时间列")
|
||||
private Boolean containsXAxis;
|
||||
|
||||
@ApiModelProperty(value = "X 轴列下标,默认 0")
|
||||
private Integer xColumnIndex;
|
||||
|
||||
@ApiModelProperty(value = "Y 轴列下标,单列波形默认 0,双列波形默认 1")
|
||||
private Integer yColumnIndex;
|
||||
|
||||
@ApiModelProperty(value = "跳过的表头行数,默认 0")
|
||||
private Integer skipHeaderLines;
|
||||
|
||||
@ApiModelProperty(value = "单列波形的采样间隔,默认 1")
|
||||
private BigDecimal samplingInterval;
|
||||
|
||||
@ApiModelProperty(value = "返回的最大点位数,超过时自动下采样,默认 2000")
|
||||
private Integer maxPointCount;
|
||||
}
|
||||
@@ -1,15 +1,32 @@
|
||||
package com.njcn.gather.tool.wave.service;
|
||||
|
||||
import com.njcn.gather.tool.wave.param.WaveParseParam;
|
||||
import com.njcn.gather.tool.wave.vo.WaveParseResultVO;
|
||||
import com.njcn.gather.tool.wave.pojo.param.WaveComtradeParseParam;
|
||||
import com.njcn.gather.tool.wave.pojo.param.WaveParseParam;
|
||||
import com.njcn.gather.tool.wave.pojo.vo.WaveComtradeResultVO;
|
||||
import com.njcn.gather.tool.wave.pojo.vo.WaveParseResultVO;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 波形解析服务。
|
||||
*/
|
||||
public interface WaveService {
|
||||
|
||||
/**
|
||||
* 解析波形文本并输出适合查看的点位结果。
|
||||
* 解析文本波形并输出前端可直接展示的点位结果。
|
||||
*
|
||||
* @param param 波形解析参数
|
||||
* @return 波形查看结果
|
||||
*/
|
||||
WaveParseResultVO parse(WaveParseParam param);
|
||||
|
||||
/**
|
||||
* 解析 COMTRADE cfg/dat 波形文件。
|
||||
*
|
||||
* @param cfgStream cfg 输入流
|
||||
* @param datStream dat 输入流
|
||||
* @param param 解析参数
|
||||
* @return COMTRADE 解析结果
|
||||
*/
|
||||
WaveComtradeResultVO parseComtrade(InputStream cfgStream, InputStream datStream, WaveComtradeParseParam param);
|
||||
}
|
||||
|
||||
@@ -3,13 +3,22 @@ package com.njcn.gather.tool.wave.service.impl;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.gather.tool.wave.param.WaveParseParam;
|
||||
import com.njcn.gather.tool.wave.component.WaveFileComponent;
|
||||
import com.njcn.gather.tool.wave.pojo.bo.WaveDataDetail;
|
||||
import com.njcn.gather.tool.wave.pojo.dto.EigenvalueDTO;
|
||||
import com.njcn.gather.tool.wave.pojo.dto.WaveDataDTO;
|
||||
import com.njcn.gather.tool.wave.pojo.param.WaveComtradeParseParam;
|
||||
import com.njcn.gather.tool.wave.pojo.param.WaveParseParam;
|
||||
import com.njcn.gather.tool.wave.service.WaveService;
|
||||
import com.njcn.gather.tool.wave.vo.WaveParseResultVO;
|
||||
import com.njcn.gather.tool.wave.vo.WavePointVO;
|
||||
import com.njcn.gather.tool.wave.utils.WaveUtil;
|
||||
import com.njcn.gather.tool.wave.pojo.vo.WaveComtradeResultVO;
|
||||
import com.njcn.gather.tool.wave.pojo.vo.WaveParseResultVO;
|
||||
import com.njcn.gather.tool.wave.pojo.vo.WavePointVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
@@ -17,13 +26,34 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 波形解析服务实现。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WaveServiceImpl implements WaveService {
|
||||
|
||||
/** 文本波形默认最大返回点数。 */
|
||||
private static final int DEFAULT_MAX_POINT_COUNT = 2000;
|
||||
/** 自动识别分隔符标记。 */
|
||||
private static final String AUTO_SEPARATOR = "AUTO";
|
||||
/** COMTRADE 默认解析类型。 */
|
||||
private static final int DEFAULT_PARSE_TYPE = 1;
|
||||
/** PT/CT 默认变比。 */
|
||||
private static final double DEFAULT_RATIO = 1D;
|
||||
/** PT 默认接线方式,0 表示星形。 */
|
||||
private static final int DEFAULT_PT_TYPE = 0;
|
||||
|
||||
/** 波形文件解析组件。 */
|
||||
private final WaveFileComponent waveFileComponent;
|
||||
|
||||
/**
|
||||
* 解析文本波形。
|
||||
*
|
||||
* @param param 波形解析参数
|
||||
* @return 文本波形结果
|
||||
*/
|
||||
@Override
|
||||
public WaveParseResultVO parse(WaveParseParam param) {
|
||||
if (param == null || StrUtil.isBlank(param.getWaveformText())) {
|
||||
@@ -55,8 +85,7 @@ public class WaveServiceImpl implements WaveService {
|
||||
}
|
||||
try {
|
||||
if (containsXAxis) {
|
||||
WavePointVO point = buildPoint(columns, xColumnIndex, yColumnIndex);
|
||||
sourcePoints.add(point);
|
||||
sourcePoints.add(buildPoint(columns, xColumnIndex, yColumnIndex));
|
||||
} else {
|
||||
sourcePoints.addAll(buildSingleColumnPoints(columns, samplingInterval, sourcePoints.size()));
|
||||
}
|
||||
@@ -71,26 +100,128 @@ public class WaveServiceImpl implements WaveService {
|
||||
}
|
||||
|
||||
List<WavePointVO> displayPoints = downSample(sourcePoints, maxPointCount);
|
||||
return buildResult(sourcePoints, displayPoints, ignoredLineCount, containsXAxis);
|
||||
return buildTextResult(sourcePoints, displayPoints, ignoredLineCount, containsXAxis);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 COMTRADE 波形文件。
|
||||
*
|
||||
* @param cfgStream cfg 输入流
|
||||
* @param datStream dat 输入流
|
||||
* @param param 解析参数
|
||||
* @return COMTRADE 解析结果
|
||||
*/
|
||||
@Override
|
||||
public WaveComtradeResultVO parseComtrade(InputStream cfgStream, InputStream datStream, WaveComtradeParseParam param) {
|
||||
if (cfgStream == null || datStream == null) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "cfg 或 dat 文件不能为空");
|
||||
}
|
||||
|
||||
WaveComtradeParseParam resolvedParam = param == null ? new WaveComtradeParseParam() : param;
|
||||
try (InputStream cfgInputStream = cfgStream; InputStream datInputStream = datStream) {
|
||||
WaveDataDTO waveDataDTO = waveFileComponent.getComtrade(cfgInputStream, datInputStream, sanitizeParseType(resolvedParam.getParseType()));
|
||||
applyWaveMetadata(waveDataDTO, resolvedParam);
|
||||
|
||||
boolean needRms = shouldCalculateRms(resolvedParam);
|
||||
boolean buildDetails = shouldBuildDetails(resolvedParam);
|
||||
boolean calculateEigenvalue = Boolean.TRUE.equals(resolvedParam.getCalculateEigenvalue());
|
||||
|
||||
if (needRms || buildDetails || calculateEigenvalue) {
|
||||
waveDataDTO = waveFileComponent.getValidData(waveDataDTO);
|
||||
}
|
||||
|
||||
WaveComtradeResultVO result = new WaveComtradeResultVO();
|
||||
result.setWaveData(waveDataDTO);
|
||||
List<WaveDataDetail> waveDataDetails = null;
|
||||
if (buildDetails) {
|
||||
waveDataDetails = WaveUtil.filterWaveData(waveDataDTO);
|
||||
result.setWaveDataDetails(waveDataDetails);
|
||||
}
|
||||
if (calculateEigenvalue) {
|
||||
List<EigenvalueDTO> eigenvalues = waveFileComponent.getEigenvalue(
|
||||
waveDataDTO,
|
||||
resolvedParam.getDynamicThreshold() == null || resolvedParam.getDynamicThreshold()
|
||||
);
|
||||
result.setEigenvalues(eigenvalues);
|
||||
}
|
||||
return result;
|
||||
} catch (BusinessException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
log.error("COMTRADE 波形解析失败", ex);
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "COMTRADE 波形解析失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将请求中的 PT、CT、测点等参数写回波形结果。
|
||||
*/
|
||||
private void applyWaveMetadata(WaveDataDTO waveDataDTO, WaveComtradeParseParam param) {
|
||||
waveDataDTO.setPt(defaultIfNull(param.getPt(), DEFAULT_RATIO));
|
||||
waveDataDTO.setCt(defaultIfNull(param.getCt(), DEFAULT_RATIO));
|
||||
waveDataDTO.setPtType(param.getPtType() == null ? DEFAULT_PT_TYPE : param.getPtType());
|
||||
waveDataDTO.setMonitorName(StrUtil.blankToDefault(param.getMonitorName(), "未命名测点"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否需要计算 RMS 数据。
|
||||
*/
|
||||
private boolean shouldCalculateRms(WaveComtradeParseParam param) {
|
||||
return param.getCalculateRms() == null || param.getCalculateRms();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否需要构建前端查看明细。
|
||||
*/
|
||||
private boolean shouldBuildDetails(WaveComtradeParseParam param) {
|
||||
return param.getBuildDetails() == null || param.getBuildDetails();
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化解析类型参数。
|
||||
*/
|
||||
private int sanitizeParseType(Integer parseType) {
|
||||
if (parseType == null || parseType < 0 || parseType > 3) {
|
||||
return DEFAULT_PARSE_TYPE;
|
||||
}
|
||||
return parseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为空或非正数时返回默认比例。
|
||||
*/
|
||||
private double defaultIfNull(Double value, double defaultValue) {
|
||||
if (value == null || value <= 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定列构建一个波形点。
|
||||
*/
|
||||
private WavePointVO buildPoint(String[] columns, int xColumnIndex, int yColumnIndex) {
|
||||
BigDecimal yValue = parseNumber(readColumn(columns, yColumnIndex));
|
||||
BigDecimal xValue = parseNumber(readColumn(columns, xColumnIndex));
|
||||
return new WavePointVO(xValue, yValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将单列数值按采样间隔扩展为点位列表。
|
||||
*/
|
||||
private List<WavePointVO> buildSingleColumnPoints(String[] columns, BigDecimal samplingInterval, int startIndex) {
|
||||
List<WavePointVO> points = new ArrayList<>();
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
BigDecimal yValue = parseNumber(columns[i]);
|
||||
// 单列波形默认按采样间隔自动补齐 X 轴,便于前端直接绘制。
|
||||
BigDecimal xValue = samplingInterval.multiply(BigDecimal.valueOf(startIndex + i));
|
||||
points.add(new WavePointVO(xValue, yValue));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取指定列内容。
|
||||
*/
|
||||
private String readColumn(String[] columns, int columnIndex) {
|
||||
if (columnIndex < 0 || columnIndex >= columns.length) {
|
||||
throw new IllegalArgumentException("列下标超出范围");
|
||||
@@ -98,13 +229,19 @@ public class WaveServiceImpl implements WaveService {
|
||||
return columns[columnIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转换为数值。
|
||||
*/
|
||||
private BigDecimal parseNumber(String value) {
|
||||
if (StrUtil.isBlank(value)) {
|
||||
throw new IllegalArgumentException("数值为空");
|
||||
throw new IllegalArgumentException("数值不能为空");
|
||||
}
|
||||
return new BigDecimal(value.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* 按分隔符规则拆分文本列。
|
||||
*/
|
||||
private String[] splitColumns(String line, String separator) {
|
||||
String trimmedLine = line.trim();
|
||||
if (StrUtil.isBlank(trimmedLine)) {
|
||||
@@ -126,6 +263,9 @@ public class WaveServiceImpl implements WaveService {
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对过多的点位执行简单下采样。
|
||||
*/
|
||||
private List<WavePointVO> downSample(List<WavePointVO> sourcePoints, int maxPointCount) {
|
||||
if (sourcePoints.size() <= maxPointCount) {
|
||||
return sourcePoints;
|
||||
@@ -145,8 +285,11 @@ public class WaveServiceImpl implements WaveService {
|
||||
return result;
|
||||
}
|
||||
|
||||
private WaveParseResultVO buildResult(List<WavePointVO> sourcePoints, List<WavePointVO> displayPoints,
|
||||
int ignoredLineCount, boolean containsXAxis) {
|
||||
/**
|
||||
* 组装文本波形解析结果。
|
||||
*/
|
||||
private WaveParseResultVO buildTextResult(List<WavePointVO> sourcePoints, List<WavePointVO> displayPoints,
|
||||
int ignoredLineCount, boolean containsXAxis) {
|
||||
BigDecimal minX = sourcePoints.get(0).getX();
|
||||
BigDecimal maxX = sourcePoints.get(0).getX();
|
||||
BigDecimal minY = sourcePoints.get(0).getY();
|
||||
@@ -184,6 +327,9 @@ public class WaveServiceImpl implements WaveService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化跳过表头行数。
|
||||
*/
|
||||
private int sanitizeSkipHeaderLines(Integer skipHeaderLines) {
|
||||
if (skipHeaderLines == null || skipHeaderLines < 0) {
|
||||
return 0;
|
||||
@@ -191,6 +337,9 @@ public class WaveServiceImpl implements WaveService {
|
||||
return skipHeaderLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化最大点数限制。
|
||||
*/
|
||||
private int sanitizeMaxPointCount(Integer maxPointCount) {
|
||||
if (maxPointCount == null || maxPointCount <= 0) {
|
||||
return DEFAULT_MAX_POINT_COUNT;
|
||||
@@ -198,6 +347,9 @@ public class WaveServiceImpl implements WaveService {
|
||||
return maxPointCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化列下标。
|
||||
*/
|
||||
private int sanitizeColumnIndex(Integer columnIndex, int defaultValue) {
|
||||
if (columnIndex == null || columnIndex < 0) {
|
||||
return defaultValue;
|
||||
@@ -205,6 +357,9 @@ public class WaveServiceImpl implements WaveService {
|
||||
return columnIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化采样间隔。
|
||||
*/
|
||||
private BigDecimal sanitizeSamplingInterval(BigDecimal samplingInterval) {
|
||||
if (samplingInterval == null || samplingInterval.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return BigDecimal.ONE;
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.njcn.gather.tool.wave.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ApiModel("波形解析结果")
|
||||
public class WaveParseResultVO {
|
||||
|
||||
@ApiModelProperty("是否包含显式 X 轴")
|
||||
private Boolean containsXAxis;
|
||||
|
||||
@ApiModelProperty("原始有效点位数")
|
||||
private Integer sourcePointCount;
|
||||
|
||||
@ApiModelProperty("返回的显示点位数")
|
||||
private Integer displayPointCount;
|
||||
|
||||
@ApiModelProperty("被忽略的无效行数")
|
||||
private Integer ignoredLineCount;
|
||||
|
||||
@ApiModelProperty("是否发生下采样")
|
||||
private Boolean sampled;
|
||||
|
||||
@ApiModelProperty("X 轴最小值")
|
||||
private BigDecimal minX;
|
||||
|
||||
@ApiModelProperty("X 轴最大值")
|
||||
private BigDecimal maxX;
|
||||
|
||||
@ApiModelProperty("Y 轴最小值")
|
||||
private BigDecimal minY;
|
||||
|
||||
@ApiModelProperty("Y 轴最大值")
|
||||
private BigDecimal maxY;
|
||||
|
||||
@ApiModelProperty("Y 轴平均值")
|
||||
private BigDecimal averageY;
|
||||
|
||||
@ApiModelProperty("用于查看的波形点位")
|
||||
private List<WavePointVO> points;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.njcn.gather.tool.wave.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ApiModel("波形点位")
|
||||
public class WavePointVO {
|
||||
|
||||
@ApiModelProperty("X 轴值")
|
||||
private BigDecimal x;
|
||||
|
||||
@ApiModelProperty("Y 轴值")
|
||||
private BigDecimal y;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,303 +0,0 @@
|
||||
package com.njcn.event.file.component;
|
||||
|
||||
import cn.hutool.core.img.ImgUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.common.utils.FileUtil;
|
||||
import com.njcn.echarts.pojo.constant.PicCommonData;
|
||||
import com.njcn.echarts.util.DrawPicUtil;
|
||||
import com.njcn.event.file.pojo.bo.WaveDataDetail;
|
||||
import com.njcn.event.file.pojo.dto.WaveDataDTO;
|
||||
import com.njcn.event.file.pojo.enums.WaveFileResponseEnum;
|
||||
import com.njcn.oss.constant.OssPath;
|
||||
import com.njcn.oss.utils.FileStorageUtil;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import sun.awt.image.BufferedImageGraphicsConfig;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2023年09月21日 09:18
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class WavePicComponent {
|
||||
|
||||
private final DrawPicUtil drawPicUtil;
|
||||
|
||||
private final FileStorageUtil fileStorageUtil;
|
||||
|
||||
|
||||
/***
|
||||
* 绘制瞬时波形图治理
|
||||
* @author hongawen
|
||||
* @date 2023/9/21 15:32
|
||||
* @return String 文件地址
|
||||
*/
|
||||
public String generateInstantImageZl(List<WaveDataDetail> waveDataDetails) {
|
||||
String firstPic = null, secondPic = null, thirdPic = null, forthPic = null;
|
||||
for (WaveDataDetail waveDataDetail : waveDataDetails) {
|
||||
if (waveDataDetail.getChannelName().toUpperCase().startsWith("SU")) {
|
||||
firstPic = drawPicUtil.drawWavePic("电压-电网侧", waveDataDetail.getInstantData().getAValue(),
|
||||
waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
} else if (waveDataDetail.getChannelName().toUpperCase().startsWith("SI")) {
|
||||
thirdPic = drawPicUtil.drawWavePic("电流-电网侧", waveDataDetail.getInstantData().getAValue(),
|
||||
waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
} else if (waveDataDetail.getChannelName().toUpperCase().startsWith("LU")) {
|
||||
secondPic = drawPicUtil.drawWavePic("电压-负载侧", waveDataDetail.getInstantData().getAValue(),
|
||||
waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
} else {
|
||||
forthPic = drawPicUtil.drawWavePic("电流-负载侧", waveDataDetail.getInstantData().getAValue(),
|
||||
waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
}
|
||||
}
|
||||
return composeImageZl(firstPic, secondPic, thirdPic, forthPic);
|
||||
}
|
||||
|
||||
/***
|
||||
* 绘制RMS波形图治理
|
||||
* @author hongawen
|
||||
* @date 2023/9/21 15:32
|
||||
* @return String 文件地址
|
||||
*/
|
||||
public String generateRmsImageZl(List<WaveDataDetail> waveDataDetails) {
|
||||
String firstPic = null, secondPic = null, thirdPic = null, forthPic = null;
|
||||
for (WaveDataDetail waveDataDetail : waveDataDetails) {
|
||||
if (waveDataDetail.getChannelName().toUpperCase().startsWith("SU")) {
|
||||
firstPic = drawPicUtil.drawWavePic("电压-电网侧", waveDataDetail.getRmsData().getAValue(),
|
||||
waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
} else if (waveDataDetail.getChannelName().toUpperCase().startsWith("SI")) {
|
||||
thirdPic = drawPicUtil.drawWavePic("电流-电网侧", waveDataDetail.getRmsData().getAValue(),
|
||||
waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
} else if (waveDataDetail.getChannelName().toUpperCase().startsWith("LU")) {
|
||||
secondPic = drawPicUtil.drawWavePic("电压-负载侧", waveDataDetail.getRmsData().getAValue(),
|
||||
waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
} else {
|
||||
forthPic = drawPicUtil.drawWavePic("电流-负载侧", waveDataDetail.getRmsData().getAValue(),
|
||||
waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
}
|
||||
}
|
||||
return composeImageZl(firstPic, secondPic, thirdPic, forthPic);
|
||||
}
|
||||
|
||||
/***
|
||||
* 合并4个原图
|
||||
* @author hongawen
|
||||
* @date 2023/9/28 14:45
|
||||
* @return String
|
||||
*/
|
||||
private String composeImageZl(String firstPic, String secondPic, String thirdPic, String forthPic) {
|
||||
try {
|
||||
//第一张图片 base64截取删除前缀data:image/png;base64,
|
||||
BufferedImage imageOne = ImgUtil.toBufferedImage(ImgUtil.toImage(firstPic.substring(22)), ImgUtil.IMAGE_TYPE_PNG);
|
||||
int width = imageOne.getWidth();
|
||||
int height = imageOne.getHeight();
|
||||
int[] imageArrayOne = new int[width * height];
|
||||
imageArrayOne = imageOne.getRGB(0, 0, width, height, imageArrayOne, 0, width);
|
||||
//第二张图片 base64截取删除前缀data:image/png;base64,
|
||||
BufferedImage imageTwo = ImgUtil.toBufferedImage(ImgUtil.toImage(secondPic.substring(22)), ImgUtil.IMAGE_TYPE_PNG);
|
||||
int[] ImageArrayTwo = new int[width * height];
|
||||
ImageArrayTwo = imageTwo.getRGB(0, 0, width, height, ImageArrayTwo, 0, width);
|
||||
//第三张图片 base64截取删除前缀data:image/png;base64,
|
||||
BufferedImage imageThree = ImgUtil.toBufferedImage(ImgUtil.toImage(thirdPic.substring(22)), ImgUtil.IMAGE_TYPE_PNG);
|
||||
int[] ImageArrayThree = new int[width * height];
|
||||
ImageArrayThree = imageThree.getRGB(0, 0, width, height, ImageArrayThree, 0, width);
|
||||
//第四张图片 base64截取删除前缀data:image/png;base64,
|
||||
BufferedImage imageForth = ImgUtil.toBufferedImage(ImgUtil.toImage(forthPic.substring(22)), ImgUtil.IMAGE_TYPE_PNG);
|
||||
int[] ImageArrayForth = new int[width * height];
|
||||
ImageArrayForth = imageForth.getRGB(0, 0, width, height, ImageArrayForth, 0, width);
|
||||
//新图片
|
||||
BufferedImage imageNew = new BufferedImage(width, height * 4, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImageGraphicsConfig config = BufferedImageGraphicsConfig.getConfig(imageNew);
|
||||
imageNew = config.createCompatibleImage(width, height * 4, Transparency.TRANSLUCENT);
|
||||
imageNew.setRGB(0, 0, width, height, imageArrayOne, 0, width);
|
||||
imageNew.setRGB(0, height, width, height, ImageArrayTwo, 0, width);
|
||||
imageNew.setRGB(0, height * 2, width, height, ImageArrayThree, 0, width);
|
||||
imageNew.setRGB(0, height * 3, width, height, ImageArrayForth, 0, width);
|
||||
String resultImg = ImgUtil.toBase64(imageNew, ImgUtil.IMAGE_TYPE_PNG);
|
||||
byte[] bytes = Base64.getDecoder().decode(resultImg);
|
||||
return fileStorageUtil.uploadStream(new ByteArrayInputStream(bytes), OssPath.EVENT_WAVE_PIC, FileUtil.generateFileName("png"));
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(WaveFileResponseEnum.COMPOSE_PIC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 绘制瞬时波形图
|
||||
* @author hongawen
|
||||
* @date 2023/9/21 15:32
|
||||
* @return String 文件地址
|
||||
*/
|
||||
public String generateImageShun(WaveDataDTO waveDataDTO, List<WaveDataDetail> waveDataDetails) {
|
||||
String picPath = null;
|
||||
String time = waveDataDTO.getTime();
|
||||
String title = "监测点名称:" + waveDataDTO.getMonitorName() + " 发生时刻:" + time;
|
||||
WaveDataDetail waveDataDetail = waveDataDetails.get(0);
|
||||
String firstPic = drawPicUtil.drawWavePic(title, waveDataDetail.getInstantData().getAValue(),
|
||||
waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
String secondPic;
|
||||
if (waveDataDetails.size() == 1) {
|
||||
//将图片上传到minioss
|
||||
if (firstPic.contains(PicCommonData.PNG_PREFIX)) {
|
||||
firstPic = firstPic.replace(PicCommonData.PNG_PREFIX, "");
|
||||
}
|
||||
byte[] bytes = Base64.getDecoder().decode(firstPic);
|
||||
picPath = fileStorageUtil.uploadStream(new ByteArrayInputStream(bytes), OssPath.EVENT_WAVE_PIC, FileUtil.generateFileName("png"));
|
||||
} else if (waveDataDetails.size() == 2) {
|
||||
//绘制第二个电压瞬时波形图
|
||||
waveDataDetail = waveDataDetails.get(1);
|
||||
secondPic = drawPicUtil.drawWavePic("", waveDataDetail.getInstantData().getAValue(),
|
||||
waveDataDetail.getInstantData().getBValue(), waveDataDetail.getInstantData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getInstantData().getMax(), waveDataDetail.getInstantData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
picPath = composeImage(firstPic, secondPic);
|
||||
}
|
||||
return picPath;
|
||||
}
|
||||
|
||||
/***
|
||||
* 绘制RMS波形图
|
||||
* @author hongawen
|
||||
* @date 2023/9/21 15:32
|
||||
* @return String 文件地址
|
||||
*/
|
||||
public String generateImageRms(WaveDataDTO waveDataDTO, List<WaveDataDetail> waveDataDetails) {
|
||||
String picPath = null;
|
||||
String time = waveDataDTO.getTime();
|
||||
String title = "监测点名称:" + waveDataDTO.getMonitorName() + " 发生时刻:" + time;
|
||||
WaveDataDetail waveDataDetail = waveDataDetails.get(0);
|
||||
String firstPic = drawPicUtil.drawWavePic(title, waveDataDetail.getRmsData().getAValue(),
|
||||
waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
String secondPic;
|
||||
if (waveDataDetails.size() == 1) {
|
||||
//将图片上传到minioss
|
||||
if (firstPic.contains(PicCommonData.PNG_PREFIX)) {
|
||||
firstPic = firstPic.replace(PicCommonData.PNG_PREFIX, "");
|
||||
}
|
||||
byte[] bytes = Base64.getDecoder().decode(firstPic);
|
||||
picPath = fileStorageUtil.uploadStream(new ByteArrayInputStream(bytes), OssPath.EVENT_WAVE_PIC, FileUtil.generateFileName("png"));
|
||||
} else if (waveDataDetails.size() == 2) {
|
||||
//绘制第二个电压瞬时波形图
|
||||
waveDataDetail = waveDataDetails.get(1);
|
||||
secondPic = drawPicUtil.drawWavePic("", waveDataDetail.getRmsData().getAValue(),
|
||||
waveDataDetail.getRmsData().getBValue(), waveDataDetail.getRmsData().getCValue(),
|
||||
waveDataDetail.getUnit(), waveDataDetail.getRmsData().getMax(), waveDataDetail.getRmsData().getMin(),
|
||||
waveDataDetail.getA(), waveDataDetail.getB(), waveDataDetail.getC(),
|
||||
waveDataDetail.getColors(), waveDataDetail.getIsOpen()
|
||||
);
|
||||
picPath = composeImage(firstPic, secondPic);
|
||||
}
|
||||
return picPath;
|
||||
}
|
||||
|
||||
/***
|
||||
* 合成图片
|
||||
* @author hongawen
|
||||
* @date 2023/9/21 15:33
|
||||
* @param firstPic 第一张图
|
||||
* @param secondPic 第二张图
|
||||
* @return String
|
||||
*/
|
||||
private String composeImage(String firstPic, String secondPic) {
|
||||
try {
|
||||
//第一张图片 base64截取删除前缀data:image/png;base64,
|
||||
BufferedImage imageOne = ImgUtil.toBufferedImage(ImgUtil.toImage(firstPic.substring(22)), ImgUtil.IMAGE_TYPE_PNG);
|
||||
int width = imageOne.getWidth();
|
||||
int height = imageOne.getHeight();
|
||||
int[] imageArrayOne = new int[width * height];
|
||||
imageArrayOne = imageOne.getRGB(0, 0, width, height, imageArrayOne, 0, width);
|
||||
//第二张图片 base64截取删除前缀data:image/png;base64,
|
||||
BufferedImage imageTwo = ImgUtil.toBufferedImage(ImgUtil.toImage(secondPic.substring(22)), ImgUtil.IMAGE_TYPE_PNG);
|
||||
int width2 = imageTwo.getWidth();
|
||||
int height2 = imageTwo.getHeight();
|
||||
int[] ImageArrayTwo = new int[width2 * height2];
|
||||
ImageArrayTwo = imageTwo.getRGB(0, 0, width, height, ImageArrayTwo, 0, width);
|
||||
//新图片
|
||||
BufferedImage imageNew = new BufferedImage(width, height * 2, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImageGraphicsConfig config = BufferedImageGraphicsConfig.getConfig(imageNew);
|
||||
imageNew = config.createCompatibleImage(width, height * 2, Transparency.TRANSLUCENT);
|
||||
imageNew.setRGB(0, 0, width, height, imageArrayOne, 0, width);
|
||||
imageNew.setRGB(0, height, width, height, ImageArrayTwo, 0, width);
|
||||
String resultImg = ImgUtil.toBase64(imageNew, ImgUtil.IMAGE_TYPE_PNG);
|
||||
byte[] bytes = Base64.getDecoder().decode(resultImg);
|
||||
return fileStorageUtil.uploadStream(new ByteArrayInputStream(bytes), OssPath.EVENT_WAVE_PIC, FileUtil.generateFileName("png"));
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(WaveFileResponseEnum.COMPOSE_PIC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* app越限指标图
|
||||
* @param title
|
||||
* @param values
|
||||
* @param limitName
|
||||
* @param limit
|
||||
* @return
|
||||
*/
|
||||
public String generateSteadyTargetImage(String title, Map<String ,List<List<Object>>> values, String limitName, List<List<Object>> limit) {
|
||||
String firstPic = drawPicUtil.drawSteadyTargetPic(title,values,limitName,limit);
|
||||
if (firstPic.contains(PicCommonData.PNG_PREFIX)) {
|
||||
firstPic = firstPic.replace(PicCommonData.PNG_PREFIX, "");
|
||||
}
|
||||
byte[] bytes = Base64.getDecoder().decode(firstPic);
|
||||
return fileStorageUtil.uploadStream(new ByteArrayInputStream(bytes), OssPath.EVENT_WAVE_PIC, FileUtil.generateFileName("png"));
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.njcn.event.file.pojo.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2023年09月20日 16:11
|
||||
*/
|
||||
@Data
|
||||
public class InstantData {
|
||||
|
||||
private Float max;
|
||||
|
||||
private Float min;
|
||||
|
||||
List<List<Float>> aValue =new ArrayList<>();
|
||||
|
||||
List<List<Float>> bValue =new ArrayList<>();
|
||||
|
||||
List<List<Float>> cValue =new ArrayList<>();
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.njcn.event.file.pojo.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2023年09月20日 16:12
|
||||
*/
|
||||
@Data
|
||||
public class RmsData {
|
||||
|
||||
private Float max;
|
||||
|
||||
private Float min;
|
||||
|
||||
List<List<Float>> aValue =new ArrayList<>();
|
||||
|
||||
List<List<Float>> bValue =new ArrayList<>();
|
||||
|
||||
List<List<Float>> cValue =new ArrayList<>();
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.njcn.event.file.pojo.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2023年09月20日 16:13
|
||||
*/
|
||||
@Data
|
||||
public class WaveDataDetail {
|
||||
|
||||
private InstantData instantData;
|
||||
|
||||
private RmsData rmsData;
|
||||
|
||||
private String a ="A相";
|
||||
|
||||
private String b ="B相";
|
||||
|
||||
private String c ="C相";
|
||||
|
||||
private String channelName;
|
||||
|
||||
private String unit;
|
||||
|
||||
private Boolean isOpen = false;
|
||||
|
||||
private String title;
|
||||
|
||||
private List<String> colors= new ArrayList<>();
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.njcn.event.file.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 模拟量通道记录类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AnalogDTO implements Serializable {
|
||||
|
||||
// 通道序号
|
||||
private Integer nIndex;
|
||||
// 通道名称
|
||||
private String szChannleName;
|
||||
// 相位名称
|
||||
private String szPhasicName;
|
||||
// 监视的通道名称
|
||||
private String szMonitoredChannleName;
|
||||
// 通道的单位
|
||||
private String szUnitName;
|
||||
// 通道的系数
|
||||
private Float fCoefficent;
|
||||
// 通道的便宜量
|
||||
private Float fOffset;
|
||||
// 起始采样时间的偏移量
|
||||
private Float fTimeOffset;
|
||||
// 采样值的最小值
|
||||
private Integer nMin;
|
||||
// 采样值的最大值
|
||||
private Integer nMax;
|
||||
// 一次变比
|
||||
private Float fPrimary;
|
||||
// 二次变比
|
||||
private Float fSecondary;
|
||||
// 一次值还是二次值标志
|
||||
private String szValueType;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.njcn.event.file.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* CFG配置文件总类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ComtradeCfgDTO implements Serializable {
|
||||
private Integer nChannelNum;//总个数
|
||||
private Integer nPhasic;// 相别的个数 yxb 2020-12-15
|
||||
private Integer nAnalogNum;// 模拟量通道的个数 WW 2013-05-15
|
||||
private Integer nDigitalNum;// 开关量的个数 WW 2013-05-15
|
||||
private Date timeStart;// 暂态记录时间 yxb 2022-06-06
|
||||
private Date timeTrige;// 暂态触发时间 yxb 2022-06-06
|
||||
|
||||
private List<AnalogDTO> lstAnalogDTO;//模拟量通道记录
|
||||
|
||||
private List<DigitalDTO> lstDigitalDTO;//数字量通道记录
|
||||
|
||||
public Integer nRates;//对应采样次数
|
||||
public List<RateDTO> lstRate;//采样率合集
|
||||
|
||||
// add by sw 暂降触发时间
|
||||
private Date firstTime; // 暂降触发第一次
|
||||
private Integer firstMs; // 暂降触发第一次毫秒
|
||||
|
||||
// 波形前推周波束
|
||||
private Integer nPush = 0;
|
||||
// 最终采样率,计算的时候只用一个采样率
|
||||
private Integer finalSampleRate;
|
||||
// 整个波形大小
|
||||
private Integer nAllWaveNum = 0;
|
||||
|
||||
/***
|
||||
* 赋值编码格式(二进制)
|
||||
*/
|
||||
private String strBinType;
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(0/16);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.njcn.event.file.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 数字量通道记录类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DigitalDTO implements Serializable {
|
||||
|
||||
// 通道序号
|
||||
private Integer nIndex;
|
||||
// 通道名称
|
||||
private String szChannleName;
|
||||
// 相位名称
|
||||
private String szPhasicName;
|
||||
// 监视的通道名称
|
||||
private String szMonitoredChannleName;
|
||||
// 通道的单位
|
||||
private Integer Initial;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.njcn.event.file.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 特征值计算类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class EigenvalueDTO implements Serializable {
|
||||
|
||||
//是特征幅值(残余电压百分比)
|
||||
private float amplitude;
|
||||
//是特征幅值(残余电压)
|
||||
private float residualVoltage;
|
||||
//额定定压(动态电压)
|
||||
private float ratedVoltage;
|
||||
//持续时间
|
||||
private float durationTime;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.njcn.event.file.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 突变量计算类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MutationDTO implements Serializable {
|
||||
|
||||
private List<List<Float>> listRms_Offline = new ArrayList<>();//离线数据RMS有效值数据
|
||||
private List<List<Float>> listTBL_Offline = new ArrayList<>();//离线数据突变量数据
|
||||
private double fMinMagA = 99999d;
|
||||
private double fMinMagB = 99999d;
|
||||
private double fMinMagC = 99999d;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.njcn.event.file.pojo.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 采样率类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RateDTO implements Serializable {
|
||||
|
||||
// 1秒钟内的采样点数
|
||||
private Integer nOneSample;
|
||||
// 总采样点数
|
||||
private Integer nSampleNum;
|
||||
|
||||
//有效值标志,如果是有效值,那么就需要反向补点,而不是抽点
|
||||
public Boolean bRMSFlag;//YXB 2025-08-27
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.njcn.event.file.pojo.dto;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yxb
|
||||
* @version 1.0.0
|
||||
* @date 2022年06月02日 20:03
|
||||
* 返回波形数据类
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WaveDataDTO implements Serializable {
|
||||
|
||||
//CFG实体类
|
||||
private ComtradeCfgDTO comtradeCfgDTO;
|
||||
//波形对应的标题
|
||||
private List<String> waveTitle;
|
||||
//波形对应的通道标题
|
||||
private List<String> channelNames;
|
||||
//波形对应的值
|
||||
private List<List<Float>> listWaveData;
|
||||
//波形RMS值
|
||||
private List<List<Float>> listRmsData;
|
||||
//RMS最小值
|
||||
private List<List<Float>> listRmsMinData;
|
||||
//波形对应的相别数量
|
||||
private Integer iPhasic;
|
||||
//接线方式(0.星型接法;1.三角型接法;2.开口三角型接法)
|
||||
private Integer ptType;
|
||||
//PT变比
|
||||
private Double pt;
|
||||
//CT变比"
|
||||
private Double ct;
|
||||
//暂降发生时刻
|
||||
private String time;
|
||||
//测点名称
|
||||
private String monitorName;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.njcn.event.file.pojo.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月20日 09:56
|
||||
*/
|
||||
@Getter
|
||||
public enum WaveFileResponseEnum {
|
||||
|
||||
/**
|
||||
* 暂降模块异常响应码的范围:
|
||||
* A00650 ~ A00749
|
||||
*/
|
||||
EVENT_NOT_FOUND("A00651","暂降事件或监测点不存在"),
|
||||
ANALYSE_WAVE_NOT_FOUND("A00652","波形文件找不到"),
|
||||
WAVE_DATA_INVALID("A00654","波形文件数据缺失"),
|
||||
CFG_DATA_ERROR("A00653","CFG文件解析有误"),
|
||||
DAT_DATA_ERROR("A00653","DAT文件数据读取失败"),
|
||||
RMS_DATA_ERROR("A00653","rms数据读取失败"),
|
||||
COMPOSE_PIC_ERROR("A00653","合成波形图失败"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String message;
|
||||
|
||||
WaveFileResponseEnum(String code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
package com.njcn.event.file.utils;
|
||||
|
||||
import com.njcn.event.file.pojo.bo.InstantData;
|
||||
import com.njcn.event.file.pojo.bo.RmsData;
|
||||
import com.njcn.event.file.pojo.bo.WaveDataDetail;
|
||||
import com.njcn.event.file.pojo.dto.WaveDataDTO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2023年09月20日 16:14
|
||||
*/
|
||||
public class WaveUtil {
|
||||
|
||||
/**
|
||||
* 筛选后台绘图所需的瞬时、RMS等一次值数据
|
||||
*/
|
||||
public static List<WaveDataDetail> filterWaveData(WaveDataDTO waveDataDTO) {
|
||||
List<WaveDataDetail> waveDataDetails = new ArrayList<>();
|
||||
List<String> waveTitle = waveDataDTO.getWaveTitle();
|
||||
//通道名称,针对治理项目波形文件处理
|
||||
List<String> channelNames = waveDataDTO.getChannelNames();
|
||||
boolean openTri = waveDataDTO.getPtType() == 2;
|
||||
/************ 一个图形的相别决定了图形个数 Modify by yexb -----start ***********/
|
||||
Integer iPhase = waveDataDTO.getIPhasic();
|
||||
int picCounts = (waveTitle.size() - 1) / iPhase;
|
||||
/**处理相别的颜色**/
|
||||
List<String> colors = new ArrayList<>();
|
||||
//遍历图形个数
|
||||
for (int i = 0; i < picCounts; i++) {
|
||||
WaveDataDetail waveDataDetail = new WaveDataDetail();
|
||||
switch (iPhase) {
|
||||
case 1:
|
||||
waveDataDetail.setA(waveTitle.get(i + 1).substring(1));
|
||||
waveDataDetail.setB("");
|
||||
waveDataDetail.setC("");
|
||||
colors.add("#DAA520");
|
||||
colors.add("#fff");
|
||||
colors.add("#fff");
|
||||
waveDataDetail.setChannelName(channelNames.get(i + 1));
|
||||
break;
|
||||
case 2:
|
||||
waveDataDetail.setA(waveTitle.get(i * 2 + 1).substring(1));
|
||||
waveDataDetail.setB(waveTitle.get(i * 2 + 2).substring(1));
|
||||
waveDataDetail.setC("");
|
||||
colors.add("#DAA520");
|
||||
colors.add("#2E8B57");
|
||||
colors.add("#fff");
|
||||
waveDataDetail.setChannelName(channelNames.get(i * 2 + 1));
|
||||
break;
|
||||
case 3:
|
||||
waveDataDetail.setA(waveTitle.get(i * 3 + 1).substring(1));
|
||||
waveDataDetail.setB(waveTitle.get(i * 3 + 2).substring(1));
|
||||
waveDataDetail.setC(waveTitle.get(i * 3 + 3).substring(1));
|
||||
colors.add("#DAA520");
|
||||
colors.add("#2E8B57");
|
||||
colors.add("#A52a2a");
|
||||
waveDataDetail.setChannelName(channelNames.get(i * 3 + 1));
|
||||
break;
|
||||
}
|
||||
waveDataDetail.setColors(colors);
|
||||
|
||||
float xishu = waveDataDTO.getPt().floatValue();
|
||||
if (waveTitle.get(iPhase * i + 1).substring(0, 1).equalsIgnoreCase("U")) {
|
||||
waveDataDetail.setUnit("kV");
|
||||
xishu = xishu / 1000;
|
||||
} else {
|
||||
waveDataDetail.setUnit("A");
|
||||
xishu = waveDataDTO.getCt().floatValue();
|
||||
}
|
||||
Float sfMax = 0f, sfMin = 0f, rfMax = 0f, rfMin = 0f;
|
||||
List<List<Float>> sAValue = new ArrayList<>(), sBValue = new ArrayList<>(), sCValue = new ArrayList<>(), rAValue = new ArrayList<>(), rBValue = new ArrayList<>(), rCValue = new ArrayList<>();
|
||||
List<List<Float>> sunData = waveDataDTO.getListWaveData();
|
||||
for (int j = 0; j < sunData.size(); j++) {
|
||||
float x = sunData.get(j).get(0);
|
||||
float shunFirstA = 0f, shunFirstB = 0f, shunFirstC = 0f;
|
||||
//根据相别来确认标题的名称
|
||||
for (int m = 0; m < iPhase; m++) {
|
||||
if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("A")) {
|
||||
float tmpShunFirstA = sunData.get(j).get(iPhase * i + m + 1) * xishu;
|
||||
shunFirstA = tmpShunFirstA;
|
||||
sAValue.add(new ArrayList<Float>() {{
|
||||
add(x);
|
||||
add(tmpShunFirstA);
|
||||
}});
|
||||
}
|
||||
if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("B")) {
|
||||
float tmpShunFirstB = sunData.get(j).get(iPhase * i + m + 1) * xishu;
|
||||
shunFirstB = tmpShunFirstB;
|
||||
sBValue.add(new ArrayList<Float>() {{
|
||||
add(x);
|
||||
add(tmpShunFirstB);
|
||||
}});
|
||||
}
|
||||
if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("C")) {
|
||||
float tmpShunFirstC = sunData.get(j).get(iPhase * i + m + 1) * xishu;
|
||||
shunFirstC = tmpShunFirstC;
|
||||
sCValue.add(new ArrayList<Float>() {{
|
||||
add(x);
|
||||
add(tmpShunFirstC);
|
||||
}});
|
||||
}
|
||||
}
|
||||
sfMax = getMax(sfMax, shunFirstA, shunFirstB, shunFirstC);
|
||||
if (openTri) {
|
||||
sfMin = getMinOpen(sfMin, shunFirstA, shunFirstC);
|
||||
} else {
|
||||
sfMin = getMin(sfMin, shunFirstA, shunFirstB, shunFirstC);
|
||||
}
|
||||
}
|
||||
InstantData instantData = new InstantData();
|
||||
instantData.setAValue(sAValue);
|
||||
instantData.setBValue(sBValue);
|
||||
instantData.setCValue(sCValue);
|
||||
instantData.setMax(sfMax);
|
||||
instantData.setMin(sfMin);
|
||||
List<List<Float>> rmsData = waveDataDTO.getListRmsData();
|
||||
for (int k = 0; k < rmsData.size(); k++) {
|
||||
float x = rmsData.get(k).get(0);
|
||||
float rmsFirstA = 0f, rmsFirstB = 0f, rmsFirstC = 0f;
|
||||
//根据相别来确认标题的名称
|
||||
for (int m = 0; m < iPhase; m++) {
|
||||
if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("A")) {
|
||||
float tmpRmsFirstA = rmsData.get(k).get(iPhase * i + m + 1) * xishu;
|
||||
rmsFirstA = tmpRmsFirstA;
|
||||
rAValue.add(new ArrayList<Float>() {{
|
||||
add(x);
|
||||
add(tmpRmsFirstA);
|
||||
}});
|
||||
}
|
||||
if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("B")) {
|
||||
float tmpRmsFirstB = rmsData.get(k).get(iPhase * i + m + 1) * xishu;
|
||||
rmsFirstB = tmpRmsFirstB;
|
||||
rBValue.add(new ArrayList<Float>() {{
|
||||
add(x);
|
||||
add(tmpRmsFirstB);
|
||||
}});
|
||||
}
|
||||
if (waveTitle.get(iPhase * i + m + 1).substring(1).contains("C")) {
|
||||
float tmpRmsFirstC = rmsData.get(k).get(iPhase * i + m + 1) * xishu;
|
||||
rmsFirstC = tmpRmsFirstC;
|
||||
rCValue.add(new ArrayList<Float>() {{
|
||||
add(x);
|
||||
add(tmpRmsFirstC);
|
||||
}});
|
||||
}
|
||||
}
|
||||
rfMax = getMax(sfMax, rmsFirstA, rmsFirstB, rmsFirstC);
|
||||
if (openTri) {
|
||||
rfMin = getMinOpen(sfMin, rmsFirstA, rmsFirstC);
|
||||
} else {
|
||||
rfMin = getMin(sfMin, rmsFirstA, rmsFirstB, rmsFirstC);
|
||||
}
|
||||
}
|
||||
RmsData rmsData1 = new RmsData();
|
||||
rmsData1.setAValue(rAValue);
|
||||
rmsData1.setBValue(rBValue);
|
||||
rmsData1.setCValue(rCValue);
|
||||
rmsData1.setMax(rfMax);
|
||||
rmsData1.setMin(rfMin);
|
||||
|
||||
waveDataDetail.setInstantData(instantData);
|
||||
waveDataDetail.setRmsData(rmsData1);
|
||||
waveDataDetail.setIsOpen(openTri);
|
||||
waveDataDetails.add(waveDataDetail);
|
||||
}
|
||||
/************ Modify by yexb -----end ***********/
|
||||
return waveDataDetails;
|
||||
}
|
||||
|
||||
private static Float getMinOpen(Float temp, float tempA, float tempB) {
|
||||
temp = temp < tempA ? temp : tempA;
|
||||
temp = temp < tempB ? temp : tempB;
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
private static float getMin(float temp, float tempA, float tempB, float tempC) {
|
||||
temp = Math.min(temp, tempA);
|
||||
temp = Math.min(temp, tempB);
|
||||
temp = Math.min(temp, tempC);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private static float getMax(float temp, float tempA, float tempB, float tempC) {
|
||||
temp = Math.max(temp, tempA);
|
||||
temp = Math.max(temp, tempB);
|
||||
temp = Math.max(temp, tempC);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user