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();
}