Files
CN_Tool/tools/wave-tool/temp/component/WaveFileComponent.java
2026-04-15 11:53:44 +08:00

1671 lines
88 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
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())) {
throw new BusinessException(WaveFileResponseEnum.CFG_DATA_ERROR);
}
/*****根据通道号计算相别** 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());
// 组装解析抬头
getWaveTitle(waveDataDTO, comtradeCfgDTO);
// 解析.dat文件
List<List<Float>> listWaveData = getComtradeDat(comtradeCfgDTO, datStream, iType);
waveDataDTO.setComtradeCfgDTO(comtradeCfgDTO);
waveDataDTO.setListWaveData(listWaveData);
//add by hongawen,将暂态触发起始时间记录下来
waveDataDTO.setTime(DateUtil.format(comtradeCfgDTO.getTimeTrige(), DatePattern.NORM_DATETIME_MS_PATTERN));
/*****根据通道号计算相别** add by yexb -----end****/
return waveDataDTO;
}
/*********************************
* 根据波形数据算出rms值数据
* param waveDataDTO 瞬时波形包含了CFG配置文件
* List<List<Float>> 返回RMS波形
**********************************/
@SuppressWarnings("unused")
public WaveDataDTO getValidData(WaveDataDTO waveDataDTO) {
//CFG 配置文件
ComtradeCfgDTO comtradeCfgDTO = waveDataDTO.getComtradeCfgDTO();
//瞬时波形值
List<List<Float>> lstWave = waveDataDTO.getListWaveData();
//返回rms的值
List<List<Float>> 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<List<Float>> listRmsMin = new ArrayList<>();
if (lstWave.size() > 0) {
nPhasic = comtradeCfgDTO.getNPhasic();
//ComtradeCfg.nAnalogNum为值的个数(-1的原因是一个存的是时间)
iWave = Math.floor((lstWave.get(0).size() - 1) / (double) nPhasic);
List<Float> tmpListRms;
List<Float> 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<Float> 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<Float> 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<Float> 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<Float> 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<Float> 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<EigenvalueDTO> getEigenvalue(WaveDataDTO waveDataDTO, boolean blType) {
//CFG 配置文件
ComtradeCfgDTO comtradeCfgDTO = waveDataDTO.getComtradeCfgDTO();
// 瞬时波形值
List<List<Float>> lstWave = waveDataDTO.getListWaveData();
//获取最终采样率
int finalSampleRate = comtradeCfgDTO.getFinalSampleRate();
// 返回值
List<EigenvalueDTO> 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();
try (InputStreamReader read = new InputStreamReader(cfgStream, CharsetUtil.CHARSET_GBK); BufferedReader bufferedReader = new BufferedReader(read);) {
// 第一行不关心仅仅是一些描述类的信息
String strFileLine = bufferedReader.readLine();
// 第二行需要关心第二个(模拟量的个数)和第三个参数(开关量的个数)
strFileLine = bufferedReader.readLine();
// 按“,”进行分割
String[] strTempArray = strFileLine.split(StrUtil.COMMA);
// 总个数
comtradeCfgDTO.setNChannelNum(Integer.parseInt(strTempArray[0]));
// 模拟量的个数
comtradeCfgDTO.setNAnalogNum(Integer.parseInt(strTempArray[1].substring(0, strTempArray[1].length() - 1)));
// 开关量的个数
comtradeCfgDTO.setNDigitalNum(Integer.parseInt(strTempArray[2].substring(0, strTempArray[2].length() - 1)));
// 从第三行开始的ComtradeCfg.nChannelNum行是模拟量通道和数字量通道
List<AnalogDTO> 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);
//通道序号
analogDTO.setNIndex(Integer.parseInt(strTempArray[0]));
// 通道名称
analogDTO.setSzChannleName(strTempArray[1]);
// 相位名称
analogDTO.setSzPhasicName(strTempArray[2]);
// 监视的通道名称
analogDTO.setSzMonitoredChannleName(strTempArray[3]);
// 通道的单位
analogDTO.setSzUnitName(strTempArray[4]);
// 通道的系数
analogDTO.setFCoefficent(Float.parseFloat(strTempArray[5]));
// 通道的偏移量
analogDTO.setFOffset(Float.parseFloat(strTempArray[6]));
// 起始采样时间的偏移量
analogDTO.setFTimeOffset(Float.parseFloat(strTempArray[7]));
// 采样值的最小值
analogDTO.setNMin(Integer.parseInt(strTempArray[8]));
// 采样值的最大值
analogDTO.setNMax(Integer.parseInt(strTempArray[9]));
// 一次变比
analogDTO.setFPrimary(Float.parseFloat(strTempArray[10]));
// 二次变比
analogDTO.setFSecondary(Float.parseFloat(strTempArray[11]));
// 一次值还是二次值标志
analogDTO.setSzValueType(strTempArray[12]);
}
//WW 2019-11-14 // 采样频率
String freqLine = bufferedReader.readLine();
int nFreq;
try {
// 先尝试解析为double再四舍五入为整数以兼容"50.00"这样的格式
nFreq = (int) Math.round(Double.parseDouble(freqLine));
} catch (NumberFormatException e) {
// 如果失败则使用原来的整数解析方式
nFreq = Integer.parseInt(freqLine);
}
// 获取采样段数
strFileLine = bufferedReader.readLine();
int nRates = Integer.parseInt(strFileLine);
comtradeCfgDTO.setNRates(nRates);
// 获得每段的采样率 //采样率
List<RateDTO> lstRate = new ArrayList<>();
int 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
double doubleValue = Double.parseDouble(strTempArray[0]); // 解析为 double
int result = (int) (doubleValue / nFreq); // 强制转换为 int
rateDTO.setNOneSample(result);
// 总点数 //这里的strTemp是一个偏移量
rateDTO.setNSampleNum((Integer.parseInt(strTempArray[1]) - nOffset));
nOffset += rateDTO.getNSampleNum();
lstRate.add(rateDTO);
}
comtradeCfgDTO.setLstRate(lstRate);
// 增加读取波形起始时间个结束时间
String timeFormat = "dd/MM/yyyy,HH:mm:ss.SSS";
// 波形起始时间
strFileLine = bufferedReader.readLine();
strFileLine = strFileLine.substring(0, strFileLine.length() - 3);
comtradeCfgDTO.setTimeStart(DateUtil.parse(strFileLine, timeFormat));
// 暂态触发时间
strFileLine = bufferedReader.readLine();
strFileLine = strFileLine.substring(0, strFileLine.length() - 3);
comtradeCfgDTO.setTimeTrige(DateUtil.parse(strFileLine, timeFormat));
// 获取触发时间的时间 + 毫秒
Calendar calendar = DateUtil.calendar(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;
}
return comtradeCfgDTO;
}
/*********************************
* 读取dat方法
* param strFilePath .dat访问路径
* param strFilePath .dat访问路径
* param iType 访问波形类型
* List<List<Float>> 返回波形瞬时值
**********************************/
private List<List<Float>> getComtradeDat(ComtradeCfgDTO comtradeCfgDTO, InputStream datStream, int iType) {
//返回数据如果仅仅做展示后期考虑换String类型降低内存开销
List<List<Float>> listWaveData = new ArrayList<>();
//初始化xValue的值
float xValueAll = 0;
//判断是否首次登陆
boolean blxValue = false;
byte[] datArray;
try {
datArray = IoUtil.readBytes(datStream);
if (ArrayUtil.isEmpty(datArray)) {
throw new BusinessException(WaveFileResponseEnum.DAT_DATA_ERROR);
}
// 计算每个单独的数据块的大小 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 = (int)Math.floor(datArray.length / nBlockSize);
// 获取采样率
int finalSampleRate = getFinalWaveSample(comtradeCfgDTO.getLstRate(), iType);
if (finalSampleRate != -1) {
//设置最终采样率
comtradeCfgDTO.setFinalSampleRate(finalSampleRate);
// 计算转换后的采样率
int nnInd = 0;
// 抽点后总共多少点数据
int nWaveNum;
//抽点后新的的采样率
List<RateDTO> newLstRate = new ArrayList<>();
for (int iRate = 0; iRate < comtradeCfgDTO.getNRates(); iRate++) {
// 计算本段录波总共有多少波形
nWaveNum = comtradeCfgDTO.getLstRate().get(iRate).getNSampleNum() / comtradeCfgDTO.getLstRate().get(iRate).getNOneSample();
//设置总波形大小
comtradeCfgDTO.setNAllWaveNum(comtradeCfgDTO.getNAllWaveNum() + nWaveNum);
// 将最低采样率替换到本段录波内
RateDTO tmpRateDTO = new RateDTO();
// 有效值标志,如果是有效值,那么就需要反向补点,而不是抽点
if (comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() >= 32) {
//YXB 2025-08-27
tmpRateDTO.bRMSFlag = false;
}
//如果采样是全波有效值或者半波有效值,需要去补足周波点数 YXB 2025-08-27
else if (comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() <= 2) {
//YXB 2025-08-27
tmpRateDTO.bRMSFlag = true;
}
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);
}
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);
// 判断是否进入下一段
if (i == tmpRateDTO.getNSampleNum() + nOffSet) {
nOffSet += tmpRateDTO.getNSampleNum();
nIndex++;
if (nIndex == nnInd) {
break;
}
}
tmpRateDTO = comtradeCfgDTO.getLstRate().get(nIndex);
//YXB 2025-08-27 如果是有效值,那么需要去补点,而不是抽点
if (newLstRate.get(nIndex).bRMSFlag == true) {
//计算本段补点采样间隔
nWaveSpan = newLstRate.get(nIndex).getNOneSample() / tmpRateDTO.getNOneSample();
} else {
// 计算本段抽点采样间隔
nWaveSpan = tmpRateDTO.getNOneSample() / newLstRate.get(nIndex).getNOneSample();
}
dfValue = (float) 20 / tmpRateDTO.getNOneSample();
// 判断是否到了需要抽的采样点
if (i % nWaveSpan == 0) {
// 计算每个通道的值
//存储局部数据集合包含了时间ABC三相
List<Float> tmpWaveData = new ArrayList<>();
//YXB 2025-08-27 如果是有效值,那么需要去补点,而不是抽点
if (newLstRate.get(nIndex).bRMSFlag == true) {
// 计算有多少个周波
long allWaveTemp = newLstRate.get(nIndex).getNSampleNum() / newLstRate.get(nIndex).getNOneSample();
// 本段需要补多少点
long allempSample = newLstRate.get(nIndex).getNOneSample();
int currentDataIndex = i;
for (int iWaveTemp = 0; iWaveTemp < allWaveTemp; iWaveTemp++) {
for (int mTempSample = 0; mTempSample < allempSample; mTempSample++) {
tmpWaveData = new ArrayList<>();
for (int j = 0; j < comtradeCfgDTO.getNAnalogNum(); j++) {
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzPhasicName().equalsIgnoreCase("N")) {
break;
}
float fCoef = comtradeCfgDTO.getLstAnalogDTO().get(j).getFCoefficent();
fValue = BitConverter.byte2ToUnsignedShort(datArray, currentDataIndex * nBlockSize + 2 * 4 + j * 2) * fCoef;
//WW 2019-11-14
/*************************
* 1、接口返回的默认是二次值
* 2、P是一次值 S是二次值
* 3、S(二次值)情况下:
* ①、单位为"V"时候则直接等于;
* ②、单位为"kV"时候需要乘以1000
* 4、P(一次值)情况下:
* ①、单位为"V"时候则直接等于;
* ②、单位为"kV"时候需要乘以1000
*************************/
//P是一次值 S是二次值
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("S")) {
//判断单位是V还是kV
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
fValue = fValue * 1000.0f;
} else {
fValue = fValue;
}
}
//P是一次值 S是二次值
else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("P")) {
//判断单位是V还是kV
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("V")) {
//根据cfg内的变比将一次值转换成二次值
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
} else {
fValue = fValue;
}
}
//判断单位是V还是kV
else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
//根据cfg内的变比将一次值转换成二次值
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
fValue = fValue * 1000.0f * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
} else {
fValue = fValue;
}
} else //还有可能是 电流单位是A
{
//根据cfg内的变比将一次值转换成二次值
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
} else {
fValue = fValue;
}
}
}
//xValue前移量假如是第一次时候则需要前移
if (!blxValue && j == 0) {
xValueAll = (float) (currentDataIndex * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
blxValue = true;
//只增加一个xValue的值 //增加时间值
tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
} else if (j == 0) {
xValueAll += (float) dfValue / nWaveSpan;
//只增加一个xValue的值 //增加时间值
tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
}
//不同通道yValue的值都需要增加最终成ABC三相 //每个通道的值
tmpWaveData.add((float) (Math.round(fValue * 100)) / 100);
}
//把每个单独的值赋予到整体里面去
listWaveData.add(tmpWaveData);
}
// 把每个单独的值赋予到整体里面去
if (iWaveTemp < (allWaveTemp - 1)) {
currentDataIndex++;
}
}
} else {
for (int j = 0; j < comtradeCfgDTO.getNAnalogNum(); j++) {
//数据只有电压ABC三相数据不展示U0、I0等数据 YXB2020-10-09 去除相别为N相的数据
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzPhasicName().equalsIgnoreCase("N")) {
break;
}
float fCoef = comtradeCfgDTO.getLstAnalogDTO().get(j).getFCoefficent();
fValue = BitConverter.byte2ToUnsignedShort(datArray, i * nBlockSize + 2 * 4 + j * 2) * fCoef;
//WW 2019-11-14
/**************************
* 1、接口返回的默认是二次值
* 2、P是一次值 S是二次值
* 3、S(二次值)情况下:
* ①、单位为"V"时候则直接等于;
* ②、单位为"kV"时候需要乘以1000
* 4、P(一次值)情况下:
* ①、单位为"V"时候则直接等于;
* ②、单位为"kV"时候需要乘以1000
**************************/
//P是一次值 S是二次值
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("S")) {
//判断单位是V还是kV
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
fValue = fValue * 1000.0f;
} else {
fValue = fValue;
}
}
//P是一次值 S是二次值
else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("P")) {
//判断单位是V还是kV
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("V")) {
//根据cfg内的变比将一次值转换成二次值
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
} else {
fValue = fValue;
}
}
//判断单位是V还是kV
else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
//根据cfg内的变比将一次值转换成二次值
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
fValue = fValue * 1000.0f * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
} else {
fValue = fValue;
}
} else //还有可能是 电流单位是A
{
//根据cfg内的变比将一次值转换成二次值
if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
} else {
fValue = fValue;
}
}
}
//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) {
e.printStackTrace();
throw new BusinessException(WaveFileResponseEnum.DAT_DATA_ERROR);
}
return listWaveData;
}
// private List<List<Float>> getComtradeDat(ComtradeCfgDTO comtradeCfgDTO, InputStream datStream, int iType) {
// //返回数据如果仅仅做展示后期考虑换String类型降低内存开销
// List<List<Float>> listWaveData = new ArrayList<>();
// //初始化xValue的值
// float xValueAll = 0;
// //判断是否首次登陆
// boolean blxValue = false;
// byte[] datArray;
// try {
// datArray = IoUtil.readBytes(datStream);
// if (ArrayUtil.isEmpty(datArray)) {
// throw new BusinessException(WaveFileResponseEnum.DAT_DATA_ERROR);
// }
// // 计算每个单独的数据块的大小 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 = (int)Math.floor(datArray.length / nBlockSize);
//
// // 获取采样率
// int finalSampleRate = getFinalWaveSample(comtradeCfgDTO.getLstRate(), iType);
// if (finalSampleRate != -1) {
// //设置最终采样率
// comtradeCfgDTO.setFinalSampleRate(finalSampleRate);
// // 计算转换后的采样率
// int nnInd = 0;
// // 抽点后总共多少点数据
// int nWaveNum;
// //抽点后新的的采样率
// List<RateDTO> 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();
// // 有效值标志,如果是有效值,那么就需要反向补点,而不是抽点
// if (comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() >= 32) {
// //YXB 2025-08-27
// tmpRateDTO.bRMSFlag = false;
// }
// //如果采样是全波有效值或者半波有效值,需要去补足周波点数 YXB 2025-08-27
// else if (comtradeCfgDTO.getLstRate().get(iRate).getNOneSample() <= 2) {
// //YXB 2025-08-27
// tmpRateDTO.bRMSFlag = true;
// }
// 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);
// // 判断是否进入下一段
// if (i == tmpRateDTO.getNSampleNum() + nOffSet) {
// nOffSet += tmpRateDTO.getNSampleNum();
// nIndex++;
// if (nIndex == nnInd) {
// break;
// }
// }
// tmpRateDTO = comtradeCfgDTO.getLstRate().get(nIndex);
// //YXB 2025-08-27 如果是有效值,那么需要去补点,而不是抽点
// if (newLstRate.get(nIndex).bRMSFlag == true) {
// //计算本段补点采样间隔
// nWaveSpan = newLstRate.get(nIndex).getNOneSample() / tmpRateDTO.getNOneSample();
// } else {
// // 计算本段抽点采样间隔
// nWaveSpan = tmpRateDTO.getNOneSample() / newLstRate.get(nIndex).getNOneSample();
// }
//
// dfValue = (float) 20 / tmpRateDTO.getNOneSample();
// // 判断是否到了需要抽的采样点
// if (i % nWaveSpan == 0) {
// // 计算每个通道的值
// //存储局部数据集合包含了时间ABC三相
// List<Float> tmpWaveData = new ArrayList<>();
// //YXB 2025-08-27 如果是有效值,那么需要去补点,而不是抽点
// if (newLstRate.get(nIndex).bRMSFlag == true) {
// // 计算有多少个周波
// long allWaveTemp = newLstRate.get(nIndex).getNSampleNum() / newLstRate.get(nIndex).getNOneSample();
// // 本段需要补多少点
// long allempSample = newLstRate.get(nIndex).getNOneSample();
// //int iStartWaveTemp = i ;// 开始补点的起点
// for (int iWaveTemp = 0; iWaveTemp < allWaveTemp; iWaveTemp++) {
// for (int mTempSample = 0; mTempSample < allempSample; mTempSample++) {
// //最多只有半波有效值也就是每周波是1个或者2个点然后去补最少16个点
// if (mTempSample / nWaveSpan == 1 && mTempSample % nWaveSpan == 0) {
// i++;
// }
// //存储局部数据集合包含了时间ABC三相
// tmpWaveData = new ArrayList<>();
// for (int j = 0; j < comtradeCfgDTO.getNAnalogNum(); j++) {
// //数据只有电压ABC三相数据不展示U0、I0等数据 YXB2020-10-09 去除相别为N相的数据
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzPhasicName().equalsIgnoreCase("N")) {
// break;
// }
// float fCoef = comtradeCfgDTO.getLstAnalogDTO().get(j).getFCoefficent();
//
// if((i * nBlockSize + 2 * 4 + j * 2) == 2437568){
// System.out.println(55);
// }
// fValue = BitConverter.byte2ToUnsignedShort(datArray, i * nBlockSize + 2 * 4 + j * 2) * fCoef;
// //WW 2019-11-14
// /*************************
// * 1、接口返回的默认是二次值
// * 2、P是一次值 S是二次值
// * 3、S(二次值)情况下:
// * ①、单位为"V"时候则直接等于;
// * ②、单位为"kV"时候需要乘以1000
// * 4、P(一次值)情况下:
// * ①、单位为"V"时候则直接等于;
// * ②、单位为"kV"时候需要乘以1000
// *************************/
// //P是一次值 S是二次值
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("S")) {
// //判断单位是V还是kV
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
// fValue = fValue * 1000.0f;
// } else {
// fValue = fValue;
// }
// }
// //P是一次值 S是二次值
// else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("P")) {
// //判断单位是V还是kV
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("V")) {
// //根据cfg内的变比将一次值转换成二次值
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
// fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
// } else {
// fValue = fValue;
// }
// }
// //判断单位是V还是kV
// else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
// //根据cfg内的变比将一次值转换成二次值
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
// fValue = fValue * 1000.0f * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
// } else {
// fValue = fValue;
// }
// } else //还有可能是 电流单位是A
// {
// //根据cfg内的变比将一次值转换成二次值
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
// fValue = comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
// } else {
// fValue = fValue;
// }
// }
// }
//
// //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) dfValue / nWaveSpan;
// //只增加一个xValue的值 //增加时间值
// tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
// }
//
// //不同通道yValue的值都需要增加最终成ABC三相 //每个通道的值
// tmpWaveData.add((float) (Math.round(fValue * 100)) / 100);
// }
// //把每个单独的值赋予到整体里面去
// listWaveData.add(tmpWaveData);
// }
// // 把每个单独的值赋予到整体里面去
// if (iWaveTemp < (allWaveTemp - 1)) {
// i++;
// }
// }
// } else {
// for (int j = 0; j < comtradeCfgDTO.getNAnalogNum(); j++) {
// //数据只有电压ABC三相数据不展示U0、I0等数据 YXB2020-10-09 去除相别为N相的数据
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzPhasicName().equalsIgnoreCase("N")) {
// break;
// }
//
// float fCoef = comtradeCfgDTO.getLstAnalogDTO().get(j).getFCoefficent();
// fValue = BitConverter.byte2ToUnsignedShort(datArray, i * nBlockSize + 2 * 4 + j * 2) * fCoef;
//
// //WW 2019-11-14
// /**************************
// * 1、接口返回的默认是二次值
// * 2、P是一次值 S是二次值
// * 3、S(二次值)情况下:
// * ①、单位为"V"时候则直接等于;
// * ②、单位为"kV"时候需要乘以1000
// * 4、P(一次值)情况下:
// * ①、单位为"V"时候则直接等于;
// * ②、单位为"kV"时候需要乘以1000
// **************************/
// //P是一次值 S是二次值
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("S")) {
// //判断单位是V还是kV
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
// fValue = fValue * 1000.0f;
// } else {
// fValue = fValue;
// }
// }
// //P是一次值 S是二次值
// else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzValueType().equalsIgnoreCase("P")) {
// //判断单位是V还是kV
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("V")) {
// //根据cfg内的变比将一次值转换成二次值
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
// fValue = fValue * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
// } else {
// fValue = fValue;
// }
// }
// //判断单位是V还是kV
// else if (comtradeCfgDTO.getLstAnalogDTO().get(j).getSzUnitName().equalsIgnoreCase("KV")) {
// //根据cfg内的变比将一次值转换成二次值
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
// fValue = fValue * 1000.0f * comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
// } else {
// fValue = fValue;
// }
// } else //还有可能是 电流单位是A
// {
// //根据cfg内的变比将一次值转换成二次值
// if (comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary() != 0.0f) {
// fValue = comtradeCfgDTO.getLstAnalogDTO().get(j).getFSecondary() / comtradeCfgDTO.getLstAnalogDTO().get(j).getFPrimary();
// } else {
// fValue = fValue;
// }
// }
// }
// //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) {
// e.printStackTrace();
// throw new BusinessException(WaveFileResponseEnum.DAT_DATA_ERROR);
// }
//
// return listWaveData;
// }
/*********************************
* 获取最小(最终)采样率方法
* @param lstRate cfg中关于采样率参数
* @return 返回最小采样率
**********************************/
private int getFinalWaveSample(List<RateDTO> lstRate, int iType) {
// 最终返回采样率
int nFinalOneSample = -1;
// 最小采样率
int nMinOneSample = -1;
if (!lstRate.isEmpty()) {
nMinOneSample = lstRate.get(0).getNOneSample();
int tmpOneSample;
for (RateDTO rateDTO : lstRate) {
tmpOneSample = rateDTO.getNOneSample();
//YXB 2025-08-27 32->16
if (tmpOneSample >= 16) {
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;
} else {
nFinalOneSample = nMinOneSample;
}
break;
case 2:
nFinalOneSample = 32;
break;
default:
nFinalOneSample = nMinOneSample;
break;
}
return nFinalOneSample;
}
/*********************************
* 离线波形导入时获取突变量算法
* param tmpListWave 波形原始数据
* param finalSampleRate 最终采样率
**********************************/
private MutationDTO getMutationValue(List<List<Float>> 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<Float> 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<Float> 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<Float> 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<List<Float>> 返回暂降数据
**********************************/
private List<EigenvalueDTO> getEventValue(List<List<Float>> lstWave, MutationDTO mutationDTO, ComtradeCfgDTO comtradeCfgDTO, boolean blType) {
List<List<Float>> tblWave = mutationDTO.getListTBL_Offline();
List<List<Float>> rmstWave = mutationDTO.getListRms_Offline();
//额定电压
float fBase = 57.74f;
//假如所选的是380V那么PT变比是1:1因此额定电压要选220 //模拟量通道记录
List<AnalogDTO> 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<EigenvalueDTO> 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 类别 0A相1B相2C相
* @param blFlag 浮动门槛和固定门槛
*************************************/
private int App_Disturb_DDY1(List<List<Float>> realWave, List<List<Float>> tblWave, List<List<Float>> 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 类别 0A相1B相2C相
* @param blFlag 浮动门槛和固定门槛
* @return
*************************************/
private int App_Disturb_GDY1(List<List<Float>> realWave, List<List<Float>> tblWave, List<List<Float>> 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<String>返回数据格式说明
**********************************/
private void getWaveTitle(WaveDataDTO waveDataDTO, ComtradeCfgDTO comtradeCfgDTO) {
//编辑数据标题 YXB2020-10-09 去除相别为N相的数据//存储数据标题
List<String> tmpWaveTitle = new ArrayList<>();
List<String> channelName = new ArrayList<>();
// 模拟量通道记录类
AnalogDTO analogDTO;
tmpWaveTitle.add("Time");
channelName.add("/");
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() + "");
channelName.add(analogDTO.getSzChannleName());
}
}
waveDataDTO.setWaveTitle(tmpWaveTitle);
waveDataDTO.setChannelNames(channelName);
}
/*********************************
* 由.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("F:\\PQ_PQLD3_9_20250821_081038_640.cfg");
InputStream datStream = waveFileComponent.getFileInputStreamByFilePath("F:\\PQ_PQLD3_9_20250821_081038_640.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<EigenvalueDTO> lstEigenvalueDTO = waveFileComponent.getEigenvalue(waveDataDTO, true);
System.out.println(1);
}
}