From b56116264c3ac301e9a8e973864e68501db1b2ce Mon Sep 17 00:00:00 2001 From: yexb <553699424@qq.com> Date: Mon, 11 May 2026 16:32:25 +0800 Subject: [PATCH] =?UTF-8?q?feat(wave-tool):=20=E6=B7=BB=E5=8A=A0=E6=B3=A2?= =?UTF-8?q?=E5=BD=A2=E8=A7=A3=E6=9E=90=E7=BB=93=E6=9E=9C=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=B9=B6=E4=BC=98=E5=8C=96=E6=95=B0=E5=80=BC?= =?UTF-8?q?=E7=B2=BE=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 WaveComtradeResultVO 中新增 totalChannels、phaseCount 和 unit 字段用于展示统计信息 - 实现波形时间和幅值的小数位统一保留 3 位精度处理 - 添加了对 COMTRADE 配置文件中的变比进行优先使用的逻辑 - 实现了波形单位识别逻辑,支持 kV/A、kV、A 等单位显示 - 更新了文档中关于 PT/CT 变比的说明,明确优先使用 cfg 模拟量通道的变比 - 添加 spring-boot-starter-test 依赖以支持测试功能 --- tools/wave-tool/README.md | 4 +- tools/wave-tool/pom.xml | 6 ++ .../wave/component/WaveFileComponent.java | 28 ++++-- .../pojo/param/WaveComtradeParseParam.java | 4 +- .../wave/pojo/vo/WaveComtradeResultVO.java | 12 +++ .../wave/service/impl/WaveServiceImpl.java | 94 ++++++++++++++++++- 6 files changed, 136 insertions(+), 12 deletions(-) diff --git a/tools/wave-tool/README.md b/tools/wave-tool/README.md index 5def628..1ce93e8 100644 --- a/tools/wave-tool/README.md +++ b/tools/wave-tool/README.md @@ -111,9 +111,9 @@ wave-tool/ - `1`: 三角 - `2`: 开口三角 - `pt` - - PT 变比 + - PT 变比,优先使用 `cfg` 模拟量通道的一次/二次变比;`cfg` 无有效变比时使用该参数 - `ct` - - CT 变比 + - CT 变比,优先使用 `cfg` 模拟量通道的一次/二次变比;`cfg` 无有效变比时使用该参数 - `monitorName` - 测点名称 - `calculateRms` diff --git a/tools/wave-tool/pom.xml b/tools/wave-tool/pom.xml index 4a8f6fe..a7ff2f4 100644 --- a/tools/wave-tool/pom.xml +++ b/tools/wave-tool/pom.xml @@ -24,5 +24,11 @@ spingboot2.3.12 2.3.12 + + + org.springframework.boot + spring-boot-starter-test + test + diff --git a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/component/WaveFileComponent.java b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/component/WaveFileComponent.java index bdc1c44..daa3495 100644 --- a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/component/WaveFileComponent.java +++ b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/component/WaveFileComponent.java @@ -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 是否匹配。 */ diff --git a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/pojo/param/WaveComtradeParseParam.java b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/pojo/param/WaveComtradeParseParam.java index d69c015..08149ef 100644 --- a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/pojo/param/WaveComtradeParseParam.java +++ b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/pojo/param/WaveComtradeParseParam.java @@ -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; /** 测点名称。 */ diff --git a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/pojo/vo/WaveComtradeResultVO.java b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/pojo/vo/WaveComtradeResultVO.java index 6d263f8..bf215b0 100644 --- a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/pojo/vo/WaveComtradeResultVO.java +++ b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/pojo/vo/WaveComtradeResultVO.java @@ -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; diff --git a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/impl/WaveServiceImpl.java b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/impl/WaveServiceImpl.java index 743e8cf..583158b 100644 --- a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/impl/WaveServiceImpl.java +++ b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/impl/WaveServiceImpl.java @@ -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 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(); }