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`: 三角
|
||||
- `2`: 开口三角
|
||||
- `pt`
|
||||
- PT 变比
|
||||
- PT 变比,优先使用 `cfg` 模拟量通道的一次/二次变比;`cfg` 无有效变比时使用该参数
|
||||
- `ct`
|
||||
- CT 变比
|
||||
- CT 变比,优先使用 `cfg` 模拟量通道的一次/二次变比;`cfg` 无有效变比时使用该参数
|
||||
- `monitorName`
|
||||
- 测点名称
|
||||
- `calculateRms`
|
||||
|
||||
@@ -24,5 +24,11 @@
|
||||
<artifactId>spingboot2.3.12</artifactId>
|
||||
<version>2.3.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -14,6 +14,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
|
||||
@@ -543,13 +545,13 @@ public class WaveFileComponent {
|
||||
if (!blxValue && j == 0) {
|
||||
xValueAll = (float) (currentDataIndex * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
|
||||
blxValue = true;
|
||||
tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
|
||||
tmpWaveData.add(roundWaveTime(xValueAll));
|
||||
} else if (j == 0) {
|
||||
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);
|
||||
}
|
||||
@@ -598,13 +600,13 @@ public class WaveFileComponent {
|
||||
if (!blxValue && j == 0) {
|
||||
xValueAll = (float) (i * 20) / tmpRateDTO.getNOneSample() - comtradeCfgDTO.getNPush();
|
||||
blxValue = true;
|
||||
tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);
|
||||
tmpWaveData.add(roundWaveTime(xValueAll));
|
||||
} else if (j == 0) {
|
||||
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);
|
||||
}
|
||||
@@ -632,6 +634,20 @@ public class WaveFileComponent {
|
||||
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 是否匹配。
|
||||
*/
|
||||
|
||||
@@ -20,11 +20,11 @@ public class WaveComtradeParseParam {
|
||||
private Integer ptType = 0;
|
||||
|
||||
/** PT 变比。 */
|
||||
@ApiModelProperty(value = "PT 变比,默认 1")
|
||||
@ApiModelProperty(value = "PT 变比,cfg 无有效变比时使用,默认 1")
|
||||
private Double pt = 1D;
|
||||
|
||||
/** CT 变比。 */
|
||||
@ApiModelProperty(value = "CT 变比,默认 1")
|
||||
@ApiModelProperty(value = "CT 变比,cfg 无有效变比时使用,默认 1")
|
||||
private Double ct = 1D;
|
||||
|
||||
/** 测点名称。 */
|
||||
|
||||
@@ -16,6 +16,18 @@ import java.util.List;
|
||||
@ApiModel("COMTRADE 波形解析结果")
|
||||
public class WaveComtradeResultVO {
|
||||
|
||||
/** 通道总数。 */
|
||||
@ApiModelProperty("通道总数")
|
||||
private Integer totalChannels;
|
||||
|
||||
/** 相别数量。 */
|
||||
@ApiModelProperty("相别数量")
|
||||
private Integer phaseCount;
|
||||
|
||||
/** 波形单位,电压/电流混合时返回 kV/A。 */
|
||||
@ApiModelProperty("波形单位")
|
||||
private String unit;
|
||||
|
||||
/** 波形基础数据。 */
|
||||
@ApiModelProperty("波形基础数据")
|
||||
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.WaveVectorComponent;
|
||||
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.WaveDataDTO;
|
||||
import com.njcn.gather.tool.wave.pojo.dto.WaveVectorGroupDTO;
|
||||
@@ -124,6 +126,7 @@ public class WaveServiceImpl implements WaveService {
|
||||
}
|
||||
|
||||
WaveComtradeResultVO result = new WaveComtradeResultVO();
|
||||
fillComtradeSummary(result, waveDataDTO);
|
||||
result.setWaveData(waveDataDTO);
|
||||
if (buildDetails) {
|
||||
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
|
||||
public WaveComtradeVectorResultVO parseComtradeVector(InputStream cfgStream, InputStream datStream, WaveComtradeParseParam param) {
|
||||
if (cfgStream == null || datStream == null) {
|
||||
@@ -180,12 +243,39 @@ public class WaveServiceImpl implements WaveService {
|
||||
}
|
||||
|
||||
private void applyWaveMetadata(WaveDataDTO waveDataDTO, WaveComtradeParseParam param) {
|
||||
waveDataDTO.setPt(defaultIfNull(param.getPt(), DEFAULT_RATIO));
|
||||
waveDataDTO.setCt(defaultIfNull(param.getCt(), DEFAULT_RATIO));
|
||||
waveDataDTO.setPt(resolveCfgRatio(waveDataDTO, true, defaultIfNull(param.getPt(), DEFAULT_RATIO)));
|
||||
waveDataDTO.setCt(resolveCfgRatio(waveDataDTO, false, defaultIfNull(param.getCt(), DEFAULT_RATIO)));
|
||||
waveDataDTO.setPtType(param.getPtType() == null ? DEFAULT_PT_TYPE : param.getPtType());
|
||||
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) {
|
||||
return param.getCalculateRms() == null || param.getCalculateRms();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user