diff --git a/src/main/java/com/xujie/sys/common/utils/ModbusUtils.java b/src/main/java/com/xujie/sys/common/utils/ModbusUtils.java index 869d7f92..d4621ef5 100644 --- a/src/main/java/com/xujie/sys/common/utils/ModbusUtils.java +++ b/src/main/java/com/xujie/sys/common/utils/ModbusUtils.java @@ -7,6 +7,7 @@ import com.ghgande.j2mod.modbus.util.BitVector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @@ -17,13 +18,66 @@ public class ModbusUtils { private static final int MODBUS_TCP_TIMEOUT_MS = 20000; /** - * - * @param highRegister 高 16 位所在寄存器的 {@code getValue()} - * @param lowRegister 低 16 位所在寄存器的 {@code getValue()} + * 与 {@code ModbusCommunicateServiceImpl#getResponseMessage} 一致:首寄存器为高 16 位,次寄存器为低 16 位。 */ + public static float registersToFloatHighWordFirst(int highRegister, int lowRegister) { + int highWord = highRegister & 0xFFFF; + int lowWord = lowRegister & 0xFFFF; + return Float.intBitsToFloat((highWord << 16) | lowWord); + } + + /** 低字在前:首寄存器为低 16 位,次寄存器为高 16 位(200 段常规采集) */ + public static float registersToFloatLowWordFirst(int lowRegister, int highRegister) { + return registersToFloatHighWordFirst(highRegister, lowRegister); + } + + /** 请使用 {@link #registersToFloatHighWordFirst} */ public static float holdingRegistersToFloatBigEndian(int highRegister, int lowRegister) { - int bits = (highRegister & 0xFFFF) << 16 | (lowRegister & 0xFFFF); - return Float.intBitsToFloat(bits); + return registersToFloatHighWordFirst(highRegister, lowRegister); + } + + /** + * 无工单异常区 float:同时按高字在前、低字在前各解析一次,取更合理的结果(避免 3.67E-41 等字序错误值)。 + */ + public static float parseAbnormalCollectorFloat(int regAtFirstAddr, int regAtSecondAddr) { + float highWordFirst = registersToFloatHighWordFirst(regAtFirstAddr, regAtSecondAddr); + float lowWordFirst = registersToFloatLowWordFirst(regAtFirstAddr, regAtSecondAddr); + return pickAbnormalFloatCandidate(highWordFirst, lowWordFirst); + } + + /** 入库/界面展示用,避免 {@code String.valueOf(float)} 出现 3.67E-41 等形式 */ + public static String formatFloatPlain(float value) { + if (Float.isNaN(value) || Float.isInfinite(value)) { + return "0"; + } + return BigDecimal.valueOf(value).stripTrailingZeros().toPlainString(); + } + + private static float pickAbnormalFloatCandidate(float highWordFirst, float lowWordFirst) { + int scoreHigh = scoreAbnormalFloat(highWordFirst); + int scoreLow = scoreAbnormalFloat(lowWordFirst); + if (scoreLow > scoreHigh) { + return lowWordFirst; + } + return highWordFirst; + } + + /** 值越大越可信:占位值 -99999.9 > 正常测量 > 0 > 字序错误的极小值 */ + private static int scoreAbnormalFloat(float value) { + if (Float.isNaN(value) || Float.isInfinite(value)) { + return -100; + } + if (value == 0f) { + return 0; + } + float abs = Math.abs(value); + if (abs >= 10000f) { + return 100; + } + if (abs >= 1e-6f) { + return 50; + } + return -100; } /** diff --git a/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java b/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java index ffdc9b3b..3f33f60b 100644 --- a/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java @@ -4964,15 +4964,15 @@ public class QcServiceImpl implements QcService { timeParts.add(timeValue == null ? 0 : (timeValue & 0xFFFF)); } - // 异常数据地址按32位float读取(高字在前):406/408/410/412/414 ... + // 异常 float:406/408…;按高/低字在前各解一次,取合理值(原 (high<<16)|low 仅适用于高字在前) List abnormalValues = new ArrayList<>(); for (int i = 0; i < 5; i++) { - int highRef = abnormalStartAddr + (i * 2); - int lowRef = highRef + 1; - Integer high = raw.get(highRef); - Integer low = raw.get(lowRef); - if (high != null && low != null) { - abnormalValues.add(ModbusUtils.holdingRegistersToFloatBigEndian(high, low)); + int regRef = abnormalStartAddr + (i * 2); + int regRefNext = regRef + 1; + Integer reg0 = raw.get(regRef); + Integer reg1 = raw.get(regRefNext); + if (reg0 != null && reg1 != null) { + abnormalValues.add(ModbusUtils.parseAbnormalCollectorFloat(reg0, reg1)); } else { abnormalValues.add(0F); } @@ -4997,7 +4997,7 @@ public class QcServiceImpl implements QcService { detailValues.setIsSubmit("N"); detailValues.setSite(data.getSite()); detailValues.setNum(1); - detailValues.setSubDetailValue(String.valueOf(abnormalValues.get(i))); + detailValues.setSubDetailValue(ModbusUtils.formatFloatPlain(abnormalValues.get(i))); detailValues.setSubDetailValueB(collectedTime); detailValues.setSamplingLocationB(collectedTime); subDetailValues.add(detailValues); @@ -5100,7 +5100,7 @@ public class QcServiceImpl implements QcService { Integer high = raw.get(highRef); Integer low = raw.get(lowRef); if (low != null && high != null) { - resultMap.put(String.valueOf(addr), ModbusUtils.holdingRegistersToFloatBigEndian(high, low)); + resultMap.put(String.valueOf(addr), ModbusUtils.registersToFloatHighWordFirst(high, low)); } } @@ -5189,7 +5189,7 @@ public class QcServiceImpl implements QcService { Integer low = raw.get(lowRef); Integer high = raw.get(highRef); if (low != null && high != null) { - resultMap.put(String.valueOf(addr), ModbusUtils.holdingRegistersToFloatBigEndian(high, low)); + resultMap.put(String.valueOf(addr), ModbusUtils.registersToFloatLowWordFirst(low, high)); } } @@ -5199,7 +5199,7 @@ public class QcServiceImpl implements QcService { Integer lowAvg = raw.get(lowRefAvg); Integer highAvg = raw.get(highRefAvg); if (lowAvg != null && highAvg != null) { - resultMap.put(String.valueOf(avgAddr), ModbusUtils.holdingRegistersToFloatBigEndian(highAvg, lowAvg)); + resultMap.put(String.valueOf(avgAddr), ModbusUtils.registersToFloatLowWordFirst(lowAvg, highAvg)); } return resultMap;