diff --git a/.gitignore b/.gitignore
index 4632c4bd9..15cc7a6c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,4 +44,7 @@ yarn.lock
rebel.xml
!DmJdbcDriver18.jar
-!kingbase8-8.6.0.jar
\ No newline at end of file
+!kingbase8-8.6.0.jar
+/.fastRequest/collections/Root/Default Group/directory.json
+/.fastRequest/collections/Root/directory.json
+/.fastRequest/config/fastRequestCurrentProjectConfig.json
diff --git a/pqs-common/common-event/.mvn/wrapper/maven-wrapper.properties b/pqs-common/common-event/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 000000000..2e76e189d
--- /dev/null
+++ b/pqs-common/common-event/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
diff --git a/pqs-common/common-event/pom.xml b/pqs-common/common-event/pom.xml
new file mode 100644
index 000000000..8aa174087
--- /dev/null
+++ b/pqs-common/common-event/pom.xml
@@ -0,0 +1,36 @@
+
+
+
+ pqs-common
+ com.njcn
+ 1.0.0
+
+ 4.0.0
+ common-event
+ common-event
+
+ 8
+ 8
+
+
+
+ com.njcn
+ common-core
+ ${project.version}
+
+
+ com.njcn
+ common-echarts
+ ${project.version}
+
+
+ com.njcn
+ common-oss
+ ${project.version}
+
+
+
+
+
+
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/component/WaveFileComponent.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/component/WaveFileComponent.java
new file mode 100644
index 000000000..2ffaaebb9
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/component/WaveFileComponent.java
@@ -0,0 +1,1289 @@
+package com.njcn.event.file.component;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.text.StrPool;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.StrUtil;
+import com.njcn.common.pojo.enums.response.CommonResponseEnum;
+import com.njcn.common.pojo.exception.BusinessException;
+import com.njcn.common.utils.wave.BitConverter;
+import com.njcn.event.file.pojo.dto.*;
+import com.njcn.event.file.pojo.enums.WaveFileResponseEnum;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @author hongawen
+ * @version 1.0.0
+ * @date 2023年03月03日 10:01
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class WaveFileComponent {
+
+
+ /******************************************
+ * 调用读取comtrate文件方法
+ * param strFilePath 波形.cfg文件路径
+ * param iType == 0 高级算法的要求,采样率只能是32-128
+ * iType == 1 普通展示,采样率按照cfg里面最小的(大于32)
+ * iType == 2 App抽点要求,采样率抽点成32
+ * iType == 3 高级算法原始波形(大于32)
+ ******************************************/
+ public WaveDataDTO getComtrade(InputStream cfgStream, InputStream datStream, int iType) {
+ WaveDataDTO waveDataDTO = new WaveDataDTO();
+ // 首先判断文件路径是否为空
+ // 读取cfg文件
+ ComtradeCfgDTO comtradeCfgDTO = getComtradeCfg(cfgStream);
+ // 为空或者未找到结束符号
+ if (comtradeCfgDTO == null || !"BINARY".equalsIgnoreCase(comtradeCfgDTO.getStrBinType())) {
+ return waveDataDTO;
+ }
+ /*****根据通道号计算相别** add by yexb -----Start****
+ * 1、判断是否是3的倍数,是3的倍数则是3相
+ * 2、假如不是3的倍数 ,是1的倍数则是单相
+ ********************************************************/
+ if (comtradeCfgDTO.getNAnalogNum() % 3 == 0) {
+ comtradeCfgDTO.setNPhasic(3);
+ } else {
+ comtradeCfgDTO.setNPhasic(1);
+ }
+ // 给相别幅值
+ waveDataDTO.setIPhasic(comtradeCfgDTO.getNPhasic());
+ // 组装解析抬头
+ List lstWaveTitle = getWaveTitle(comtradeCfgDTO);
+ // 解析.dat文件
+ List> listWaveData = getComtradeDat(comtradeCfgDTO, datStream, iType);
+ waveDataDTO.setComtradeCfgDTO(comtradeCfgDTO);
+ waveDataDTO.setWaveTitle(lstWaveTitle);
+ waveDataDTO.setListWaveData(listWaveData);
+ //add by hongawen,将暂态触发起始时间记录下来
+ waveDataDTO.setTime(DateUtil.format(comtradeCfgDTO.getFirstTime(), DatePattern.NORM_DATETIME_PATTERN).concat(StrPool.DOT)+comtradeCfgDTO.getFirstMs());
+ /*****根据通道号计算相别** add by yexb -----end****/
+
+ return waveDataDTO;
+ }
+
+ /*********************************
+ * 根据波形数据算出rms值数据
+ * param waveDataDTO 瞬时波形(包含了CFG配置文件)
+ * List> 返回RMS波形
+ **********************************/
+ @SuppressWarnings("unused")
+ public WaveDataDTO getValidData(WaveDataDTO waveDataDTO) {
+ //CFG 配置文件
+ ComtradeCfgDTO comtradeCfgDTO = waveDataDTO.getComtradeCfgDTO();
+ //瞬时波形值
+ List> lstWave = waveDataDTO.getListWaveData();
+ //返回rms的值
+ List> listRms = new ArrayList<>();
+ /*float fs = nOneWaveNum;
+ int nWaveNum = (int) nAllWaveNum;*/
+
+ // 全波有效值 (int)fs / 2;//半波有效值
+ int halfTs = comtradeCfgDTO.getFinalSampleRate().intValue();
+ // 计算有效值算法
+ /*********************************
+ * modify by yexibao 2020-10-29
+ * 增加多波形算法 ---------start
+ ********************************/
+ double iWave;
+ // 相别
+ int nPhasic;
+ //存放RMS值的最小值
+ List> listRmsMin = new ArrayList<>();
+ if (lstWave.size() > 0) {
+ nPhasic = comtradeCfgDTO.getNPhasic();
+ //ComtradeCfg.nAnalogNum为值的个数(-1的原因是一个存的是时间)
+ iWave = Math.floor((lstWave.get(0).size() - 1) / (double) nPhasic);
+ List tmpListRms;
+ List tmpListRmsMin;
+ //增加RMS的最小值
+ double fMinTime = 0.0, fMinValue = 0.0;
+ //每一项一项计算
+ for (int j = 0; j < iWave; j++) {
+ // 实例化
+ tmpListRmsMin = new ArrayList<>();
+ double fSumA = 0.0, fSumB = 0.0, fSumC = 0.0;
+ double fValidA, fValidB, fValidC;
+ //循环原始数据
+ for (int i = 0; i < lstWave.size(); i++) {
+ // 当第一次循环的时候实例化,其余的获取已有的List//获取每一项的值
+ List tmpListValue = lstWave.get(i);
+ if (j == 0) {
+ tmpListRms = new ArrayList<>();
+ //获取时间
+ tmpListRms.add(tmpListValue.get(0));
+ listRms.add(tmpListRms);
+ } else {
+ tmpListRms = listRms.get(i);
+ }
+
+ //包含了时间、电压(A、B、C)三相、电流(A、B、C)三相
+ if (tmpListValue.size() >= 2) {
+ //电压有效值算法,根据相别进行处理
+ switch (comtradeCfgDTO.getNPhasic()) {
+ case 1:
+ fSumA += Math.pow(tmpListValue.get(1 + nPhasic * j), 2);
+ // 计算有效值
+ if (i >= halfTs) {
+ //获取前推周波的值
+ List forwardListValue = lstWave.get(i - halfTs);
+ fSumA -= Math.pow(forwardListValue.get(1 + nPhasic * j), 2);
+ }
+ fValidA = Math.sqrt(fSumA / halfTs);
+ tmpListRms.add((float) (Math.round(fValidA * 100)) / 100);
+ listRms.set(i, tmpListRms);
+ // 最小值判断
+ if (i >= halfTs) {
+ if (i == halfTs) {
+ fMinValue = fValidA;
+ fMinTime = tmpListValue.get(0);
+ } else {
+ if (fValidA < fMinValue) {
+ fMinValue = fValidA;
+ fMinTime = tmpListValue.get(0);
+ }
+ }
+ }
+ break;
+ case 2:
+ fSumA += Math.pow(tmpListValue.get(1 + nPhasic * j), 2);
+ fSumB += Math.pow(tmpListValue.get(2 + nPhasic * j), 2);
+ // 计算有效值
+ if (i >= halfTs) {
+ //获取前推周波的值
+ List forwardListValue = lstWave.get(i - halfTs);
+ fSumA -= Math.pow(forwardListValue.get(1 + nPhasic * j), 2);
+ fSumB -= Math.pow(forwardListValue.get(2 + nPhasic * j), 2);
+ }
+ fValidA = Math.sqrt(fSumA / halfTs);
+ fValidB = Math.sqrt(fSumB / halfTs);
+
+ tmpListRms.add((float) (Math.round(fValidA * 100)) / 100);
+ tmpListRms.add((float) (Math.round(fValidB * 100)) / 100);
+ listRms.set(i, tmpListRms);
+
+ // 最小值判断
+ if (i >= halfTs) {
+ if (i == halfTs) {
+ fMinValue = fValidA;
+ fMinTime = tmpListValue.get(0);
+ } else {
+ if (fValidA < fMinValue) {
+ fMinValue = fValidA;
+ fMinTime = tmpListValue.get(0);
+ }
+ if (fValidB < fMinValue) {
+ fMinValue = fValidB;
+ fMinTime = tmpListValue.get(0);
+ }
+ }
+ }
+ break;
+ case 3:
+ fSumA += Math.pow(tmpListValue.get(1 + nPhasic * j), 2);
+ fSumB += Math.pow(tmpListValue.get(2 + nPhasic * j), 2);
+ fSumC += Math.pow(tmpListValue.get(3 + nPhasic * j), 2);
+ // 计算有效值
+ if (i >= halfTs) {
+ //获取前推周波的值
+ List forwardListValue = lstWave.get(i - halfTs);
+ fSumA -= Math.pow(forwardListValue.get(1 + nPhasic * j), 2);
+ fSumB -= Math.pow(forwardListValue.get(2 + nPhasic * j), 2);
+ fSumC -= Math.pow(forwardListValue.get(3 + nPhasic * j), 2);
+ }
+ fValidA = Math.sqrt(fSumA / halfTs);
+ fValidB = Math.sqrt(fSumB / halfTs);
+ fValidC = Math.sqrt(fSumC / halfTs);
+
+ tmpListRms.add((float) (Math.round(fValidA * 100)) / 100);
+ tmpListRms.add((float) (Math.round(fValidB * 100)) / 100);
+ tmpListRms.add((float) (Math.round(fValidC * 100)) / 100);
+ listRms.set(i, tmpListRms);
+
+ // 最小值判断
+ if (i >= halfTs) {
+ if (i == halfTs) {
+ fMinValue = fValidA;
+ fMinTime = tmpListValue.get(0);
+ } else {
+ if (fValidA < fMinValue) {
+ fMinValue = fValidA;
+ fMinTime = tmpListValue.get(0);
+ }
+ if (fValidB < fMinValue) {
+ fMinValue = fValidB;
+ fMinTime = tmpListValue.get(0);
+ }
+ if (fValidC < fMinValue) {
+ fMinValue = fValidC;
+ fMinTime = tmpListValue.get(0);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ //增加最小值时间,最小值//获取时间
+ tmpListRmsMin.add((float) fMinTime);
+ //获取时间
+ tmpListRmsMin.add((float) (Math.round(fMinValue * 100)) / 100);
+ listRmsMin.add(tmpListRmsMin);
+ }
+
+ //过滤前一个周波
+ //HalfTs表示一个周波
+ try {
+ for (int i = 0; i < halfTs; i++) {
+ //电压有效值算法 //没相具体的值
+ List tmpNewListRms = new ArrayList<>();
+ for (int j = 0; j < iWave; j++) {
+ if (j == 0) {
+ //获取时间
+ tmpNewListRms.add(listRms.get(i).get(0));
+ }
+ switch (nPhasic) {
+ case 1:
+ tmpNewListRms.add(listRms.get(i + halfTs).get(1 + nPhasic * j));
+ break;
+ case 2:
+ tmpNewListRms.add(listRms.get(i + halfTs).get(1 + nPhasic * j));
+ tmpNewListRms.add(listRms.get(i + halfTs).get(2 + nPhasic * j));
+ break;
+ case 3:
+ tmpNewListRms.add(listRms.get(i + halfTs).get(1 + nPhasic * j));
+ tmpNewListRms.add(listRms.get(i + halfTs).get(2 + nPhasic * j));
+ tmpNewListRms.add(listRms.get(i + halfTs).get(3 + nPhasic * j));
+ break;
+ default:
+ break;
+ }
+ }
+ //重新赋值
+ listRms.set(i, tmpNewListRms);
+ }
+ } catch (Exception e) {
+ throw new BusinessException(WaveFileResponseEnum.RMS_DATA_ERROR);
+ }
+ }
+ waveDataDTO.setListRmsData(listRms);
+ //RMS最小值
+ waveDataDTO.setListRmsMinData(listRmsMin);
+
+ return waveDataDTO;
+ }
+
+ /*****************************
+ *获取暂降特征值,包含离线
+ * param waveDataDTO 波形返回参数
+ * param blType 计算方式 true:浮动门槛 false:固定门槛
+ *****************************/
+ public List getEigenvalue(WaveDataDTO waveDataDTO, boolean blType) {
+ //CFG 配置文件
+ ComtradeCfgDTO comtradeCfgDTO = waveDataDTO.getComtradeCfgDTO();
+ // 瞬时波形值
+ List> lstWave = waveDataDTO.getListWaveData();
+ //获取最终采样率
+ Long finalSampleRate = comtradeCfgDTO.getFinalSampleRate();
+ // 返回值
+ List lstEigenvalueDTO = new ArrayList<>();
+
+ // 必须包含了瞬时波形
+ if (lstWave.size() > 0) {
+ MutationDTO mutationDTO = getMutationValue(lstWave, finalSampleRate);
+ //获取突变量和RMS值
+ if (mutationDTO.getListRms_Offline().size() > 0 && mutationDTO.getListTBL_Offline().size() > 0) {
+ lstEigenvalueDTO = getEventValue(lstWave, mutationDTO, comtradeCfgDTO, blType);
+ }
+ } else {
+ lstEigenvalueDTO = null;
+ }
+ return lstEigenvalueDTO;
+ }
+
+ /***
+ * 获取波形文件流,存在则返回inputStream,不存在则返回null
+ * 为null时,这抛出波形文件不存在异常
+ * @author hongawen
+ * @date 2023/3/3 14:03
+ */
+ public InputStream getFileInputStreamByFilePath(String filePath) {
+ File file = new File(filePath);
+ if (file.isFile() && file.exists()) {
+ InputStream inputStream;
+ try {
+ inputStream = Files.newInputStream(file.toPath());
+ if (inputStream.available() < 1) {
+ throw new BusinessException(WaveFileResponseEnum.WAVE_DATA_INVALID);
+ }
+ return inputStream;
+ } catch (IOException e) {
+ throw new BusinessException(WaveFileResponseEnum.WAVE_DATA_INVALID);
+ }
+ } else {
+ throw new BusinessException(WaveFileResponseEnum.ANALYSE_WAVE_NOT_FOUND);
+ }
+ }
+
+ /*********************************
+ * 读取cfg方法
+ * param strFilePath 文件路径
+ * return 返回bool为是否解析出错
+ **********************************/
+ private ComtradeCfgDTO getComtradeCfg(InputStream cfgStream) {
+ ComtradeCfgDTO comtradeCfgDTO = new ComtradeCfgDTO();
+ InputStreamReader read = null;
+ BufferedReader bufferedReader = null;
+ try {
+ // 将.cfg文件转换为管道流
+ read = new InputStreamReader(cfgStream, CharsetUtil.CHARSET_GBK);
+ bufferedReader = new BufferedReader(read);
+ //WW 2019-11-14
+ float nFreq;
+ // 第一行不关心仅仅是一些描述类的信息
+ String strFileLine = bufferedReader.readLine();
+ // 第二行需要关心第二个(模拟量的个数)和第三个参数(开关量的个数)
+ strFileLine = bufferedReader.readLine();
+ // 按“,”进行分割
+ String[] strTempArray = strFileLine.split(StrUtil.COMMA);
+ // 按“,”进行分割
+ for (int i = 0; i < strTempArray.length; i++) {
+ switch (i) {
+ // 总个数
+ case 0:
+ comtradeCfgDTO.setNChannelNum(Integer.parseInt(strTempArray[i]));
+ break;
+ // 模拟量的个数
+ case 1:
+ comtradeCfgDTO.setNAnalogNum(Integer.parseInt(strTempArray[i].substring(0, strTempArray[i].length() - 1)));
+ break;
+ // 开关量的个数
+ case 2:
+ comtradeCfgDTO.setNDigitalNum(Integer.parseInt(strTempArray[i].substring(0, strTempArray[i].length() - 1)));
+ break;
+ default:
+ break;
+ }
+ }
+
+ // 从第三行到第ComtradeCfg.nChannelNum + 3行是模拟量通道和数字量通道
+ List lstAnalogDTO = new ArrayList<>();
+ comtradeCfgDTO.setLstAnalogDTO(lstAnalogDTO);
+ for (int i = 0; i < comtradeCfgDTO.getNChannelNum(); i++) {
+ AnalogDTO analogDTO = new AnalogDTO();
+ lstAnalogDTO.add(analogDTO);
+ strFileLine = bufferedReader.readLine();
+ strTempArray = strFileLine.split(StrUtil.COMMA);
+ // 配置总共13项
+ for (int j = 0; j < strTempArray.length; j++) {
+ switch (j) {
+ // 通道序号
+ case 0:
+ analogDTO.setNIndex(Integer.parseInt(strTempArray[j]));
+ break;
+ // 通道名称
+ case 1:
+ analogDTO.setSzChannleName(strTempArray[j]);
+ break;
+ // 相位名称
+ case 2:
+ analogDTO.setSzPhasicName(strTempArray[j]);
+ break;
+ // 监视的通道名称
+ case 3:
+ analogDTO.setSzMonitoredChannleName(strTempArray[j]);
+ break;
+ // 通道的单位
+ case 4:
+ analogDTO.setSzUnitName(strTempArray[j]);
+ break;
+ // 通道的系数
+ case 5:
+ analogDTO.setFCoefficent(Float.parseFloat(strTempArray[j]));
+ break;
+ // 通道的偏移量
+ case 6:
+ analogDTO.setFOffset(Float.parseFloat(strTempArray[j]));
+ break;
+ // 起始采样时间的偏移量
+ case 7:
+ analogDTO.setFTimeOffset(Float.parseFloat(strTempArray[j]));
+ break;
+ // 采样值的最小值
+ case 8:
+ analogDTO.setNMin(Integer.parseInt(strTempArray[j]));
+ break;
+ // 采样值的最大值
+ case 9:
+ analogDTO.setNMax(Integer.parseInt(strTempArray[j]));
+ break;
+ // 一次变比
+ case 10:
+ analogDTO.setFPrimary(Float.parseFloat(strTempArray[j]));
+ break;
+ // 二次变比
+ case 11:
+ analogDTO.setFSecondary(Float.parseFloat(strTempArray[j]));
+ break;
+ // 一次值还是二次值标志
+ case 12:
+ analogDTO.setSzValueType(strTempArray[j]);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ //WW 2019-11-14 // 采样频率
+ nFreq = Float.parseFloat(bufferedReader.readLine());
+ // 获取采样段数
+ strFileLine = bufferedReader.readLine();
+ int nRates = Integer.parseInt(strFileLine);
+ comtradeCfgDTO.setNRates(nRates);
+ // 获得每段的采样率 //采样率
+ List lstRate = new ArrayList<>();
+ long nOffset = 0;
+ for (int i = 0; i < nRates; i++) {
+ strFileLine = bufferedReader.readLine();
+ strTempArray = strFileLine.split(StrUtil.COMMA);
+ RateDTO rateDTO = new RateDTO();
+ // 单周波采样点数 //WW 2019-11-14
+ rateDTO.setNOneSample((long) (Float.parseFloat(strTempArray[0]) / nFreq));
+ // 总点数 //这里的strTemp是一个偏移量
+ rateDTO.setNSampleNum((long) (Float.parseFloat(strTempArray[1]) - nOffset));
+ lstRate.add(rateDTO);
+ }
+ comtradeCfgDTO.setLstRate(lstRate);
+ // 增加读取波形起始时间个结束时间
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss.SSS");
+ // 波形起始时间
+ strFileLine = bufferedReader.readLine();
+ strFileLine = strFileLine.substring(0, strFileLine.length() - 3).replace(StrUtil.COMMA, StrUtil.SPACE);
+ comtradeCfgDTO.setTimeStart(sdf.parse(strFileLine));
+ // 暂态触发时间
+ strFileLine = bufferedReader.readLine();
+ strFileLine = strFileLine.substring(0, strFileLine.length() - 3).replace(StrUtil.COMMA, StrUtil.SPACE);
+ comtradeCfgDTO.setTimeTrige(sdf.parse(strFileLine));
+ // 获取触发时间的时间 + 毫秒
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(comtradeCfgDTO.getTimeTrige());
+ comtradeCfgDTO.setFirstMs(calendar.get(Calendar.MILLISECOND));
+ comtradeCfgDTO.setFirstTime(calendar.getTime());
+
+ long a = comtradeCfgDTO.getTimeStart().getTime();
+ long b = comtradeCfgDTO.getTimeTrige().getTime();
+ int c = (int) (b - a);
+ if (c >= 90 && c <= 110) {
+ comtradeCfgDTO.setNPush(100);
+ } else if (c >= 190 && c <= 210) {
+ comtradeCfgDTO.setNPush(200);
+ }
+ // 赋值编码格式(二进制)
+ comtradeCfgDTO.setStrBinType(bufferedReader.readLine().toUpperCase());
+ } catch (Exception e) {
+ // 解析.cfg文件出错
+ comtradeCfgDTO = null;
+ } finally {
+ try {
+ bufferedReader.close();
+ } catch (IOException e) {
+ throw new BusinessException(CommonResponseEnum.CLOSE_RESOURCE_ERROR);
+ }
+ try {
+ read.close();
+ } catch (IOException e) {
+ throw new BusinessException(CommonResponseEnum.CLOSE_RESOURCE_ERROR);
+ }
+ }
+ return comtradeCfgDTO;
+ }
+
+ /*********************************
+ * 读取dat方法
+ * param strFilePath .dat访问路径
+ * param strFilePath .dat访问路径
+ * param iType 访问波形类型
+ * List> 返回波形瞬时值
+ **********************************/
+ private List> getComtradeDat(ComtradeCfgDTO comtradeCfgDTO, InputStream datStream, int iType) {
+ //返回数据
+ List> listWaveData = new ArrayList<>();
+ // 波形文件路径由 .cfg 换成 .dat
+ //初始化xValue的值
+ float xValueAll = 0;
+ //判断是否首次登陆
+ boolean blxValue = false;
+ byte[] datArray;
+ try {
+ datArray = IoUtil.readBytes(datStream);
+ if (ArrayUtil.isEmpty(datArray)) {
+ return listWaveData;
+ }
+ // 计算每个单独的数据块的大小 4个字节的序号 4个字节的时间 2个字节的值
+ // 示例中的排布是 4个字节的序号 4个字节的时间 UA(2字节) UB(2字节) UC(2字节) IA(2字节) IB(2字节) IC(2字节)
+ int nDigSize = (comtradeCfgDTO.getNDigitalNum() % 16) > 0 ? (comtradeCfgDTO.getNDigitalNum() / 16 + 1) * 2 : comtradeCfgDTO.getNDigitalNum() / 16 * 2;
+ int nBlockSize = 2 * Integer.SIZE / 8 + comtradeCfgDTO.getNAnalogNum() * 2 + nDigSize;
+ // 总长度除以每个快的大小
+ int nBlockNum = datArray.length / nBlockSize;
+ // 获取采样率
+ long finalSampleRate = getFinalWaveSample(comtradeCfgDTO.getLstRate(), iType);
+ if (finalSampleRate != -1) {
+ //设置最终采样率
+ comtradeCfgDTO.setFinalSampleRate(finalSampleRate);
+ // 计算转换后的采样率
+ int nnInd = 0;
+ // 抽点后总共多少点数据
+ long nWaveNum;
+ //抽点后新的的采样率
+ List newLstRate = new ArrayList<>();
+ for (int iRate = 0; iRate < comtradeCfgDTO.getNRates(); iRate++) {
+ if (comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() >= 32) {
+ // 计算本段录波总共有多少波形
+ nWaveNum = comtradeCfgDTO.getLstRate().get(iRate).getNSampleNum() / comtradeCfgDTO.getLstRate().get(iRate).getNOneSample();
+ //设置总波形大小
+ comtradeCfgDTO.setNAllWaveNum(comtradeCfgDTO.getNAllWaveNum() + nWaveNum);
+ // 将最低采样率替换到本段录波内
+ RateDTO tmpRateDTO = new RateDTO();
+ newLstRate.add(tmpRateDTO);
+ //iFlag =3 一定不进行抽点算法
+ if (iType != 3) {
+ //true 抽点算法(当前采样率跟统一采样率不一样则是抽点,否则是未抽点)
+ if (!Objects.equals(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample(), comtradeCfgDTO.getFinalSampleRate())) {
+ newLstRate.get(nnInd).setNOneSample(comtradeCfgDTO.getFinalSampleRate());
+ // 计算本段录波按照最低采样点应该有多少录波
+ newLstRate.get(nnInd).setNSampleNum(comtradeCfgDTO.getFinalSampleRate() * nWaveNum);
+ } else {
+ newLstRate.get(nnInd).setNOneSample(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample());
+ // 计算本段录波按照最低采样点应该有多少录波
+ newLstRate.get(nnInd).setNSampleNum(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() * nWaveNum);
+ }
+ } else {
+ newLstRate.get(nnInd).setNOneSample(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample());
+ // 计算本段录波按照最低采样点应该有多少录波
+ newLstRate.get(nnInd).setNSampleNum(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() * nWaveNum);
+ }
+
+ // 正常的配置中采样率
+ comtradeCfgDTO.getLstRate().get(nnInd).setNOneSample(comtradeCfgDTO.getLstRate().get(iRate).getNOneSample());
+ comtradeCfgDTO.getLstRate().get(nnInd).setNSampleNum(comtradeCfgDTO.getLstRate().get(iRate).getNSampleNum());
+ nnInd++;
+ }
+ }
+ // 偏移量,采样间隔
+ long nOffSet = 0, nWaveSpan;
+ //两个点之间的时间差
+ float fValue, dfValue;
+ // 计算不同块的采样率
+ int nIndex = 0;
+ // 将最低采样率替换到本段录波内
+ // .CFG中采样率
+ RateDTO tmpRateDTO;
+ // nBlockNum 总循环次数
+ for (int i = 0; i < nBlockNum; i++) {
+ tmpRateDTO = comtradeCfgDTO.getLstRate().get(nIndex);
+ // 计算本段抽点采样间隔
+ nWaveSpan = tmpRateDTO.getNOneSample() / newLstRate.get(nIndex).getNOneSample();
+ // 判断是否进入下一段
+ if (i == tmpRateDTO.getNSampleNum() + nOffSet) {
+ nOffSet += tmpRateDTO.getNSampleNum();
+ nIndex++;
+ if (nIndex == nnInd) {
+ break;
+ }
+ }
+ dfValue = (float) 20 / tmpRateDTO.getNOneSample();
+ // 判断是否到了需要抽的采样点
+ if (i % nWaveSpan == 0) {
+ // 计算每个通道的值
+ //存储局部数据集合,包含了时间,A,B,C三相
+ List tmpWaveData = new ArrayList<>();
+ AnalogDTO tmpAnalogDTO;
+ for (int j = 0; j < comtradeCfgDTO.getNAnalogNum(); j++) {
+ tmpAnalogDTO = comtradeCfgDTO.getLstAnalogDTO().get(j);
+ //数据只有电压ABC三相数据,不展示U0、I0等数据 YXB2020-10-09 去除相别为N相的数据
+ if ("N".equalsIgnoreCase(tmpAnalogDTO.getSzPhasicName())) {
+ break;
+ }
+ float fCoef = tmpAnalogDTO.getFCoefficent();
+ fValue = BitConverter.byte2ToUnsignedShort(datArray, i * nBlockSize + 2 * 4 + j * 2) * fCoef;
+
+ //WW 2019-11-14//P是一次值 S是二次值
+ if ("S".equalsIgnoreCase(tmpAnalogDTO.getSzValueType())) {
+ //判断单位是V还是kV
+ if ("KV".equalsIgnoreCase(tmpAnalogDTO.getSzUnitName())) {
+ fValue = fValue * 1000.0f;
+ }
+ }
+ //P是一次值 S是二次值
+ else if ("P".equalsIgnoreCase(tmpAnalogDTO.getSzValueType())) {
+ //判断单位是V还是kV
+ if ("V".equalsIgnoreCase(tmpAnalogDTO.getSzUnitName())) {
+ //根据cfg内的变比,将一次值转换成二次值
+ if (tmpAnalogDTO.getFPrimary() != 0.0f) {
+ fValue = fValue * tmpAnalogDTO.getFSecondary() / tmpAnalogDTO.getFPrimary();
+ }
+
+ }
+ //判断单位是V还是kV
+ else if ("KV".equalsIgnoreCase(tmpAnalogDTO.getSzUnitName())) {
+ //根据cfg内的变比,将一次值转换成二次值
+ if (tmpAnalogDTO.getFPrimary() != 0.0f) {
+ fValue = fValue * 1000.0f * tmpAnalogDTO.getFSecondary() / tmpAnalogDTO.getFPrimary();
+ }
+ }
+ //还有可能是电流,单位是A
+ else {
+ //根据cfg内的变比,将一次值转换成二次值
+ if (tmpAnalogDTO.getFPrimary() != 0.0f) {
+ fValue = tmpAnalogDTO.getFSecondary() / tmpAnalogDTO.getFPrimary();
+ }
+ }
+ }
+
+ //ComtradeCfg.OneChannleCfg.get(j)
+
+ //xValue前移量,假如是第一次时候则需要前移
+ if (!blxValue && j == 0) {
+ xValueAll = (float) (i * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
+ blxValue = true;
+ //只增加一个xValue的值 //增加时间值
+ tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
+ } else if (j == 0) {
+ xValueAll += (float) nWaveSpan * dfValue;
+ //只增加一个xValue的值 //增加时间值
+ tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
+ }
+
+ //不同通道yValue的值都需要增加,最终成ABC三相 //每个通道的值
+ tmpWaveData.add((float) (Math.round(fValue * 100)) / 100);
+ }
+ //把每个单独的值赋予到整体里面去
+ listWaveData.add(tmpWaveData);
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new BusinessException(WaveFileResponseEnum.DAT_DATA_ERROR);
+ }
+
+ return listWaveData;
+ }
+
+
+ /*********************************
+ * 获取最小(最终)采样率方法
+ * @param lstRate cfg中关于采样率参数
+ * @return 返回最小采样率
+ **********************************/
+ private long getFinalWaveSample(List lstRate, int iType) {
+ // 最终返回采样率
+ long nFinalOneSample = -1;
+ // 最小采样率
+ long nMinOneSample = -1;
+ if (lstRate.size() > 0) {
+ nMinOneSample = lstRate.get(0).getNOneSample();
+ long tmpOneSample;
+ for (RateDTO rateDTO : lstRate) {
+ tmpOneSample = rateDTO.getNOneSample();
+ if (tmpOneSample >= 32) {
+ if (nMinOneSample > tmpOneSample) {
+ nMinOneSample = tmpOneSample;
+ }
+ }
+ }
+ }
+ /********************************************************
+ * iFlag == 0 高级算法的要求,采样率只能是32-128
+ * iFlag == 1 普通展示,采样率按照cfg里面最小的(大于32)
+ * iFlag == 2 App抽点要求,采样率抽点成32
+ * iFlag == 3 高级算法原始波形(大于32)
+ ********************************************************/
+ switch (iType) {
+ case 0:
+ if (nMinOneSample < 32) {
+ nFinalOneSample = 32;
+ } else if (nMinOneSample > 128) {
+ nFinalOneSample = 128;
+ }
+ break;
+ case 2:
+ nFinalOneSample = 32;
+ break;
+
+ default:
+ nFinalOneSample = nMinOneSample;
+ break;
+
+ }
+ return nFinalOneSample;
+ }
+
+
+ /*********************************
+ * 离线波形导入时获取突变量算法
+ * param tmpListWave 波形原始数据
+ * param finalSampleRate 最终采样率
+ **********************************/
+ private MutationDTO getMutationValue(List> lstWave, float finalSampleRate) {
+ MutationDTO mutationDTO = new MutationDTO();
+ // 计算有效值
+ double fSumA = 0.0, fSumB = 0.0, fSumC = 0.0;
+ double fValidA, fValidB, fValidC;
+ double fValue = 0.0;
+ // 全波有效值 ; (int)fs / 2;//半波有效值
+ int HalfTs = (int) finalSampleRate;
+ //瞬时波形数据_瞬时---前推周波的值_瞬时----周波的值_突变量----前推周波的值_突变量
+ List tmpRealValue, forwardRealValue, tblValue, forwardTblValue;
+ // 计算有效值算法
+ for (int i = 0; i < lstWave.size(); i++) {
+ //获取每一项的值
+ tmpRealValue = lstWave.get(i);
+ //包含了时间、A、B、C三相
+ if (tmpRealValue.size() >= 4) {
+ fSumA += Math.pow(tmpRealValue.get(1), 2);
+ fSumB += Math.pow(tmpRealValue.get(2), 2);
+ fSumC += Math.pow(tmpRealValue.get(3), 2);
+ // 计算有效值
+ List tmpRmsValue = new ArrayList<>();
+ if (i >= finalSampleRate) {
+ forwardRealValue = lstWave.get(i - HalfTs);
+ fSumA -= Math.pow(forwardRealValue.get(1), 2);
+ fSumB -= Math.pow(forwardRealValue.get(2), 2);
+ fSumC -= Math.pow(forwardRealValue.get(3), 2);
+ }
+ // 计算突变量值
+ List tmpTblValue = new ArrayList<>();
+ //获取时间
+ tmpTblValue.add(tmpRealValue.get(0));
+ if (i >= HalfTs) {
+ //获取前推周波的值
+ tblValue = lstWave.get(i);
+ //获取前推周波的值
+ forwardTblValue = lstWave.get(i - HalfTs);
+ tmpTblValue.add(tblValue.get(1) - forwardTblValue.get(1));
+ tmpTblValue.add(tblValue.get(2) - forwardTblValue.get(2));
+ tmpTblValue.add(tblValue.get(3) - forwardTblValue.get(3));
+ } else {
+ tmpTblValue.add(0f);
+ tmpTblValue.add(0f);
+ tmpTblValue.add(0f);
+ }
+ fValidA = Math.sqrt(fSumA / HalfTs);
+ fValidB = Math.sqrt(fSumB / HalfTs);
+ fValidC = Math.sqrt(fSumC / HalfTs);
+
+ if (i >= finalSampleRate) {
+ if (fValidA < mutationDTO.getFMinMagA()) {
+ mutationDTO.setFMinMagA(fValidA);
+ }
+ if (fValidB < mutationDTO.getFMinMagB()) {
+ mutationDTO.setFMinMagB(fValidB);
+ }
+ if (fValidC < mutationDTO.getFMinMagC()) {
+ mutationDTO.setFMinMagC(fValidC);
+ }
+ }
+ //RMS获取//获取时间
+ tmpRmsValue.add(tmpRealValue.get(0));
+ tmpRmsValue.add((float) fValidA);
+ tmpRmsValue.add((float) fValidB);
+ tmpRmsValue.add((float) fValidC);
+ mutationDTO.getListRms_Offline().add(tmpRmsValue);
+
+ //RMS获取
+ mutationDTO.getListTBL_Offline().add(tmpTblValue);
+ }
+ }
+ return mutationDTO;
+ }
+
+ /*********************************
+ * 离线波形导入时获取暂降特征值的算法
+ * param lstWave 波形原始数据
+ * param tblWave 突变量波形数据
+ * param rmstWave RMS数据
+ * param comtradeCfgDTO 波形CFG配置参数
+ * param blType 计算方式
+ * List> 返回暂降数据
+ **********************************/
+ private List getEventValue(List> lstWave, MutationDTO mutationDTO, ComtradeCfgDTO comtradeCfgDTO, boolean blType) {
+ List> tblWave = mutationDTO.getListTBL_Offline();
+ List> rmstWave = mutationDTO.getListRms_Offline();
+ //额定电压
+ float fBase = 57.74f;
+ //假如所选的是380V,那么PT变比是1:1,因此额定电压要选220 //模拟量通道记录
+ List lstAnalogDTO = comtradeCfgDTO.getLstAnalogDTO();
+ if (!lstAnalogDTO.isEmpty()) {
+ if (lstAnalogDTO.get(0).getFPrimary() / lstAnalogDTO.get(0).getFSecondary() <= 1) {
+ fBase = 220f;
+ }
+ }
+ //采样率
+ int nSJ = comtradeCfgDTO.getFinalSampleRate().intValue();
+ /*********************************
+ * 0是特征幅值(残余电压百分比)
+ * 1是特征幅值(残余电压)
+ * 2额定定压(动态电压)
+ * 3是持续时间
+ **********************************/
+ //ABC三相分析结果
+ List lstEigenvalueDTO = new ArrayList<>();
+ for (int i = 0; i < 3; i++) {
+ //低电压和郭电压标识值
+ int iDDY = 0, iGDY;
+ //某一项分析结果
+ EigenvalueDTO eigenvalueDTO = new EigenvalueDTO();
+ iDDY = App_Disturb_DDY1(lstWave, tblWave, rmstWave, nSJ, i, blType);
+ if (Disturb_Val == 0 && Disturb_SJ == 0) {
+ //判断A相的暂态事件类型是否为短时中断或电压暂降
+ iGDY = App_Disturb_GDY1(lstWave, tblWave, rmstWave, nSJ, i, blType);
+ if (iGDY != 0) {
+ if (Disturb_Val != 0) {
+ if (blType) {
+ //征幅值(残余电压百分比)
+ eigenvalueDTO.setAmplitude(Disturb_Val / rmstWave.get(nSJ + 2).get(i + 1));
+ //特征幅值(残余电压)
+ eigenvalueDTO.setResidualVoltage(Disturb_Val);
+ //额定定压(动态电压)
+ eigenvalueDTO.setRatedVoltage(rmstWave.get(nSJ + 2).get(i + 1));
+ } else {
+ //征幅值(残余电压百分比)
+ eigenvalueDTO.setAmplitude(Disturb_Val / 57.74f);
+ //特征幅值(残余电压)
+ eigenvalueDTO.setResidualVoltage(Disturb_Val);
+ //额定定压(动态电压)
+ eigenvalueDTO.setRatedVoltage(57.74f);
+ }
+ }
+ }
+ //如果都没有找到,那么需要从曲线里面找出比较小的值来计算
+ else {
+ double rate = 0f;
+ //残余电压
+ double residualVoltage = 0.f;
+ switch (i) {
+ case 0:
+ residualVoltage = mutationDTO.getFMinMagA();
+ break;
+ case 1:
+ residualVoltage = mutationDTO.getFMinMagB();
+ break;
+ case 2:
+ residualVoltage = mutationDTO.getFMinMagC();
+ break;
+ default:
+ break;
+ }
+
+ if (residualVoltage != -1) {
+ rate = residualVoltage / fBase > 1 ? 1.0f : residualVoltage / fBase;
+ }
+ //征幅值(残余电压百分比)
+ eigenvalueDTO.setAmplitude((float) rate);
+ //特征幅值(残余电压)
+ eigenvalueDTO.setResidualVoltage((float) residualVoltage);
+ //额定定压(动态电压)
+ eigenvalueDTO.setRatedVoltage(fBase);
+ }
+ } else {
+ if (Disturb_Val != 0) {
+ if (blType) {
+ //征幅值(残余电压百分比)
+ eigenvalueDTO.setAmplitude(Disturb_Val / rmstWave.get(nSJ + 2).get(i + 1));
+ //特征幅值(残余电压)
+ eigenvalueDTO.setResidualVoltage(Disturb_Val);
+ //额定定压(动态电压)
+ eigenvalueDTO.setRatedVoltage(rmstWave.get(nSJ + 2).get(i + 1));
+ } else {
+ //征幅值(残余电压百分比)
+ eigenvalueDTO.setAmplitude(Disturb_Val / 57.74f);
+ //特征幅值(残余电压)
+ eigenvalueDTO.setResidualVoltage(Disturb_Val);
+ //额定定压(动态电压)
+ eigenvalueDTO.setRatedVoltage(57.74f);
+ }
+ }
+ }
+ //持续时间
+ eigenvalueDTO.setDurationTime(Disturb_SJ / nSJ * 20.0f);
+ lstEigenvalueDTO.add(eigenvalueDTO);
+ }
+ return lstEigenvalueDTO;
+ }
+
+ /***
+ * 暂降幅值
+ */
+ private float Disturb_Val = 0;
+ /***
+ * 持续时间
+ */
+ private double Disturb_Time = 0;
+ /***
+ * 暂态启动点号
+ */
+ private float Disturb_SJ = 0;
+
+ /***
+ * 暂降幅值90%
+ */
+ private float Un09 = (0.90f * 57.74f);
+ /***
+ * 暂降幅值2%
+ */
+ private float Un002 = (0.02f * 57.74f);
+ /***
+ * 暂降幅值110%
+ */
+ private float Un110 = (1.10f * 57.74f);
+
+ /************************************
+ *低电压的判据 包含了暂降和中断
+ * @param realWave 原始波形数据
+ * @param tblWave 突变量波形数据
+ * @param rmstWave RMS波形数据
+ * @param nCirclePoint 采样率
+ * @param nType 类别 0:A相,1:B相,2:C相
+ * @param blFlag 浮动门槛和固定门槛
+ *************************************/
+ private int App_Disturb_DDY1(List> realWave, List> tblWave, List> rmstWave, int nCirclePoint, int nType, boolean blFlag) {
+ Disturb_Val = 0;
+ Disturb_Time = 0;
+ Disturb_SJ = 0;
+
+ /****************************
+ * ADC 临时的突变量判据
+ * Disturb_JS_Val 事件启动点时刻的有效值
+ ****************************/
+ double temp, ADC, Disturb_JS_Val = 0;
+ int iTbl = 0;
+ long Disturb_QD = 0;
+ //nSJ就是全波的采样率,nHalfSJ是半波的采样率
+ int nSJ = nCirclePoint, nHalfSJ = nCirclePoint / 2;
+ //定义90%和20%额定电压
+ float fUN09 = Un09, fUN002 = Un002;
+ //增加浮动门槛判断
+ if (blFlag) {
+ /****************************
+ * 计算值去掉一个前一个周波后
+ * 取第二个周波的第二个有效值
+ * 第一个值是时间、A,B,C三相
+ ****************************/
+ if (rmstWave.size() > nSJ + 2) {
+ fUN09 = rmstWave.get(nSJ + 2).get(nType + 1) * 0.9f;
+ fUN002 = rmstWave.get(nSJ + 2).get(nType + 1) * 0.02f;
+ }
+ }
+ /****************************
+ * 从第二个周波开始
+ ****************************/
+ for (int i = nSJ; i < realWave.size(); i++) {
+ //获取RMS有效值
+ float rmsValue = rmstWave.get(i).get(nType + 1);
+ //电压扰动启动判别
+ if (Disturb_QD == 0) {
+ //有效值小于90%
+ if (rmsValue < fUN09) {
+ Disturb_QD = 0xff;
+ Disturb_Val = rmsValue;
+ Disturb_JS_Val = rmsValue;
+ //寻找突变点
+ for (int j = 0; j < nHalfSJ; j++) {
+ //临时的突变量
+ ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1);
+ //临时的突变量小于0的时候取绝对值
+ if (ADC < 0) {
+ ADC = 0 - ADC;
+ }
+ if (ADC > fUN002) {
+ Disturb_SJ += (nHalfSJ - j);
+ iTbl = (i - nHalfSJ + j);
+ break;
+ }
+ }
+ }
+ }
+ //电压扰动返回判别
+ else {
+ if (rmsValue < (fUN09 + fUN002)) {
+ Disturb_SJ++;
+ if (Disturb_Val > rmsValue) {
+ Disturb_Val = rmsValue;
+ }
+ Disturb_JS_Val = rmsValue;
+ } else {
+ if (Disturb_SJ >= (nSJ + nHalfSJ)) {
+ //20%突变量标志
+ int iFlag = 0;
+ for (int j = 0; j < nHalfSJ; j++) {
+ iFlag = j;
+ //临时的突变量
+ ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1);
+ //临时的突变量小于0的时候取绝对值
+ if (ADC < 0) {
+ ADC = 0 - ADC;
+ }
+ if (ADC > fUN002) {
+ break;
+ }
+ }
+ Disturb_SJ -= (nHalfSJ - iFlag);
+ Disturb_Time = ((double) Disturb_SJ) * 20 / nSJ;
+ return iTbl;
+ } else {
+ Disturb_SJ++;
+ ADC = realWave.get(i).get(nType + 1);
+ if (ADC < 0) {
+ ADC = 0 - ADC;
+ }
+ temp = rmsValue - Disturb_JS_Val;
+ if (temp < 0) {
+ temp = 0 - temp;
+ }
+ if ((ADC > 100) && (temp < 0.1)) {
+ Disturb_SJ -= (nHalfSJ + 1);
+ Disturb_Time = ((double) Disturb_SJ) * 20 / nSJ + 1;
+ return iTbl;
+ }
+ }
+ Disturb_JS_Val = rmsValue;
+ }
+ }
+ }
+ return iTbl;
+ }
+
+
+ /************************************
+ *过电压的判据
+ * @param realWave 原始波形数据
+ * @param tblWave 突变量波形数据
+ * @param rmstWave RMS波形数据
+ * @param nCirclePoint 采样率
+ * @param nType 类别 0:A相,1:B相,2:C相
+ * @param blFlag 浮动门槛和固定门槛
+ * @return
+ *************************************/
+ private int App_Disturb_GDY1(List> realWave, List> tblWave, List> rmstWave, int nCirclePoint, int nType, boolean blFlag) {
+ Disturb_Val = 0;
+ Disturb_Time = 0;
+ Disturb_SJ = 0;
+
+ /****************************
+ * ADC 临时的突变量判据
+ * Disturb_JS_Val 事件启动点时刻的有效值
+ ****************************/
+ double temp, ADC, Disturb_JS_Val = 0;
+ int iTbl = 0;
+ long Disturb_QD = 0;
+ //nSJ就是全波的采样率,nHalfSJ是半波的采样率
+ int nSJ = nCirclePoint, nHalfSJ = nCirclePoint / 2;
+ //定义110%和20%额定电压
+ float fUN110 = Un110, fUN002 = Un002;
+ //增加浮动门槛判断
+ if (blFlag) {
+ /****************************
+ * 计算值去掉一个前一个周波后
+ * 取第二个周波的第二个有效值
+ * 第一个值是时间、A,B,C三相
+ ****************************/
+ if (rmstWave.size() > nSJ + 2) {
+ fUN110 = rmstWave.get(nSJ + 2).get(nType + 1) * 1.1f;
+ fUN002 = rmstWave.get(nSJ + 2).get(nType + 1) * 0.02f;
+ }
+ }
+ /****************************
+ * 从第二个周波开始
+ ****************************/
+ for (int i = nSJ; i < realWave.size(); i++) {
+ //获取RMS有效值
+ float rmsValue = rmstWave.get(i).get(nType + 1);
+ //电压扰动启动判别
+ if (Disturb_QD == 0) {
+ if (rmsValue > fUN110) {
+ Disturb_QD = 0xff;
+ Disturb_Val = rmsValue;
+ Disturb_JS_Val = rmsValue;
+ //寻找突变点
+ for (int j = 0; j < nHalfSJ; j++) {
+ //临时的突变量
+ ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1);
+ //临时的突变量小于0时候取绝对值
+ if (ADC < 0) {
+ ADC = 0 - ADC;
+ }
+ if (ADC > fUN002) {
+ Disturb_SJ += (nHalfSJ - j);
+ iTbl = (int) (i - nHalfSJ + j);
+ break;
+ }
+ }
+ }
+ }
+ //电压扰动返回判别
+ else {
+ if (rmsValue > (fUN110 - fUN002)) {
+ Disturb_SJ++;
+ if (Disturb_Val < rmsValue) {
+ Disturb_Val = rmsValue;
+ }
+ Disturb_JS_Val = rmsValue;
+ } else {
+ if (Disturb_SJ >= (nSJ + nHalfSJ)) {
+ int iFlag = 0;
+ for (int j = 0; j < nHalfSJ; j++) {
+ iFlag = j;
+ ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1);
+ if (ADC < 0) {
+ ADC = 0 - ADC;
+ }
+ if (ADC > fUN002) {
+ break;
+ }
+ }
+ Disturb_SJ -= (nHalfSJ - iFlag);
+ Disturb_Time = (double) Disturb_SJ * 20 / nSJ;
+ return iTbl;
+ } else {
+ Disturb_SJ++;
+ ADC = realWave.get(i).get(nType + 1);
+ if (ADC < 0) {
+ ADC = 0 - ADC;
+ }
+ temp = rmsValue - Disturb_JS_Val;
+ if (temp < 0) {
+ temp = 0 - temp;
+ }
+ if ((ADC > 100) && (temp < 0.1)) {
+ Disturb_SJ -= (nHalfSJ + 1);
+ Disturb_Time = Disturb_SJ * 20 / nSJ + 1;
+ return iTbl;
+ }
+ }
+ Disturb_JS_Val = rmsValue;
+ }
+ }
+ }
+ return iTbl;
+ }
+
+
+ /*********************************
+ * 获取波形标题的方法
+ * param tmpComtradeCfgDTO 文件路径
+ * return 返回List返回数据格式说明
+ **********************************/
+ private List getWaveTitle(ComtradeCfgDTO comtradeCfgDTO) {
+ //编辑数据标题 YXB2020-10-09 去除相别为N相的数据//存储数据标题
+ List tmpWaveTitle = new ArrayList<>();
+ // 模拟量通道记录类
+ AnalogDTO analogDTO;
+ tmpWaveTitle.add("Time");
+ String strUnit;
+ for (int j = 0; j < comtradeCfgDTO.getNAnalogNum(); j++) {
+ analogDTO = comtradeCfgDTO.getLstAnalogDTO().get(j);
+ // 假如为N相则跳过
+ if (!StrUtil.equals(analogDTO.getSzPhasicName().toUpperCase(), "N")) {
+ if ("A".equalsIgnoreCase(analogDTO.getSzUnitName())) {
+ strUnit = "I";
+ } else {
+ strUnit = "U";
+ }
+ tmpWaveTitle.add(strUnit + analogDTO.getSzPhasicName().toUpperCase() + "相");
+ }
+ }
+ return tmpWaveTitle;
+ }
+
+ /*********************************
+ * 由.cfg 路径更换成 .dat
+ * param strFilePath 文件路径
+ * return String返回.dat文件的路径
+ **********************************/
+ private String getDatFilePath(String strFilePath) {
+ String strDatFilePath;
+ //替换前的
+ String strOriginally = ".cfg";
+ //替换后的
+ String strReplace = ".dat";
+ //截取.之后字符串
+ String strIntercept = strFilePath.substring(strFilePath.lastIndexOf(".") + 1);
+ switch (strIntercept) {
+ case "cfg":
+ strOriginally = ".cfg";
+ strReplace = ".dat";
+ break;
+ case "CFG":
+ strOriginally = ".CFG";
+ strReplace = ".DAT";
+ break;
+ case "Cfg":
+ strOriginally = ".Cfg";
+ strReplace = ".Dat";
+ break;
+ case "CFg":
+ strOriginally = ".CFg";
+ strReplace = ".DAt";
+ break;
+ case "cFg":
+ strOriginally = ".cFg";
+ strReplace = ".dAt";
+ break;
+ case "cFG":
+ strOriginally = ".cFG";
+ strReplace = ".dAT";
+ break;
+ default:
+ break;
+ }
+ //把.cfg换成.dat
+ strDatFilePath = strFilePath.replace(strOriginally, strReplace);
+ return strDatFilePath;
+ }
+
+ public static void main(String[] args) {
+ /********************************************************
+ * iFlag == 0 高级算法的要求,采样率只能是32-128
+ * iFlag == 1 普通展示,采样率按照cfg里面最小的(大于32)
+ * iFlag == 2 App抽点要求,采样率抽点成32
+ * iFlag == 3 高级算法原始波形(大于32)
+ ********************************************************/
+ /** 输出格式: 2014-5-05 00:00:00 大写H为24小时制 */
+ DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String s;
+ Date d = new Date();
+ s = sdf.format(d);
+ System.out.println(s);
+ WaveFileComponent waveFileComponent = new WaveFileComponent();
+ InputStream cfgStream = waveFileComponent.getFileInputStreamByFilePath("D:\\comtrade\\00-B7-8D-00-B7-25\\1_20200629_164016_234.CFG");
+ InputStream datStream = waveFileComponent.getFileInputStreamByFilePath("D:\\comtrade\\00-B7-8D-00-B7-25\\1_20200629_164016_234.DAT");
+ // 获取瞬时波形 //获取原始波形值
+ WaveDataDTO waveDataDTO = waveFileComponent.getComtrade(cfgStream,datStream, 1);
+ d = new Date();
+ s = sdf.format(d);
+ System.out.println(s);
+ // 获取RMS波形
+ WaveDataDTO waveDataDTO1 = waveFileComponent.getValidData(waveDataDTO);
+ d = new Date();
+ s = sdf.format(d);
+ System.out.println(s);
+ // 获取特征值
+ List lstEigenvalueDTO = waveFileComponent.getEigenvalue(waveDataDTO, true);
+ }
+
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/component/WavePicComponent.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/component/WavePicComponent.java
new file mode 100644
index 000000000..db527e2d6
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/component/WavePicComponent.java
@@ -0,0 +1,152 @@
+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.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.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.Base64;
+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 generateImageShun(WaveDataDTO waveDataDTO, List 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
+ InputStream instantStream = IoUtil.toStream(firstPic, CharsetUtil.UTF_8);
+ picPath = fileStorageUtil.uploadStream(instantStream, 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 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
+ InputStream instantStream = IoUtil.toStream(firstPic, CharsetUtil.UTF_8);
+ picPath = fileStorageUtil.uploadStream(instantStream, 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);
+ }
+ }
+
+
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/bo/InstantData.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/bo/InstantData.java
new file mode 100644
index 000000000..b7b47757e
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/bo/InstantData.java
@@ -0,0 +1,25 @@
+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> aValue =new ArrayList<>();
+
+ List> bValue =new ArrayList<>();
+
+ List> cValue =new ArrayList<>();
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/bo/RmsData.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/bo/RmsData.java
new file mode 100644
index 000000000..444118126
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/bo/RmsData.java
@@ -0,0 +1,25 @@
+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> aValue =new ArrayList<>();
+
+ List> bValue =new ArrayList<>();
+
+ List> cValue =new ArrayList<>();
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/bo/WaveDataDetail.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/bo/WaveDataDetail.java
new file mode 100644
index 000000000..4ade35362
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/bo/WaveDataDetail.java
@@ -0,0 +1,33 @@
+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 unit;
+
+ private Boolean isOpen = false;
+
+ private String title;
+
+ private List colors= new ArrayList<>();
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/AnalogDTO.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/AnalogDTO.java
new file mode 100644
index 000000000..127b83c1c
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/AnalogDTO.java
@@ -0,0 +1,46 @@
+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;
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/ComtradeCfgDTO.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/ComtradeCfgDTO.java
new file mode 100644
index 000000000..185ba122f
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/ComtradeCfgDTO.java
@@ -0,0 +1,50 @@
+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 lstAnalogDTO;//模拟量通道记录
+ private List lstDigitalDTO;//数字量通道记录
+
+ public Integer nRates;//对应采样次数
+ public List lstRate;//采样率合集
+
+ // add by sw 暂降触发时间
+ private Date firstTime; // 暂降触发第一次
+ private Integer firstMs; // 暂降触发第一次毫秒
+
+ // 波形前推周波束
+ private Integer nPush = 0;
+ // 最终采样率,计算的时候只用一个采样率
+ private Long finalSampleRate;
+ // 整个波形大小
+ private Long nAllWaveNum = 0L;
+
+ /***
+ * 赋值编码格式(二进制)
+ */
+ private String strBinType;
+
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/DigitalDTO.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/DigitalDTO.java
new file mode 100644
index 000000000..ab0350adf
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/DigitalDTO.java
@@ -0,0 +1,30 @@
+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;
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/EigenvalueDTO.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/EigenvalueDTO.java
new file mode 100644
index 000000000..f082491e9
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/EigenvalueDTO.java
@@ -0,0 +1,28 @@
+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;
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/MutationDTO.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/MutationDTO.java
new file mode 100644
index 000000000..9ef8ae947
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/MutationDTO.java
@@ -0,0 +1,27 @@
+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> listRms_Offline = new ArrayList<>();//离线数据RMS有效值数据
+ private List> listTBL_Offline = new ArrayList<>();//离线数据突变量数据
+ private double fMinMagA = 99999d;
+ private double fMinMagB = 99999d;
+ private double fMinMagC = 99999d;
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/RateDTO.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/RateDTO.java
new file mode 100644
index 000000000..169428e09
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/RateDTO.java
@@ -0,0 +1,24 @@
+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 Long nOneSample;
+ // 总采样点数
+ private Long nSampleNum;
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/WaveDataDTO.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/WaveDataDTO.java
new file mode 100644
index 000000000..2854c939a
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/dto/WaveDataDTO.java
@@ -0,0 +1,44 @@
+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 waveTitle;
+ //波形对应的值
+ private List> listWaveData;
+ //波形RMS值
+ private List> listRmsData;
+ //RMS最小值
+ private List> listRmsMinData;
+ //波形对应的相别数量
+ private Integer iPhasic;
+ //接线方式(0.星型接法;1.三角型接法;2.开口三角型接法)
+ private Integer ptType;
+ //PT变比
+ private Double pt;
+ //CT变比"
+ private Double ct;
+ //暂降发生时刻
+ private String time;
+ //测点名称
+ private String monitorName;
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/enums/WaveFileResponseEnum.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/enums/WaveFileResponseEnum.java
new file mode 100644
index 000000000..a59138b21
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/pojo/enums/WaveFileResponseEnum.java
@@ -0,0 +1,33 @@
+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","波形文件数据缺失"),
+ 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;
+ }
+}
diff --git a/pqs-common/common-event/src/main/java/com/njcn/event/file/utils/WaveUtil.java b/pqs-common/common-event/src/main/java/com/njcn/event/file/utils/WaveUtil.java
new file mode 100644
index 000000000..dcd6a170a
--- /dev/null
+++ b/pqs-common/common-event/src/main/java/com/njcn/event/file/utils/WaveUtil.java
@@ -0,0 +1,189 @@
+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 filterWaveData(WaveDataDTO waveDataDTO) {
+ List waveDataDetails = new ArrayList<>();
+ List waveTitle = waveDataDTO.getWaveTitle();
+ boolean openTri = waveDataDTO.getPtType() == 2;
+ /************ 一个图形的相别决定了图形个数 Modify by yexb -----start ***********/
+ Integer iPhase = waveDataDTO.getIPhasic();
+ int picCounts = (waveTitle.size() - 1) / iPhase;
+ /**处理相别的颜色**/
+ List 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");
+ 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");
+ 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");
+ 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> sAValue = new ArrayList<>(), sBValue = new ArrayList<>(), sCValue = new ArrayList<>(), rAValue = new ArrayList<>(), rBValue = new ArrayList<>(), rCValue = new ArrayList<>();
+ List> 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() {{
+ 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() {{
+ 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() {{
+ 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> 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() {{
+ 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() {{
+ 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() {{
+ 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;
+ }
+}