feat(wave-tool): 添加波形解析结果统计信息并优化数值精度
- 在 WaveComtradeResultVO 中新增 totalChannels、phaseCount 和 unit 字段用于展示统计信息 - 实现波形时间和幅值的小数位统一保留 3 位精度处理 - 添加了对 COMTRADE 配置文件中的变比进行优先使用的逻辑 - 实现了波形单位识别逻辑,支持 kV/A、kV、A 等单位显示 - 更新了文档中关于 PT/CT 变比的说明,明确优先使用 cfg 模拟量通道的变比 - 添加 spring-boot-starter-test 依赖以支持测试功能
This commit is contained in:
@@ -111,9 +111,9 @@ wave-tool/
|
|||||||
- `1`: 三角
|
- `1`: 三角
|
||||||
- `2`: 开口三角
|
- `2`: 开口三角
|
||||||
- `pt`
|
- `pt`
|
||||||
- PT 变比
|
- PT 变比,优先使用 `cfg` 模拟量通道的一次/二次变比;`cfg` 无有效变比时使用该参数
|
||||||
- `ct`
|
- `ct`
|
||||||
- CT 变比
|
- CT 变比,优先使用 `cfg` 模拟量通道的一次/二次变比;`cfg` 无有效变比时使用该参数
|
||||||
- `monitorName`
|
- `monitorName`
|
||||||
- 测点名称
|
- 测点名称
|
||||||
- `calculateRms`
|
- `calculateRms`
|
||||||
|
|||||||
@@ -24,5 +24,11 @@
|
|||||||
<artifactId>spingboot2.3.12</artifactId>
|
<artifactId>spingboot2.3.12</artifactId>
|
||||||
<version>2.3.12</version>
|
<version>2.3.12</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -543,13 +545,13 @@ public class WaveFileComponent {
|
|||||||
if (!blxValue && j == 0) {
|
if (!blxValue && j == 0) {
|
||||||
xValueAll = (float) (currentDataIndex * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
|
xValueAll = (float) (currentDataIndex * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
|
||||||
blxValue = true;
|
blxValue = true;
|
||||||
tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
|
tmpWaveData.add(roundWaveTime(xValueAll));
|
||||||
} else if (j == 0) {
|
} else if (j == 0) {
|
||||||
xValueAll += (float) dfValue / nWaveSpan;
|
xValueAll += (float) dfValue / nWaveSpan;
|
||||||
tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
|
tmpWaveData.add(roundWaveTime(xValueAll));
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpWaveData.add((float) (Math.round(fValue * 100)) / 100);
|
tmpWaveData.add(roundWaveAmplitude(fValue));
|
||||||
}
|
}
|
||||||
listWaveData.add(tmpWaveData);
|
listWaveData.add(tmpWaveData);
|
||||||
}
|
}
|
||||||
@@ -598,13 +600,13 @@ public class WaveFileComponent {
|
|||||||
if (!blxValue && j == 0) {
|
if (!blxValue && j == 0) {
|
||||||
xValueAll = (float) (i * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
|
xValueAll = (float) (i * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
|
||||||
blxValue = true;
|
blxValue = true;
|
||||||
tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
|
tmpWaveData.add(roundWaveTime(xValueAll));
|
||||||
} else if (j == 0) {
|
} else if (j == 0) {
|
||||||
xValueAll += (float) nWaveSpan * dfValue;
|
xValueAll += (float) nWaveSpan * dfValue;
|
||||||
tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
|
tmpWaveData.add(roundWaveTime(xValueAll));
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpWaveData.add((float) (Math.round(fValue * 100)) / 100);
|
tmpWaveData.add(roundWaveAmplitude(fValue));
|
||||||
}
|
}
|
||||||
listWaveData.add(tmpWaveData);
|
listWaveData.add(tmpWaveData);
|
||||||
}
|
}
|
||||||
@@ -632,6 +634,20 @@ public class WaveFileComponent {
|
|||||||
return listWaveData;
|
return listWaveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 波形时间统一保留 3 位小数。
|
||||||
|
*/
|
||||||
|
static Float roundWaveTime(float value) {
|
||||||
|
return BigDecimal.valueOf(value).setScale(3, RoundingMode.HALF_UP).floatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 波形幅值统一保留 3 位小数。
|
||||||
|
*/
|
||||||
|
static Float roundWaveAmplitude(float value) {
|
||||||
|
return BigDecimal.valueOf(value).setScale(3, RoundingMode.HALF_UP).floatValue();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组装 DAT 解析上下文,便于日志直接定位 cfg/dat 是否匹配。
|
* 组装 DAT 解析上下文,便于日志直接定位 cfg/dat 是否匹配。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ public class WaveComtradeParseParam {
|
|||||||
private Integer ptType = 0;
|
private Integer ptType = 0;
|
||||||
|
|
||||||
/** PT 变比。 */
|
/** PT 变比。 */
|
||||||
@ApiModelProperty(value = "PT 变比,默认 1")
|
@ApiModelProperty(value = "PT 变比,cfg 无有效变比时使用,默认 1")
|
||||||
private Double pt = 1D;
|
private Double pt = 1D;
|
||||||
|
|
||||||
/** CT 变比。 */
|
/** CT 变比。 */
|
||||||
@ApiModelProperty(value = "CT 变比,默认 1")
|
@ApiModelProperty(value = "CT 变比,cfg 无有效变比时使用,默认 1")
|
||||||
private Double ct = 1D;
|
private Double ct = 1D;
|
||||||
|
|
||||||
/** 测点名称。 */
|
/** 测点名称。 */
|
||||||
|
|||||||
@@ -16,6 +16,18 @@ import java.util.List;
|
|||||||
@ApiModel("COMTRADE 波形解析结果")
|
@ApiModel("COMTRADE 波形解析结果")
|
||||||
public class WaveComtradeResultVO {
|
public class WaveComtradeResultVO {
|
||||||
|
|
||||||
|
/** 通道总数。 */
|
||||||
|
@ApiModelProperty("通道总数")
|
||||||
|
private Integer totalChannels;
|
||||||
|
|
||||||
|
/** 相别数量。 */
|
||||||
|
@ApiModelProperty("相别数量")
|
||||||
|
private Integer phaseCount;
|
||||||
|
|
||||||
|
/** 波形单位,电压/电流混合时返回 kV/A。 */
|
||||||
|
@ApiModelProperty("波形单位")
|
||||||
|
private String unit;
|
||||||
|
|
||||||
/** 波形基础数据。 */
|
/** 波形基础数据。 */
|
||||||
@ApiModelProperty("波形基础数据")
|
@ApiModelProperty("波形基础数据")
|
||||||
private WaveDataDTO waveData;
|
private WaveDataDTO waveData;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import com.njcn.common.pojo.exception.BusinessException;
|
|||||||
import com.njcn.gather.tool.wave.component.WaveFileComponent;
|
import com.njcn.gather.tool.wave.component.WaveFileComponent;
|
||||||
import com.njcn.gather.tool.wave.component.WaveVectorComponent;
|
import com.njcn.gather.tool.wave.component.WaveVectorComponent;
|
||||||
import com.njcn.gather.tool.wave.pojo.bo.WaveDataDetail;
|
import com.njcn.gather.tool.wave.pojo.bo.WaveDataDetail;
|
||||||
|
import com.njcn.gather.tool.wave.pojo.dto.AnalogDTO;
|
||||||
|
import com.njcn.gather.tool.wave.pojo.dto.ComtradeCfgDTO;
|
||||||
import com.njcn.gather.tool.wave.pojo.dto.EigenvalueDTO;
|
import com.njcn.gather.tool.wave.pojo.dto.EigenvalueDTO;
|
||||||
import com.njcn.gather.tool.wave.pojo.dto.WaveDataDTO;
|
import com.njcn.gather.tool.wave.pojo.dto.WaveDataDTO;
|
||||||
import com.njcn.gather.tool.wave.pojo.dto.WaveVectorGroupDTO;
|
import com.njcn.gather.tool.wave.pojo.dto.WaveVectorGroupDTO;
|
||||||
@@ -124,6 +126,7 @@ public class WaveServiceImpl implements WaveService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WaveComtradeResultVO result = new WaveComtradeResultVO();
|
WaveComtradeResultVO result = new WaveComtradeResultVO();
|
||||||
|
fillComtradeSummary(result, waveDataDTO);
|
||||||
result.setWaveData(waveDataDTO);
|
result.setWaveData(waveDataDTO);
|
||||||
if (buildDetails) {
|
if (buildDetails) {
|
||||||
List<WaveDataDetail> waveDataDetails = WaveUtil.filterWaveData(waveDataDTO);
|
List<WaveDataDetail> waveDataDetails = WaveUtil.filterWaveData(waveDataDTO);
|
||||||
@@ -145,6 +148,66 @@ public class WaveServiceImpl implements WaveService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillComtradeSummary(WaveComtradeResultVO result, WaveDataDTO waveDataDTO) {
|
||||||
|
if (result == null || waveDataDTO == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComtradeCfgDTO cfgDTO = waveDataDTO.getComtradeCfgDTO();
|
||||||
|
if (cfgDTO != null) {
|
||||||
|
result.setTotalChannels(cfgDTO.getNChannelNum());
|
||||||
|
}
|
||||||
|
result.setPhaseCount(resolvePhaseCount(waveDataDTO, cfgDTO));
|
||||||
|
result.setUnit(resolveDisplayUnit(waveDataDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer resolvePhaseCount(WaveDataDTO waveDataDTO, ComtradeCfgDTO cfgDTO) {
|
||||||
|
if (waveDataDTO.getIPhasic() != null) {
|
||||||
|
return waveDataDTO.getIPhasic();
|
||||||
|
}
|
||||||
|
return cfgDTO == null ? null : cfgDTO.getNPhasic();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveDisplayUnit(WaveDataDTO waveDataDTO) {
|
||||||
|
boolean hasVoltage = false;
|
||||||
|
boolean hasCurrent = false;
|
||||||
|
ComtradeCfgDTO cfgDTO = waveDataDTO.getComtradeCfgDTO();
|
||||||
|
if (cfgDTO != null && cfgDTO.getLstAnalogDTO() != null) {
|
||||||
|
for (AnalogDTO analogDTO : cfgDTO.getLstAnalogDTO()) {
|
||||||
|
if (analogDTO == null || StrUtil.isBlank(analogDTO.getSzUnitName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isVoltageChannel(analogDTO)) {
|
||||||
|
hasVoltage = true;
|
||||||
|
} else {
|
||||||
|
hasCurrent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasVoltage && !hasCurrent && waveDataDTO.getWaveTitle() != null) {
|
||||||
|
for (String title : waveDataDTO.getWaveTitle()) {
|
||||||
|
if (StrUtil.isBlank(title) || "x".equalsIgnoreCase(title)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (title.substring(0, 1).equalsIgnoreCase("U")) {
|
||||||
|
hasVoltage = true;
|
||||||
|
} else {
|
||||||
|
hasCurrent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasVoltage && hasCurrent) {
|
||||||
|
return "kV/A";
|
||||||
|
}
|
||||||
|
if (hasVoltage) {
|
||||||
|
return "kV";
|
||||||
|
}
|
||||||
|
if (hasCurrent) {
|
||||||
|
return "A";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WaveComtradeVectorResultVO parseComtradeVector(InputStream cfgStream, InputStream datStream, WaveComtradeParseParam param) {
|
public WaveComtradeVectorResultVO parseComtradeVector(InputStream cfgStream, InputStream datStream, WaveComtradeParseParam param) {
|
||||||
if (cfgStream == null || datStream == null) {
|
if (cfgStream == null || datStream == null) {
|
||||||
@@ -180,12 +243,39 @@ public class WaveServiceImpl implements WaveService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void applyWaveMetadata(WaveDataDTO waveDataDTO, WaveComtradeParseParam param) {
|
private void applyWaveMetadata(WaveDataDTO waveDataDTO, WaveComtradeParseParam param) {
|
||||||
waveDataDTO.setPt(defaultIfNull(param.getPt(), DEFAULT_RATIO));
|
waveDataDTO.setPt(resolveCfgRatio(waveDataDTO, true, defaultIfNull(param.getPt(), DEFAULT_RATIO)));
|
||||||
waveDataDTO.setCt(defaultIfNull(param.getCt(), DEFAULT_RATIO));
|
waveDataDTO.setCt(resolveCfgRatio(waveDataDTO, false, defaultIfNull(param.getCt(), DEFAULT_RATIO)));
|
||||||
waveDataDTO.setPtType(param.getPtType() == null ? DEFAULT_PT_TYPE : param.getPtType());
|
waveDataDTO.setPtType(param.getPtType() == null ? DEFAULT_PT_TYPE : param.getPtType());
|
||||||
waveDataDTO.setMonitorName(StrUtil.blankToDefault(param.getMonitorName(), "未命名测点"));
|
waveDataDTO.setMonitorName(StrUtil.blankToDefault(param.getMonitorName(), "未命名测点"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double resolveCfgRatio(WaveDataDTO waveDataDTO, boolean voltage, double fallbackRatio) {
|
||||||
|
if (waveDataDTO == null || waveDataDTO.getComtradeCfgDTO() == null
|
||||||
|
|| waveDataDTO.getComtradeCfgDTO().getLstAnalogDTO() == null) {
|
||||||
|
return fallbackRatio;
|
||||||
|
}
|
||||||
|
for (AnalogDTO analogDTO : waveDataDTO.getComtradeCfgDTO().getLstAnalogDTO()) {
|
||||||
|
if (!hasValidCfgRatio(analogDTO) || isVoltageChannel(analogDTO) != voltage) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// cfg 模拟量通道的 primary/secondary 是变比权威来源。
|
||||||
|
return analogDTO.getFPrimary() / analogDTO.getFSecondary();
|
||||||
|
}
|
||||||
|
return fallbackRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasValidCfgRatio(AnalogDTO analogDTO) {
|
||||||
|
return analogDTO != null
|
||||||
|
&& analogDTO.getFPrimary() != null
|
||||||
|
&& analogDTO.getFSecondary() != null
|
||||||
|
&& analogDTO.getFPrimary() > 0
|
||||||
|
&& analogDTO.getFSecondary() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isVoltageChannel(AnalogDTO analogDTO) {
|
||||||
|
return !StrUtil.equalsIgnoreCase(analogDTO.getSzUnitName(), "A");
|
||||||
|
}
|
||||||
|
|
||||||
private boolean shouldCalculateRms(WaveComtradeParseParam param) {
|
private boolean shouldCalculateRms(WaveComtradeParseParam param) {
|
||||||
return param.getCalculateRms() == null || param.getCalculateRms();
|
return param.getCalculateRms() == null || param.getCalculateRms();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user