diff --git a/tools/wave-comtrade/src/main/java/com/njcn/gather/tools/comtrade/comparewave/core/io/ComtradeReader.java b/tools/wave-comtrade/src/main/java/com/njcn/gather/tools/comtrade/comparewave/core/io/ComtradeReader.java index 9ab253d9..1da6726c 100644 --- a/tools/wave-comtrade/src/main/java/com/njcn/gather/tools/comtrade/comparewave/core/io/ComtradeReader.java +++ b/tools/wave-comtrade/src/main/java/com/njcn/gather/tools/comtrade/comparewave/core/io/ComtradeReader.java @@ -876,51 +876,37 @@ public class ComtradeReader { // 记录段的起始位置 dataBuf.getSegmentStartIndices()[seg] = sampleIndex; - // 只对超过512的段降采样到256 - float targetRate = segmentSamplesPerCycle; - int downsampleMod = 1; + // 记录段的原始采样率(不做降采样) + dataBuf.getSegmentSampleRates()[seg] = segmentSamplesPerCycle; - if (segmentSamplesPerCycle > 512) { - targetRate = 256; - downsampleMod = Math.round(segmentSamplesPerCycle / 256); - log.info("段{} - 原始: {}点/周波 > 512, 降采样到256, 模数: {}", - seg, segmentSamplesPerCycle, downsampleMod); - } else { - log.info("段{} - 原始: {}点/周波, 保持不变", - seg, segmentSamplesPerCycle); - } + log.info("段{} - 原始: {}点/周波, 保留原始数据", + seg, segmentSamplesPerCycle); - // 记录段的采样率(降采样后的) - dataBuf.getSegmentSampleRates()[seg] = targetRate; - - // 读取当前段的数据 + // 读取当前段的所有数据(不降采样) for (int i = 0; i < segmentSamples; i++) { int bytesRead = dis.read(buffer, 0, recordSize); if (bytesRead != recordSize) { break; } - // 降采样(仅当>512时) - if (i % downsampleMod == 0) { - ByteBuffer bb = ByteBuffer.wrap(buffer); - bb.order(ByteOrder.LITTLE_ENDIAN); + ByteBuffer bb = ByteBuffer.wrap(buffer); + bb.order(ByteOrder.LITTLE_ENDIAN); - bb.getInt(); // 序号 - bb.getInt(); // 时间戳 + bb.getInt(); // 序号 + bb.getInt(); // 时间戳 - // 读取模拟通道数据 - for (int ch = 0; ch < cfgInfo.getAnalogChannels() && ch < MAX_CH_NUM; ch++) { - short rawValue = bb.getShort(); - dataBuf.getSmpData()[ch][sampleIndex] = rawValue; - } - sampleIndex++; + // 读取模拟通道数据 + for (int ch = 0; ch < cfgInfo.getAnalogChannels() && ch < MAX_CH_NUM; ch++) { + short rawValue = bb.getShort(); + dataBuf.getSmpData()[ch][sampleIndex] = rawValue; } + sampleIndex++; } log.info("段{} 完成 - 起始索引: {}, 输出采样点: {}, 采样率: {}点/周波", seg, dataBuf.getSegmentStartIndices()[seg], sampleIndex - dataBuf.getSegmentStartIndices()[seg], - targetRate); + segmentSamplesPerCycle); } log.info("=== 多段数据处理完成 - 总采样点: {} ===", sampleIndex); @@ -931,15 +917,11 @@ public class ComtradeReader { dataBuf.getSegmentStartIndices()[0] = 0; float samplesPerCycle = (float) cfgInfo.getSampleRate() / lineFreq; - float targetRate = samplesPerCycle; - int downsampleMod = 1; - if (samplesPerCycle > 512) { - targetRate = 256; - downsampleMod = Math.round(samplesPerCycle / 256); - } + // 记录原始采样率(不降采样) + dataBuf.getSegmentSampleRates()[0] = samplesPerCycle; - dataBuf.getSegmentSampleRates()[0] = targetRate; + log.info("单段数据 - 原始: {}点/周波, 保留原始数据", samplesPerCycle); int totalSamples = cfgInfo.getTotalSamples(); for (int i = 0; i < totalSamples; i++) { @@ -948,22 +930,20 @@ public class ComtradeReader { break; } - if (i % downsampleMod == 0) { - ByteBuffer bb = ByteBuffer.wrap(buffer); - bb.order(ByteOrder.LITTLE_ENDIAN); + ByteBuffer bb = ByteBuffer.wrap(buffer); + bb.order(ByteOrder.LITTLE_ENDIAN); - bb.getInt(); - bb.getInt(); + bb.getInt(); + bb.getInt(); - for (int ch = 0; ch < cfgInfo.getAnalogChannels() && ch < MAX_CH_NUM; ch++) { - short rawValue = bb.getShort(); - dataBuf.getSmpData()[ch][sampleIndex] = rawValue; - } - sampleIndex++; + for (int ch = 0; ch < cfgInfo.getAnalogChannels() && ch < MAX_CH_NUM; ch++) { + short rawValue = bb.getShort(); + dataBuf.getSmpData()[ch][sampleIndex] = rawValue; } + sampleIndex++; } - log.info("单段数据处理完成 - 采样点: {}, 采样率: {}点/周波", sampleIndex, targetRate); + log.info("单段数据处理完成 - 采样点: {}, 采样率: {}点/周波", sampleIndex, samplesPerCycle); } } diff --git a/tools/wave-comtrade/src/main/java/com/njcn/gather/tools/comtrade/comparewave/service/impl/CompareWaveServiceImpl.java b/tools/wave-comtrade/src/main/java/com/njcn/gather/tools/comtrade/comparewave/service/impl/CompareWaveServiceImpl.java index 7f2951c2..e398f7da 100644 --- a/tools/wave-comtrade/src/main/java/com/njcn/gather/tools/comtrade/comparewave/service/impl/CompareWaveServiceImpl.java +++ b/tools/wave-comtrade/src/main/java/com/njcn/gather/tools/comtrade/comparewave/service/impl/CompareWaveServiceImpl.java @@ -17,6 +17,8 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import static com.njcn.gather.tools.comtrade.comparewave.core.Constants.MAX_CH_NUM; + /** * 波形比对分析服务实现类 * @@ -418,6 +420,20 @@ public class CompareWaveServiceImpl implements ICompareWaveService { break; } + // 检查采样率是否过低(< 128) + boolean sourceLowSampleRate = (sourceSampleRate < 128); + boolean targetLowSampleRate = (targetSampleRate < 128); + + if (sourceLowSampleRate || targetLowSampleRate) { + log.warn("窗口 {} - 采样率过低(源文件: {}点/周波, 目标文件: {}点/周波, 最小要求128),该窗口被丢弃", + window, sourceSampleRate, targetSampleRate); + + // 推进位置到下一个窗口 + sourceCurrentPos = sourceWindowEnd; + targetCurrentPos = targetWindowEnd; + continue; + } + // 判断源文件窗口是否跨段 int sourceEndSegment = findSegmentIndex(sourceDataBuf, sourceWindowEnd - 1); boolean sourceCrossSegment = (sourceSegment != sourceEndSegment); @@ -429,12 +445,14 @@ public class CompareWaveServiceImpl implements ICompareWaveService { // 如果任一文件跨段,两个文件都丢弃该窗口 if (sourceCrossSegment || targetCrossSegment) { if (sourceCrossSegment) { - log.warn("窗口 {} - 源文件跨段(段{} -> 段{}),该窗口被丢弃", - window, sourceSegment, sourceEndSegment); + float sourceEndSampleRate = sourceDataBuf.getSegmentSampleRates()[sourceEndSegment]; + log.warn("窗口 {} - 源文件跨段(段{}/{}点/周波 -> 段{}/{}点/周波),该窗口被丢弃", + window, sourceSegment, sourceSampleRate, sourceEndSegment, sourceEndSampleRate); } if (targetCrossSegment) { - log.warn("窗口 {} - 目标文件跨段(段{} -> 段{}),该窗口被丢弃", - window, targetSegment, targetEndSegment); + float targetEndSampleRate = targetDataBuf.getSegmentSampleRates()[targetEndSegment]; + log.warn("窗口 {} - 目标文件跨段(段{}/{}点/周波 -> 段{}/{}点/周波),该窗口被丢弃", + window, targetSegment, targetSampleRate, targetEndSegment, targetEndSampleRate); } // 推进位置到下一个窗口 @@ -449,24 +467,16 @@ public class CompareWaveServiceImpl implements ICompareWaveService { ClockStruct sourceDataTime = calculateWindowTime(sourceStartTime, window); ClockStruct targetDataTime = calculateWindowTime(targetStartTime, window); - // 计算源文件窗口 - float sourceOriginalRate = sourceDataBuf.getSmpRate(); - sourceDataBuf.setSmpRate(sourceSampleRate); - sourceDataBuf.setDataPoint(validWindowCount); - PowerQualityCalculator.pqs200msDataCal(sourceDataBuf, sourceDataTime, sourceWindowEnd); - sourceDataBuf.setSmpRate(sourceOriginalRate); - - PqsDataStruct sourceResult = sourceDataBuf.getPqData()[validWindowCount]; + // 计算源文件窗口(如果采样率>512,降采样到256) + PqsDataStruct sourceResult = calculateWindowWithDownsampling( + sourceDataBuf, sourceCurrentPos, sourceWindowEnd, + sourceSampleRate, sourceDataTime, validWindowCount); sourceResults.add(sourceResult); - // 计算目标文件窗口 - float targetOriginalRate = targetDataBuf.getSmpRate(); - targetDataBuf.setSmpRate(targetSampleRate); - targetDataBuf.setDataPoint(validWindowCount); - PowerQualityCalculator.pqs200msDataCal(targetDataBuf, targetDataTime, targetWindowEnd); - targetDataBuf.setSmpRate(targetOriginalRate); - - PqsDataStruct targetResult = targetDataBuf.getPqData()[validWindowCount]; + // 计算目标文件窗口(如果采样率>512,降采样到256) + PqsDataStruct targetResult = calculateWindowWithDownsampling( + targetDataBuf, targetCurrentPos, targetWindowEnd, + targetSampleRate, targetDataTime, validWindowCount); targetResults.add(targetResult); log.info("有效窗口 {} (总窗口{}) - 源文件段{}/{}点, 目标文件段{}/{}点, UA: {}/{}, IA: {}/{}", @@ -501,6 +511,81 @@ public class CompareWaveServiceImpl implements ICompareWaveService { compareWaveDTO.setTargetResults(targetResults); } + /** + * 计算窗口电能质量参数(如果采样率>512,降采样到256) + * + * @param dataBuf 数据缓冲区 + * @param windowStart 窗口起始位置 + * @param windowEnd 窗口结束位置 + * @param sampleRate 窗口采样率(点/周波) + * @param dataTime 时间戳 + * @param windowIndex 窗口索引 + * @return 计算结果 + */ + private PqsDataStruct calculateWindowWithDownsampling( + DataPq dataBuf, int windowStart, int windowEnd, + float sampleRate, ClockStruct dataTime, int windowIndex) { + + float originalRate = dataBuf.getSmpRate(); + int originalDataPoint = dataBuf.getDataPoint(); + + try { + // 判断是否需要降采样 + if (sampleRate > 512) { + // 需要降采样到256 + int downsampleMod = Math.round(sampleRate / 256); + float targetRate = 256; + int windowSamples = windowEnd - windowStart; + int downsampledSamples = (windowSamples + downsampleMod - 1) / downsampleMod; + + log.debug("窗口{}降采样: {}点/周波 -> 256点/周波, 模数: {}, 原始{}点 -> {}点", + windowIndex, sampleRate, downsampleMod, windowSamples, downsampledSamples); + + // 备份原始数据 + int[][] backup = new int[MAX_CH_NUM][windowSamples]; + for (int ch = 0; ch < MAX_CH_NUM; ch++) { + System.arraycopy(dataBuf.getSmpData()[ch], windowStart, backup[ch], 0, windowSamples); + } + + // 降采样:每downsampleMod个点取1个 + int downsampledIndex = 0; + for (int i = 0; i < windowSamples; i += downsampleMod) { + for (int ch = 0; ch < MAX_CH_NUM; ch++) { + dataBuf.getSmpData()[ch][windowStart + downsampledIndex] = + dataBuf.getSmpData()[ch][windowStart + i]; + } + downsampledIndex++; + } + + // 设置降采样后的采样率和窗口结束位置 + dataBuf.setSmpRate(targetRate); + dataBuf.setDataPoint(windowIndex); + int downsampledWindowEnd = windowStart + downsampledSamples; + + // 计算电能质量参数 + PowerQualityCalculator.pqs200msDataCal(dataBuf, dataTime, downsampledWindowEnd); + + // 恢复原始数据 + for (int ch = 0; ch < MAX_CH_NUM; ch++) { + System.arraycopy(backup[ch], 0, dataBuf.getSmpData()[ch], windowStart, windowSamples); + } + + } else { + // 不需要降采样,直接计算 + dataBuf.setSmpRate(sampleRate); + dataBuf.setDataPoint(windowIndex); + PowerQualityCalculator.pqs200msDataCal(dataBuf, dataTime, windowEnd); + } + + return dataBuf.getPqData()[windowIndex]; + + } finally { + // 恢复原始设置 + dataBuf.setSmpRate(originalRate); + dataBuf.setDataPoint(originalDataPoint); + } + } + /** * 计算窗口的时间戳 */