From 855c8d98d631b0f4660ea7d2e7351d4d820f4610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E6=9C=A8c?= <857448963@qq.com> Date: Thu, 10 Aug 2023 16:30:01 +0800 Subject: [PATCH] =?UTF-8?q?=E9=AB=98=E7=BA=A7=E7=AE=97=E6=B3=95=E7=89=B9?= =?UTF-8?q?=E5=BE=81=E5=80=BC=EF=BC=8C=E6=9A=82=E9=99=8D=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E8=8C=83=E5=9B=B4=E5=88=86=E6=9E=90=E4=BB=A3=E7=A0=81=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pqs-advance/advance-api/pom.xml | 6 + .../advance/enums/AdvanceResponseEnum.java | 4 +- .../java/com/njcn/advance/enums/EnumEvt.java | 99 ++ .../com/njcn/advance/pojo/bo/FinalData.java | 38 - .../com/njcn/advance/pojo/bo/QtIdxArray.java | 3 +- .../njcn/advance/pojo/bo/QvvrDataStruct.java | 1 + .../com/njcn/advance/pojo/bo/ZtpgSin.java | 1 + .../njcn/advance/pojo/dto/BalanceInfo.java | 1 + .../pojo/dto/relevent/EntityGroupData.java | 43 + .../pojo/dto/relevent/EntityGroupEvtData.java | 53 + .../pojo/dto/relevent/EntityLogic.java | 21 + .../pojo/dto/relevent/EntityMtrans.java | 71 + .../pojo/dto/relevent/EventAssObj.java | 123 ++ .../advance/pojo/dto/relevent/FinalData.java | 25 + .../advance/pojo/dto/relevent/PlantInfo.java | 32 + .../pojo/dto/{ => relevent}/QtIdx.java | 2 +- .../advance/pojo/dto/relevent/SagEvent.java | 423 ++++++ .../pojo/dto/waveAnalysis/AnalyWave.java | 1152 +++++++++++++++++ .../pojo/dto/waveAnalysis/AnalyWaveModel.java | 200 +++ .../pojo/dto/waveAnalysis/BackData.java | 94 ++ .../pojo/dto/waveAnalysis/CauseStruct.java | 30 + .../pojo/dto/waveAnalysis/DirectionData.java | 47 + .../dto/waveAnalysis/EntityAdvancedData.java | 39 + .../pojo/dto/waveAnalysis/PowerData.java | 27 + .../pojo/dto/waveAnalysis/PubWaveModel.java | 168 +++ .../advance/pojo/dto/waveAnalysis/Rect.java | 42 + .../pojo/dto/waveAnalysis/UtblData.java | 13 + .../pojo/dto/waveAnalysis/WaveData.java | 296 +++++ .../njcn/advance/pojo/po/PqsRelevanceLog.java | 33 + .../com/njcn/advance/utils/WaveUtils.java | 49 + pqs-advance/advance-boot/pom.xml | 7 +- .../EventRelevantAnalysisController.java | 74 ++ .../EventWaveAnalysisController.java | 48 + .../njcn/advance/mapper/RelevantMapper.java | 26 + .../advance/mapper/RmpEventAdvanceMapper.java | 21 + .../mapper/RmpEventDetailAssMapper.java | 23 + .../mapping/EventWaveAnalysisMapper.xml | 9 + .../advance/mapper/mapping/RelevantMapper.xml | 22 + .../mapping/RmpEventDetailAssMapper.xml | 24 + .../njcn/advance/service/BalanceService.java | 4 +- .../service/EventRelevantAnalysisService.java | 30 + .../service/EventWaveAnalysisService.java | 14 + .../service/impl/BalanceServiceImpl.java | 8 +- .../EventRelevantAnalysisServiceImpl.java | 475 +++++++ .../impl/EventWaveAnalysisServiceImpl.java | 828 ++++++++++++ .../njcn/advance/utils/GetBalanceUtils.java | 6 +- .../njcn/advance/utils/JnaCallBalance.java | 20 + .../njcn/advance/utils/JnaCallDllOrSo.java | 1 - .../njcn/advance/utils/UtilNormalization.java | 382 ++++++ .../java/com/njcn/advance/utils/Utils.java | 102 ++ .../com/njcn/advance/utils/qvvr_balance.dll | Bin 335479 -> 0 bytes ...bqvvr_pg_dll.so => libqvvr_balance_dll.so} | Bin .../java/com/njcn/common/utils/PubUtils.java | 26 + .../biz/commApi/CommLedgerDeptClient.java | 2 +- .../pq/api/GeneralDeviceInfoClient.java | 4 +- .../njcn/device/pq/api/TransformerClient.java | 28 + .../TransformerClientFallbackFactory.java | 45 + .../pojo/dto/transformer/EntityLogicDTO.java | 26 + .../controller/PqsTransformerController.java | 11 + .../device/pq/mapper/PqsTflgassMapper.java | 6 + .../pq/mapper/mapping/PqsTflgassMapper.xml | 14 + .../pq/service/IPqsTransformerService.java | 8 + .../impl/PqsTransformerServiceImpl.java | 8 + .../event/api/RmpEventDetailFeignClient.java | 44 + ...EventDetailFeignClientFallbackFactory.java | 46 + .../event/pojo/po/RmpEventDetailAssPO.java | 41 + .../njcn/event/pojo/po/RmpEventDetailPO.java | 1 + .../event/pojo/vo/AdvanceEventDetailVO.java | 110 ++ .../AdvancedAnalysisController.java | 21 - .../RmpEventDetailController.java | 37 + .../Impl/RmpEventDetailServiceImpl.java | 101 +- .../majornetwork/RmpEventDetailService.java | 13 + .../njcn/system/enums/SystemResponseEnum.java | 2 +- 73 files changed, 5766 insertions(+), 88 deletions(-) create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/enums/EnumEvt.java delete mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/FinalData.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityGroupData.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityGroupEvtData.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityLogic.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityMtrans.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EventAssObj.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/FinalData.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/PlantInfo.java rename pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/{ => relevent}/QtIdx.java (94%) create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/SagEvent.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/AnalyWave.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/AnalyWaveModel.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/BackData.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/CauseStruct.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/DirectionData.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/EntityAdvancedData.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/PowerData.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/PubWaveModel.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/Rect.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/UtblData.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/WaveData.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/po/PqsRelevanceLog.java create mode 100644 pqs-advance/advance-api/src/main/java/com/njcn/advance/utils/WaveUtils.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/controller/EventRelevantAnalysisController.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/controller/EventWaveAnalysisController.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RelevantMapper.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RmpEventAdvanceMapper.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RmpEventDetailAssMapper.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/EventWaveAnalysisMapper.xml create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/RelevantMapper.xml create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/RmpEventDetailAssMapper.xml create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/EventRelevantAnalysisService.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/EventWaveAnalysisService.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/EventRelevantAnalysisServiceImpl.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/EventWaveAnalysisServiceImpl.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/UtilNormalization.java create mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/Utils.java delete mode 100644 pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/qvvr_balance.dll rename pqs-advance/advance-boot/src/main/resources/{libqvvr_pg_dll.so => libqvvr_balance_dll.so} (100%) create mode 100644 pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/TransformerClient.java create mode 100644 pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/fallback/TransformerClientFallbackFactory.java create mode 100644 pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/pojo/dto/transformer/EntityLogicDTO.java create mode 100644 pqs-event/event-api/src/main/java/com/njcn/event/api/RmpEventDetailFeignClient.java create mode 100644 pqs-event/event-api/src/main/java/com/njcn/event/api/fallback/RmpEventDetailFeignClientFallbackFactory.java create mode 100644 pqs-event/event-api/src/main/java/com/njcn/event/pojo/po/RmpEventDetailAssPO.java create mode 100644 pqs-event/event-api/src/main/java/com/njcn/event/pojo/vo/AdvanceEventDetailVO.java delete mode 100644 pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/AdvancedAnalysisController.java diff --git a/pqs-advance/advance-api/pom.xml b/pqs-advance/advance-api/pom.xml index eb06043eb..a5f991315 100644 --- a/pqs-advance/advance-api/pom.xml +++ b/pqs-advance/advance-api/pom.xml @@ -33,6 +33,12 @@ common-microservice ${project.version} + + + com.njcn + event-api + ${project.version} + com.sun.jna jna diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/enums/AdvanceResponseEnum.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/enums/AdvanceResponseEnum.java index 909f41a62..b16ee6ff0 100644 --- a/pqs-advance/advance-api/src/main/java/com/njcn/advance/enums/AdvanceResponseEnum.java +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/enums/AdvanceResponseEnum.java @@ -28,7 +28,9 @@ public enum AdvanceResponseEnum { USER_DATA_P_NODE_PARAMETER_ERROR("A0101","无用采用户或所有用户的完整性均不满足条件"), - RESPONSIBILITY_PARAMETER_ERROR("A0101","调用接口程序计算失败,参数非法") + RESPONSIBILITY_PARAMETER_ERROR("A0101","调用接口程序计算失败,参数非法"), + + EVENT_EMPTY("A0102","没有查询到未分析事件") ; private final String code; diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/enums/EnumEvt.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/enums/EnumEvt.java new file mode 100644 index 000000000..96bcc9dfa --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/enums/EnumEvt.java @@ -0,0 +1,99 @@ +package com.njcn.advance.enums; + +/** + * @Author: Sunwei 【sunW2016@163.com】 + * @Description: 高级分析返回结果 + * @Date: Create in 9:02 2018/3/6 + * @Modified By: + */ +public enum EnumEvt { + EVT_NUM("evt_num", "高级算法返回事件个数"), EVT_BUF("evt_buf", "高级算法返回数据"), QVVR_TYPE("qvvr_type", "暂降类型"), POW_A("POW_a", + "A相波形起始点"), POW_B("POW_b", "B相波形起始点"), POW_C("POW_c", "C相波形起始点"), SEG_T_IDX("SEG_T_idx", + "修正分段位置"), SEG_T_NUM("SEG_T_num", "分段数目"), SEG_RMS_T_NUM("SEG_RMS_T_num", "有效值分段数目"), SEG_RMS_T_IDX( + "SEG_RMS_T_idx", "有效值分段位置"), UA_MIN("ua_min", "A相电压特征值"), UB_MIN("ub_min", + "B相电压特征值"), UC_MIN("uc_min", "C相电压特征值"), U3_MIN("u3_min", + "三相电压特征值"), U_MIN_NUM("u_min_num", "特征值个数"), ORDER_MIN_IDX("order_min_idx", + "最小值位置"), HOLD_TIME_RMS("hold_time_rms", "有效值算法持续时间"), HOLD_TIME_DQ( + "hold_time_dq", + "dq变换算法持续时间"), VOLTAGECHANGE_VA("Voltagechange_Va", + "A相跳变段电压变化率"), VOLTAGECHANGE_VB("Voltagechange_Vb", + "B相跳变段电压变化率"), VOLTAGECHANGE_VC("Voltagechange_Vc", + "C相跳变段电压变化率"), ANGLE_DIFF_AP("angle_diff_ap", + "A相相位正跳变"), ANGLE_DIFF_BP("angle_diff_bp", + "B相相位正跳变"), ANGLE_DIFF_CP("angle_diff_cp", + "C相相位正跳变"), ANGLE_DIFF_AN("angle_diff_an", + "A相相位负跳变"), ANGLE_DIFF_BN("angle_diff_bn", + "B相相位负跳变"), ANGLE_DIFF_CN("angle_diff_cn", + "C相相位负跳变"), BPH_MAX_VALUE("bph_max_value", + "不平衡度"), QVVR_CATA_CAUSE("qvvr_cata_cause", + "暂降原因"), QVVR_PHASETYPE("qvvr_phasetype", + "暂降相别"), QVVR_CATA_TYPE("qvvr_cata_type", + "暂降类型"), POWER_QVVR_BEFORE_BUF("power_qvvr_before_buf", + "暂态前基波功率参数"),POWER_QVVR_AFTER_BUF("power_qvvr_after_buf", + "暂态前基波功率参数"),FUND_P("Fund_P", + "基波有功功率"),FUND_Q("Fund_Q", + "基波无功功率"),FUND_S("Fund_S", + "基波视在功率"),QVVR_DIRECTION_INFO("qvvr_direction_info", + "暂降源定位特征参数"),TRIG_TIME("trig_time", + "暂降触发时刻"),QVVR_BEFORE_RMS("qvvr_before_rms", + "暂降前基波有效值"),QVVR_BEFORE_ZK("qvvr_before_zk", + "暂降前基波阻抗值"),QVVR_OCCUR_RMS("qvvr_occur_rms", + "暂降发生时基波有效值"),QVVR_OCCUR_ZK("qvvr_occur_zk", + "暂降发生时基波阻抗值"),QVVR_POS_INFO("qvvr_pos_info", + "暂降源与监测位置关系"),QVVR_UTBL_INFO("qvvr_utbl_info", + "突变量参数"),ENTER("\n", + "回车换行"), QUOTATION("\"", + "双引号"), NEWLINE("\n\t", + "换行Tab"), TAB("\t", + "tab"); + /** + * 字段描述 + */ + private String description; + + /** + * 字段值 + */ + private String property; + + EnumEvt(String property, String description) { + this.description = description; + this.property = property; + } + + public String getDescription() { + return description; + } + + public String getProperty() { + return property; + } + + public static String setEvtProperty(String property) { + return QUOTATION.getProperty() + property + QUOTATION.getProperty() + ":"; + } + + public static String setEnter(String s, int lineNumber) { + return s += "," + ENTER.getProperty() + setTab(lineNumber); + } + + public static String setClose(int lineNumber) { + String s = ENTER.getProperty(); + s += setTab(lineNumber); + return s + "}"; + } + + public static String setTab(int count) { + String string = ""; + + for (int i = 0; i < count; i++) { + string += TAB.getProperty(); + } + + return string; + } + + public static String setNewLine() { + return "{" + NEWLINE.getProperty(); + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/FinalData.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/FinalData.java deleted file mode 100644 index fdabd4e5d..000000000 --- a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/FinalData.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.njcn.advance.pojo.bo; - -/** - * pqs - * - * @author cdf - * @date 2023/6/20 - */ -public interface FinalData { - - /** - * 暂降事件按开始时间归集门槛10秒 - */ - int TIME_THRESHOLD = 10; - //分组的最大组数 - int MAX_GROUP_NUM = 1000; - //类别数 - int MAX_CATA_NUM = 7; - //最大事件个数 - int MAX_EVT_NUM = 1000; - //三相故障 - int QVVR_TYPE_THREE = 9; - //故障类型未知 - int QVVR_TYPE_UNKNOWN = 10; - //节点不在网络拓扑中 - int QVVR_TYPE_OUTOFRANGE = -1; - int DATA_INF = -1; - int EVT_TYPE_NUM = 6;//故障类型数 - int MAX_PATH_NUM = 50;//最大路径数 - int NODE_NUM = -1;//输入节点数 - - // 暂降综合评估算法 - int CLUSER_NUM = 4; // 系统中各监测点分类后的代表节点 - int MAX_LINE_NUM = 1000; // 监测点最多个数 - int MAX_STA_NUM = 120; // 支持的子系统个数 - - -} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/QtIdxArray.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/QtIdxArray.java index 3ea0613b5..97ca3f10e 100644 --- a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/QtIdxArray.java +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/QtIdxArray.java @@ -1,6 +1,7 @@ package com.njcn.advance.pojo.bo; -import com.njcn.advance.pojo.dto.QtIdx; +import com.njcn.advance.pojo.dto.relevent.FinalData; +import com.njcn.advance.pojo.dto.relevent.QtIdx; import com.sun.jna.Structure; import java.util.List; diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/QvvrDataStruct.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/QvvrDataStruct.java index 6a9ad4d86..de454b1c7 100644 --- a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/QvvrDataStruct.java +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/QvvrDataStruct.java @@ -1,5 +1,6 @@ package com.njcn.advance.pojo.bo; +import com.njcn.advance.pojo.dto.relevent.FinalData; import com.sun.jna.Structure; import java.util.Arrays; diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/ZtpgSin.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/ZtpgSin.java index 82b3e7711..234af5ed9 100644 --- a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/ZtpgSin.java +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/bo/ZtpgSin.java @@ -1,5 +1,6 @@ package com.njcn.advance.pojo.bo; +import com.njcn.advance.pojo.dto.relevent.FinalData; import com.sun.jna.Structure; import java.util.Arrays; diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/BalanceInfo.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/BalanceInfo.java index 798417c2c..7ebe66475 100644 --- a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/BalanceInfo.java +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/BalanceInfo.java @@ -1,5 +1,6 @@ package com.njcn.advance.pojo.dto; +import com.njcn.advance.pojo.dto.relevent.QtIdx; import lombok.Data; import java.util.List; diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityGroupData.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityGroupData.java new file mode 100644 index 000000000..8d2a236fa --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityGroupData.java @@ -0,0 +1,43 @@ +package com.njcn.advance.pojo.dto.relevent; + +import lombok.Data; + +/** + * pqs + * + * @author cdf + * @date 2023/7/20 + */ +@Data +public class EntityGroupData { + private int idx[]; + private int all_evt_num; + private int evt_in_num; + private int evt_out_num; + private int evt_res_num; + + private int Matrixcata[][]; + + private EntityGroupEvtData in_buf[]; + private EntityGroupEvtData out_buf[]; + private EntityGroupEvtData res_buf[]; + private EntityGroupEvtData grp_buf[][]; + + private int grp_num[]; + private int grp_all_num; + private EntityGroupEvtData grp_cata_buf[][][]; + private int grp_cata_num[][]; + + public EntityGroupData() { + idx = new int[FinalData.MAX_EVT_NUM]; + Matrixcata = new int[FinalData.MAX_CATA_NUM][FinalData.MAX_EVT_NUM]; + in_buf = new EntityGroupEvtData[FinalData.MAX_EVT_NUM]; + out_buf = new EntityGroupEvtData[FinalData.MAX_EVT_NUM]; + res_buf = new EntityGroupEvtData[FinalData.MAX_EVT_NUM]; + grp_buf = new EntityGroupEvtData[FinalData.MAX_GROUP_NUM][FinalData.MAX_EVT_NUM]; + grp_num = new int[FinalData.MAX_GROUP_NUM]; + grp_cata_buf = new EntityGroupEvtData[FinalData.MAX_GROUP_NUM][FinalData.MAX_CATA_NUM + + 2][FinalData.MAX_EVT_NUM]; + grp_cata_num = new int[FinalData.MAX_GROUP_NUM][FinalData.MAX_CATA_NUM + 2]; + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityGroupEvtData.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityGroupEvtData.java new file mode 100644 index 000000000..c4c888941 --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityGroupEvtData.java @@ -0,0 +1,53 @@ +package com.njcn.advance.pojo.dto.relevent; + +import com.njcn.advance.pojo.dto.SagEvent; +import lombok.Data; + +@Data +public class EntityGroupEvtData implements Cloneable,Comparable { + + //逻辑节点序号 + private int node; + //事件开始时间时标 + private int start_time; + //类别 + private int cata; + //标注类别 + private int cata2; + //物理节点 + private String nodePhysics; + + private SagEvent sagEvent; + + private String sagReason; + + + public Object objClone() { + try { + return clone(); + } catch (CloneNotSupportedException e) { + return new EntityGroupEvtData(null, -1, -1, -1,null,null); + } + } + + public EntityGroupEvtData(String nodePhysics, int start_time, int cata, int cata2, SagEvent sagEvent, String sagReason) { + this.nodePhysics = nodePhysics; + this.start_time = start_time; + this.cata = cata; + this.cata2 = cata2; + this.sagEvent = sagEvent; + this.sagReason = sagReason; + } + + + @Override + public int compareTo(EntityGroupEvtData obj) { + if(this.getStart_time() < obj.getStart_time()){ + return -1; + }else if(this.getStart_time() > obj.getStart_time()){ + return 1; + } + + return 0; + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityLogic.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityLogic.java new file mode 100644 index 000000000..f71da1882 --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityLogic.java @@ -0,0 +1,21 @@ +package com.njcn.advance.pojo.dto.relevent; + + +import lombok.Data; + +@Data +public class EntityLogic { + //物理隔绝变压器策略GUID + private String tPIndex; + //变压器逻辑上节点 + private String node_h; + //变压器逻辑下节点 + private String node_l; + // 变压器连接方式 + private Integer type; + //变压器物理上节点 + private String nodeBefore; + //变压器物理下节点 + private String nodeNext; + +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityMtrans.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityMtrans.java new file mode 100644 index 000000000..67550b4bd --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EntityMtrans.java @@ -0,0 +1,71 @@ +package com.njcn.advance.pojo.dto.relevent; + +import com.njcn.advance.pojo.dto.relevent.FinalData; + +import java.io.Serializable; +import java.util.Arrays; + +public class EntityMtrans implements Serializable { + private static final long serialVersionUID = 1L; + private int Matrixcata0[][]; + private int Matrixcata1[][]; + private int Mtrans[][]; + private int possiable_path[][]; + private int path_num; + + public EntityMtrans() { + super(); + Mtrans = new int[FinalData.NODE_NUM][FinalData.NODE_NUM]; + Matrixcata0 = new int[FinalData.EVT_TYPE_NUM][FinalData.NODE_NUM]; + Matrixcata1 = new int[FinalData.EVT_TYPE_NUM][FinalData.NODE_NUM]; + possiable_path = new int[FinalData.MAX_PATH_NUM][FinalData.NODE_NUM + 1]; + path_num = 0; + } + + public int[][] getMatrixcata0() { + return Matrixcata0; + } + + public void setMatrixcata0(int[][] matrixcata0) { + Matrixcata0 = matrixcata0; + } + + public int[][] getMatrixcata1() { + return Matrixcata1; + } + + public void setMatrixcata1(int[][] matrixcata1) { + Matrixcata1 = matrixcata1; + } + + public int[][] getMtrans() { + return Mtrans; + } + + public void setMtrans(int[][] mtrans) { + Mtrans = mtrans; + } + + public int[][] getPossiable_path() { + return possiable_path; + } + + public void setPossiable_path(int[][] possiable_path) { + this.possiable_path = possiable_path; + } + + public int getPath_num() { + return path_num; + } + + public void setPath_num(int path_num) { + this.path_num = path_num; + } + + @Override + public String toString() { + return "EntityMtrans [Matrixcata0=" + Arrays.toString(Matrixcata0) + ", Matrixcata1=" + + Arrays.toString(Matrixcata1) + ", Mtrans=" + Arrays.toString(Mtrans) + ", possiable_path=" + + Arrays.toString(possiable_path) + ", path_num=" + path_num + "]"; + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EventAssObj.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EventAssObj.java new file mode 100644 index 000000000..528972e1c --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/EventAssObj.java @@ -0,0 +1,123 @@ +package com.njcn.advance.pojo.dto.relevent; + +import com.njcn.advance.pojo.dto.SagEvent; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; +import java.util.List; + +/* + *一个归一化事件包含多个事件(一对多) + *indexEventAss:事件关联分析表Guid + *time:归一化中第一个时间 + *describe:关联事件描述 + *bRange:是否进行范围分析 + *indexUser:用户表Guid + *updateTime:更新时间 + *state:数据状态 + *name:关联事件名称 + *list:属于该归一化事件的暂降事件 + *strTime:字符串时间 +*/ +@Data +public class EventAssObj implements Serializable { + private String indexEventAss; + private LocalDateTime time; + private String describe; + private int bRange; + private String indexUser; + private LocalDateTime updateTime = LocalDateTime.now(); + private int state; + private String name; + private String strTime; + private List list; + + public String getStrTime() { + return strTime; + } + + public void setStrTime(String strTime) { + this.strTime = strTime; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIndexEventAss() { + return indexEventAss; + } + + public void setIndexEventAss(String indexEventAss) { + this.indexEventAss = indexEventAss; + } + + public LocalDateTime getTime() { + return time; + } + + public void setTime(LocalDateTime time) { + this.time = time; + } + + public String getDescribe() { + return describe; + } + + public void setDescribe(String describe) { + this.describe = describe; + } + + public int getbRange() { + return bRange; + } + + public void setbRange(int bRange) { + this.bRange = bRange; + } + + public String getIndexUser() { + return indexUser; + } + + public void setIndexUser(String indexUser) { + this.indexUser = indexUser; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public int getState() { + return state; + } + + public void setState(int state) { + this.state = state; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + @Override + public String toString() { + return "EventAssObj [indexEventAss=" + indexEventAss + ", time=" + time + ", describe=" + describe + ", bRange=" + + bRange + ", indexUser=" + indexUser + ", updateTime=" + updateTime + ", state=" + state + ", name=" + + name + ", strTime=" + strTime + ", list=" + list + "]"; + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/FinalData.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/FinalData.java new file mode 100644 index 000000000..1d7a025a4 --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/FinalData.java @@ -0,0 +1,25 @@ +package com.njcn.advance.pojo.dto.relevent; + +public class FinalData { + public static final int TIME_THRESHOLD = 10;//暂降事件按开始时间归集门槛10秒 + public static final int MAX_GROUP_NUM = 1000;//分组的最大组数 + public static final int MAX_CATA_NUM = 7;//类别数 + public static final int MAX_EVT_NUM = 1000;//最大事件个数 + + public static final int QVVR_TYPE_THREE = 9; //三相故障 + public static final int QVVR_TYPE_UNKNOWN = 10; //故障类型未知 + public static final int QVVR_TYPE_OUTOFRANGE = -1; //节点不在网络拓扑中 + public static final int DATA_INF = -1; + public static final int EVT_TYPE_NUM = 6;//故障类型数 + public static final int MAX_PATH_NUM = 50;//最大路径数 + public static int NODE_NUM;//输入节点数 + + // 暂降综合评估算法 + public static final int CLUSER_NUM = 4; // 系统中各监测点分类后的代表节点 + public static final int MAX_LINE_NUM = 1000; // 监测点最多个数 + public static final int MAX_STA_NUM = 120; // 支持的子系统个数 + + static { + NODE_NUM = -1; + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/PlantInfo.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/PlantInfo.java new file mode 100644 index 000000000..27dfd7550 --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/PlantInfo.java @@ -0,0 +1,32 @@ +package com.njcn.advance.pojo.dto.relevent; + +import lombok.Data; + +import java.io.Serializable; + +/** + * pqs + *终端监测点名称信息 + * nameGD:供电公司名称 + * nameBD:变电站名称 + * nameSubV:母线名称 + * namePoint:监测点名称 + * indexPoint:监测点的唯一标识 + * + * 新增add + * xuyang + * 2021.05.11 + * 监测点电压等级:monitorVoltageLevel + * 监测点干扰源类型终:monitorLoadType + */ +@Data +public class PlantInfo implements Serializable { + private String indexPoint; + private String nameGD; + private String nameBD; + private String nameSubV; + private String namePoint; + private String monitorVoltageLevel; + private String monitorLoadType; + private String objName; +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/QtIdx.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/QtIdx.java similarity index 94% rename from pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/QtIdx.java rename to pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/QtIdx.java index f6cba8d7d..d9c002a73 100644 --- a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/QtIdx.java +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/QtIdx.java @@ -1,4 +1,4 @@ -package com.njcn.advance.pojo.dto; +package com.njcn.advance.pojo.dto.relevent; import com.sun.jna.Structure; import lombok.Data; diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/SagEvent.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/SagEvent.java new file mode 100644 index 000000000..0b12f4a2b --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/relevent/SagEvent.java @@ -0,0 +1,423 @@ +package com.njcn.advance.pojo.dto; + +import com.njcn.advance.pojo.dto.relevent.PlantInfo; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +/** + * pqs + * + * @author cdf + * @date 2023/7/21 + */ +public class SagEvent implements Comparable, Serializable { + // 事件的唯一标识 + private String indexEventDetail; + + private Integer waveType; + // 暂降事件发生时间 + private LocalDateTime sagTime; + + // 暂降事件发生时间毫秒 + private Integer msec; + + // 事件描述 + private String events; + + // 持续时间 + private Float persistTime; + + // 发生暂降事件的监测点层级信息 + private PlantInfo plantInfo; + + // 拼接sagTime和msec + private String strTime; + + // 事件发生时刻的毫秒表示 + private Long time; + + // 监测点的唯一标识 + private String indexPoint; + + // 归一化事件的GUID + private String indexEventAss; + + // 特征幅值 + private Float eventValue; + + // 暂降原因 + private String sagReason; + + // 暂降类型 + private String sagType; + + // 暂降类型描述 + private String sagTypeDes; + + public String getSagTypeDes() { + return sagTypeDes; + } + + public void setSagTypeDes(String sagTypeDes) { + this.sagTypeDes = sagTypeDes; + } + + // 暂降深度 + private String strEventValue; + private String strPersist; + + // 事件是否经过高级算法处理(0-未处理,1-已处理,默认为0) + private Integer dealFlag; + + // 事件是否经过高级算法处理中文描述(已处理、未处理) + private String dealFlagDescription; + + // 录波文件是否存在(0-不存在,1-存在,默认为0) + private Integer fileFlag; + + // 录波文件是否存在中文描述(存在、不存在) + private String fileFlagDescription; + + // 高级算法返回dq持续时间 + private Float dqTime; + + // 高级算法处理事件个数记录 + private Integer number; + + // 归一化处理更新时间 + private LocalDateTime dealTime; + + // 高级算法的对应关系 + private int cata; + + // 第一次事件的触发时间 + private Date firstTime; + + // 第一次事件的暂降类型 + private String firstType; + + // 第一次事件的触发时间毫秒 + private Integer firstMs; + + // 第一次事件触发时间date->毫秒 + private Long firstTimeMills; + + // 暂降严重度 + private Float severity; + + // 排序方式 + private int sortType = 0; // 初始化默认为0-按照时间排序 新增1-按暂降严重度排序 2-暂降发生时刻排序 3-先根据电压等级排序,如果相等再按照暂降幅值排序 + + //电压等级 + private Double voltage; + + //监测点对象名称 + private String objName; + + public String getObjName() { + return objName; + } + + public void setObjName(String objName) { + this.objName = objName; + } + + public Integer getWaveType() { + return waveType; + } + + public void setWaveType(Integer waveType) { + this.waveType = waveType; + } + + private String strVoltage; + + public Double getVoltage() { + return voltage; + } + + public void setVoltage(Double voltage) { + this.voltage = voltage; + } + + public String getStrVoltage() { + return strVoltage; + } + + public void setStrVoltage(String strVoltage) { + //转为double + strVoltage = strVoltage.toUpperCase(); + String str = strVoltage.substring(0, strVoltage.indexOf("KV")); + this.voltage = Double.parseDouble(str); + } + + public int getSortType() { + return sortType; + } + + public void setSortType(int sortType) { + this.sortType = sortType; + } + + public Float getSeverity() { + return severity; + } + + public void setSeverity(Float severity) { + this.severity = severity; + } + + public Long getFirstTimeMills() { + return firstTimeMills; + } + + public void setFirstTimeMills(Long firstTimeMills) { + this.firstTimeMills = firstTimeMills; + } + + public Integer getFirstMs() { + return firstMs; + } + + public void setFirstMs(Integer firstMs) { + this.firstMs = firstMs; + } + + public Date getFirstTime() { + return firstTime; + } + + public void setFirstTime(Date firstTime) { + this.firstTime = firstTime; + } + + public String getFirstType() { + return firstType; + } + + public void setFirstType(String firstType) { + this.firstType = firstType; + } + + public Integer getFileFlag() { + return fileFlag; + } + + public void setFileFlag(Integer fileFlag) { + this.fileFlag = fileFlag; + } + + public String getFileFlagDescription() { + return fileFlagDescription; + } + + public void setFileFlagDescription(String fileFlagDescription) { + this.fileFlagDescription = fileFlagDescription; + } + + public int getCata() { + return cata; + } + + public void setCata(int cata) { + this.cata = cata; + } + + public LocalDateTime getDealTime() { + return dealTime; + } + + public void setDealTime(LocalDateTime dealTime) { + this.dealTime = dealTime; + } + + public Float getDqTime() { + return dqTime; + } + + public void setDqTime(Float dqTime) { + this.dqTime = dqTime; + } + + public Integer getNumber() { + return number; + } + + public void setNumber(Integer number) { + this.number = number; + } + + public void setDealFlagDescription(String dealFlagDescription) { + this.dealFlagDescription = dealFlagDescription; + } + + public String getDealFlagDescription() { + return dealFlagDescription; + } + + public Integer getDealFlag() { + return dealFlag; + } + + public void setDealFlag(Integer dealFlag) { + this.dealFlag = dealFlag; + } + + public String getIndexEventDetail() { + return indexEventDetail; + } + + public void setIndexEventDetail(String indexEventDetail) { + this.indexEventDetail = indexEventDetail; + } + + public LocalDateTime getSagTime() { + return sagTime; + } + + public void setSagTime(LocalDateTime sagTime) { + this.sagTime = sagTime; + } + + public Integer getMsec() { + return msec; + } + + public void setMsec(Integer msec) { + this.msec = msec; + } + + public String getEvents() { + return events; + } + + public void setEvents(String events) { + this.events = events; + } + + public Float getPersistTime() { + return persistTime; + } + + public void setPersistTime(Float persistTime) { + if (persistTime == null) { + this.persistTime = 0f; + return; + } + + float f1 = (float) (Math.round(persistTime.floatValue() * 1000)) / 1000; + this.persistTime = new Float(f1); + } + + public PlantInfo getPlantInfo() { + return plantInfo; + } + + public void setPlantInfo(PlantInfo plantInfo) { + this.plantInfo = plantInfo; + } + + public String getStrTime() { + return strTime; + } + + public void setStrTime(String strTime) { + this.strTime = strTime; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + + public String getIndexPoint() { + return indexPoint; + } + + public void setIndexPoint(String indexPoint) { + this.indexPoint = indexPoint; + } + + public String getIndexEventAss() { + return indexEventAss; + } + + public void setIndexEventAss(String indexEventAss) { + this.indexEventAss = indexEventAss; + } + + public Float getEventValue() { + return eventValue; + } + + public void setEventValue(Float eventValue) { + if (eventValue == null) { + this.eventValue = 0f; + return; + } + + this.eventValue = eventValue; + } + + public String getSagReason() { + return sagReason; + } + + public void setSagReason(String sagReason) { + this.sagReason = sagReason; + } + + public String getSagType() { + return sagType; + } + + public void setSagType(String sagType) { + this.sagType = sagType; + } + + public String getStrEventValue() { + return strEventValue; + } + + public void setStrEventValue(String strEventValue) { + this.strEventValue = strEventValue; + } + + public String getStrPersist() { + return strPersist; + } + + public void setStrPersist(String strPersist) { + this.strPersist = strPersist; + } + + + + // 根据设定规则进行排序 + @Override + public int compareTo(SagEvent obj) { + switch (this.getSortType()) { + case 1: + return obj.getSeverity().compareTo(this.getSeverity()); + case 2: + return this.getTime().compareTo(obj.getTime()); + case 3: { + if (obj.getVoltage().compareTo(this.getVoltage()) != 0) { + return obj.getVoltage().compareTo(this.getVoltage()); + } + else { + return this.getEventValue().compareTo(obj.getEventValue()); + } + } + default: + break; + } + + return this.getFirstTimeMills().compareTo(obj.getFirstTimeMills()); + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/AnalyWave.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/AnalyWave.java new file mode 100644 index 000000000..8f4b1ae9f --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/AnalyWave.java @@ -0,0 +1,1152 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.CharsetUtil; +import com.njcn.advance.utils.WaveUtils; +import com.njcn.common.config.GeneralInfo; +import com.njcn.common.utils.wave.BitConverter; +import com.njcn.harmonic.utils.PubUtils; +import com.njcn.oss.utils.FileStorageUtil; + +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import sun.nio.ch.IOUtil; + + +import javax.annotation.Resource; +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.*; + + +public class AnalyWave { + + + + + /***************************************** + * 解析comtrate文件工具类 + * author yexb根据Ww算法装换 + *****************************************/ + // 日志记录 + private static final Logger logger = LoggerFactory.getLogger(AnalyWave.class); + + private AnalyWaveModel.tagComtradeCfg ComtradeCfg;//cfg实体类 + private AnalyWaveModel.tagRates RatesCfg;//cfg_采样率实体类 + private AnalyWaveModel.tagDataValue TagDataValue;//返回数据实体类 + private String strBinType;//结束读取cfg标志 + private int iPush = 0;//前推周波个数(目前常见的是5个或者10个周波) + private float nFreq;//comtrade频率 WW 2019-11-14 + private long nOneWaveNum = 32;//最小采样率,高级算法时候需要 + private long nAllWaveNum = 0;//所有波形 + private Date TimeTrige;//cfg中【波形的触发时间】、【波形的起始时间】 + + private static Date TimeWave; + + public Date getTimeTrige() { + return TimeTrige; + } + + public void setTimeTrige(Date timeTrige) { + TimeTrige = timeTrige; + } + + public static Date getTimeWave() { + return TimeWave; + } + + public void setTimeWave(Date timeWave) { + TimeWave = timeWave; + } + + //add by sw 暂降触发时间 + private Date firstTime;//暂降触发第一次 + private Integer firstMs; + + //add by sw获取最小采样率供其他类使用 + public long getnOneWaveNum() { + return nOneWaveNum; + } + + public AnalyWaveModel.tagRates getRatesCfg() { + return RatesCfg; + } + + public Date getFirstTime() { + return firstTime; + } + + public Integer getFirstMs() { + return firstMs; + } + + public String startTime; + + public String ms; + + + /****************************************** + * 调用读取comtrate文件方法 + ** ** strFilePath *** cfg文件路径 + * *** auth *** 读取方式 null则使用本地读取方式读取 + ******************************************/ + public AnalyWaveModel.tagDataValue readComtrade(List temCfgList,byte[] array, int iFlag) { + //初始化参数 + ComtradeCfg = new AnalyWaveModel.tagComtradeCfg(); + RatesCfg = new AnalyWaveModel.tagRates(); + TagDataValue = new AnalyWaveModel.tagDataValue(); + // 读取cfg文件 + if (!AnalyseComtradeCfg(temCfgList)) { + return TagDataValue; + } + + if (!strBinType.equals("BINARY")) { + return TagDataValue; + } + + //编辑数据标题 YXB2020-10-09 去除相别为N相的数据//存储数据标题 + List tmpWaveTitle = new ArrayList<>(); + tmpWaveTitle.add("Time"); + for (int j = 0; j < ComtradeCfg.nAnalogNum; j++) { + if (ComtradeCfg.OneChannleCfg.get(j).szPhasicName.toUpperCase().equals("N")) { + continue; + } else { + String strUnit = "U"; + switch (ComtradeCfg.OneChannleCfg.get(j).szUnitName.toUpperCase()) { + case "KV": + strUnit = "U"; + break; + case "V": + strUnit = "U"; + break; + case "A": + strUnit = "I"; + break; + } + tmpWaveTitle.add(strUnit + ComtradeCfg.OneChannleCfg.get(j).szPhasicName.toUpperCase() + "相"); + } + } + // 读取dat + /*****根据通道号计算相别** add by yexb -----Start**** + * 1、判断是否是3的倍数,是3的倍数则是3相 + * 2、假如不是3的倍数 ,是1的倍数则是单相 + ********************************************************/ + if (ComtradeCfg.nAnalogNum % 3 == 0) { + ComtradeCfg.nPhasic = 3; + } else if (ComtradeCfg.nAnalogNum % 1 == 0) { + ComtradeCfg.nPhasic = 1; + } + TagDataValue.setiPhasic(ComtradeCfg.nPhasic); + + List> listWaveData = AnalyseComtradeDat(array, iFlag); + TagDataValue.setTmpWaveTitle(tmpWaveTitle); + TagDataValue.setListWaveData(listWaveData); + + /*****根据通道号计算相别** add by yexb -----end****/ + + return TagDataValue; + } + + + /********************************* + * 读取cfg方法 + * param strFilePath 文件路径 + * return 返回bool为是否解析出错 + * readType 1:本地磁盘 2:华为obs 3: minioss + **********************************/ + private boolean AnalyseComtradeCfg(List temCfgList) { + Iterator iterable = temCfgList.iterator(); + iterable.next(); + String[] strTempArray;// 读取cfg文件 + try { + nFreq = 0f;//WW 2019-11-14 + String strFileLine = iterable.next(); + strTempArray = strFileLine.split(","); + + for (int i = 0; i < strTempArray.length; i++) { + switch (i) { + case 0:// 总个数 + ComtradeCfg.nChannelNum = Integer.parseInt(strTempArray[i]); + break; + case 1:// 模拟量的个数 + { + String str = strTempArray[i].substring(0, strTempArray[i].length() - 1); + ComtradeCfg.nAnalogNum = Integer.parseInt(str); + } + break; + case 2:// 开关量的个数 + { + String str = strTempArray[i].substring(0, strTempArray[i].length() - 1); + ComtradeCfg.nDigitalNum = Integer.parseInt(str); + } + break; + } + } + + // 从第三行到第ComtradeCfg.nChannelNum+3行是模拟量通道和数字量通道 + for (int i = 0; i < ComtradeCfg.nChannelNum; i++) { + AnalyWaveModel.tagOneChannleCfg OneChannlecfg = new AnalyWaveModel.tagOneChannleCfg(); + ComtradeCfg.OneChannleCfg.add(OneChannlecfg); + + strFileLine = iterable.next(); + strTempArray = strFileLine.split(","); + // 配置总共13项 + for (int j = 0; j < strTempArray.length; j++) { + switch (j) { + case 0:// 通道序号 + OneChannlecfg.nIndex = Integer.parseInt(strTempArray[j]); + break; + case 1:// 通道名称 + OneChannlecfg.szChannleName = strTempArray[j]; + break; + case 2:// 相位名称 + OneChannlecfg.szPhasicName = strTempArray[j]; + break; + case 3:// 监视的通道名称 + OneChannlecfg.szMonitoredChannleName = strTempArray[j]; + break; + case 4:// 通道的单位 + OneChannlecfg.szUnitName = strTempArray[j]; + break; + case 5:// 通道的系数 + OneChannlecfg.fCoefficent = Float.parseFloat(strTempArray[j]); + break; + case 6:// 通道的偏移量 + OneChannlecfg.fOffset = Float.parseFloat(strTempArray[j]); + break; + case 7:// 起始采样时间的偏移量 + OneChannlecfg.fTimeOffset = Float.parseFloat(strTempArray[j]); + break; + case 8:// 采样值的最小值 + OneChannlecfg.nMin = Integer.parseInt(strTempArray[j]); + break; + case 9:// 采样值的最大值 + OneChannlecfg.nMax = Integer.parseInt(strTempArray[j]); + break; + case 10:// 一次变比 + OneChannlecfg.fPrimary = Float.parseFloat(strTempArray[j]); + break; + case 11:// 二次变比 + OneChannlecfg.fSecondary = Float.parseFloat(strTempArray[j]); + break; + case 12:// 一次值还是二次值标志 + OneChannlecfg.szValueType = strTempArray[j]; + break; + } + } + } + // 采样频率 + strFileLine = iterable.next(); + float fFreq = Float.parseFloat(strFileLine); + nFreq = (float) fFreq;//WW 2019-11-14 + // 采样段数 + strFileLine = iterable.next(); + int nRates = Integer.parseInt(strFileLine); + RatesCfg.nRates = nRates; + // 获得每段的采样率 + long nOffset = 0; + for (int i = 0; i < nRates; i++) { + strFileLine = iterable.next(); + strTempArray = strFileLine.split(","); + + AnalyWaveModel.tagOneRate OneRate = new AnalyWaveModel.tagOneRate(); + RatesCfg.OneRate.add(OneRate); + + for (int j = 0; j < strTempArray.length; j++) { + + switch (j) { + case 0:// 单周波采样点数 + OneRate.nOneSample = (int) (Float.parseFloat(strTempArray[j]) / nFreq);//WW 2019-11-14 + break; + case 1:// 总点数 //这里的strTemp是一个偏移量 + OneRate.nSampleNum = (long) (Float.parseFloat(strTempArray[j]) - nOffset); + nOffset = OneRate.nSampleNum; + break; + } + } + } + + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss.SSS"); + // 波形起始时间 + strFileLine = iterable.next(); + strFileLine = strFileLine.substring(0, strFileLine.length() - 3).replace(",", " "); + TimeTrige = sdf.parse(strFileLine); + // 暂态触发时间 + strFileLine = iterable.next(); + strFileLine = strFileLine.substring(0, strFileLine.length() - 3).replace(",", " "); + TimeWave = sdf.parse(strFileLine); + + Calendar calendar = Calendar.getInstance(); + calendar.setTime(TimeWave); + firstMs = calendar.get(Calendar.MILLISECOND); + firstTime = calendar.getTime(); + + long a = TimeWave.getTime(); + long b = TimeTrige.getTime(); + int c = (int) (a - b); + if (c >= 90 && c <= 110) { + iPush = 100; + } else if (c >= 190 && c <= 210) { + iPush = 200; + } + // 赋值编码格式(二进制) + strBinType = iterable.next().toUpperCase(); + + + + + } catch (Exception e) { + e.printStackTrace(); + logger.error("读取文件内容出错"+e.getMessage()); + return false; + }finally { + + + + } + return true; + } + + /********************************* + * 读取dat方法 + * param strFilePath + * List> 返回波形瞬时值 + **********************************/ + private List> AnalyseComtradeDat(byte[] array, int iFlag) { + float xValueAll = 0;//初始化xValue的值 + boolean blxValue = false;//判断是否首次登陆 + + List> listWaveData = new ArrayList<>();//返回数据 + + + try { + + + + + // 计算每个单独的数据块的大小 4字节的序号 4字节的时间 2字节的值 + // 示例中的排布是 4字节的序号 4字节的时间 UA(2字节) UB(2字节) UC(2字节) IA(2字节) IB(2字节) + // IC(2字节) + int nDigSize = (ComtradeCfg.nDigitalNum % 16) > 0 ? (ComtradeCfg.nDigitalNum / 16 + 1) * 2 + : ComtradeCfg.nDigitalNum / 16 * 2; + int nBlockSize = 2 * Integer.SIZE / 8 + ComtradeCfg.nAnalogNum * 2 + nDigSize; + int nBlockNum = array.length / nBlockSize; + nOneWaveNum = MinWaveSample(RatesCfg.OneRate); + /******************************************************** + * iFlag == 0 高级算法的要求,采样率只能是32-128 + * iFlag == 1 普通展示,采样率按照cfg里面最小的(大于32) + * iFlag == 2 App抽点要求,采样率抽点成32 + * iFlag == 3 高级算法原始波形(大于32) + ********************************************************/ + //高级算法的要求,采样率只能是32-128 + if (iFlag == 0) { + if (nOneWaveNum < 32) { + nOneWaveNum = 32; + } else if (nOneWaveNum > 128) { + nOneWaveNum = 128; + } + } + //App抽点要求,采样率抽点成32 + else if (iFlag == 2) { + if (nOneWaveNum < 32) { + nOneWaveNum = 32; + } else if (nOneWaveNum > 32) { + nOneWaveNum = 32; + } + } + + int iRates = 0; + // 设定最小采样率 + int nnInd = 0; + long nWaveNum = 0, nNum = 0;// 抽点后总共多少点数据 + AnalyWaveModel.tagRates RateTemp = new AnalyWaveModel.tagRates(); + for (iRates = 0; iRates < RatesCfg.nRates; iRates++) { + if (RatesCfg.OneRate.get(iRates).nOneSample >= 32) { + // 计算本段录波总共有多少波形 + nWaveNum = RatesCfg.OneRate.get(iRates).nSampleNum / RatesCfg.OneRate.get(iRates).nOneSample; + nAllWaveNum += nWaveNum; + // 将最低采样率替换到本段录波内 + AnalyWaveModel.tagOneRate OneTempRate = new AnalyWaveModel.tagOneRate(); + RateTemp.OneRate.add(OneTempRate); + //iFlag =3 一定不进行抽点算法 + if (iFlag != 3) { + //true 抽点算法(当前采样率跟统一采样率不一样则是抽点,否则是未抽点) + if (RatesCfg.OneRate.get(iRates).nOneSample != nOneWaveNum) { + RateTemp.OneRate.get(nnInd).nOneSample = nOneWaveNum; + // 计算本段录波按照最低采样点应该有多少录波 + RateTemp.OneRate.get(nnInd).nSampleNum = nOneWaveNum * nWaveNum; + } else { + RateTemp.OneRate.get(nnInd).nOneSample = RatesCfg.OneRate.get(iRates).nOneSample; + // 计算本段录波按照最低采样点应该有多少录波 + RateTemp.OneRate.get(nnInd).nSampleNum = RatesCfg.OneRate.get(iRates).nOneSample * nWaveNum; + } + } else { + RateTemp.OneRate.get(nnInd).nOneSample = RatesCfg.OneRate.get(iRates).nOneSample; + // 计算本段录波按照最低采样点应该有多少录波 + RateTemp.OneRate.get(nnInd).nSampleNum = RatesCfg.OneRate.get(iRates).nOneSample * nWaveNum; + } + + nNum += RateTemp.OneRate.get(nnInd).nSampleNum; + // 正常的配置中采样率 + RatesCfg.OneRate.get(nnInd).nOneSample = RatesCfg.OneRate.get(iRates).nOneSample; + RatesCfg.OneRate.get(nnInd).nSampleNum = RatesCfg.OneRate.get(iRates).nSampleNum; + nnInd++; + } + } + + long nOffSet = 0; + int nIndex = 0; + long nWaveSpan = 0; + + float fValue; + float dfValue;//两个点之间的时间差 + for (int i = 0; i < nBlockNum; i++) { + // 计算本段抽点采样间隔 + nWaveSpan = RatesCfg.OneRate.get(nIndex).nOneSample / RateTemp.OneRate.get(nIndex).nOneSample; + // 判断是否进入下一段 + if (i == RatesCfg.OneRate.get(nIndex).nSampleNum + nOffSet) { + nOffSet += RatesCfg.OneRate.get(nIndex).nSampleNum; + nIndex++; + if (nIndex == nnInd) { + break; + } + } + dfValue = (float) 20 / RatesCfg.OneRate.get(nIndex).nOneSample; + // 判断是否到了需要抽的采样点 + if (i % nWaveSpan == 0) { + // 计算每个通道的值 + List tmpWaveData = new ArrayList();//存储局部数据集合,包含了时间,A,B,C三相 + for (int j = 0; j < ComtradeCfg.nAnalogNum; j++) { + //数据只有电压ABC三相数据,不展示U0、I0等数据 YXB2020-10-09 去除相别为N相的数据 + if (ComtradeCfg.OneChannleCfg.get(j).szPhasicName.toUpperCase().equals("N")) { + break; + } + + float fCoef = ComtradeCfg.OneChannleCfg.get(j).fCoefficent; + fValue = BitConverter.byte2ToUnsignedShort(array, i * nBlockSize + 2 * 4 + j * 2) * fCoef; + + //WW 2019-11-14 + /************************** + * 1、接口返回的默认是二次值 + * 2、P是一次值 S是二次值 + * 3、S(二次值)情况下: + * ①、单位为"V"时候则直接等于; + * ②、单位为"kV"时候需要乘以1000 + * 4、P(一次值)情况下: + * ①、单位为"V"时候则直接等于; + * ②、单位为"kV"时候需要乘以1000 + **************************/ + if (ComtradeCfg.OneChannleCfg.get(j).szValueType.toUpperCase().equals("S"))//P是一次值 S是二次值 + { + if (ComtradeCfg.OneChannleCfg.get(j).szUnitName.toUpperCase().equals("KV"))//判断单位是V还是kV + { + fValue = fValue * 1000.0f; + } else { + fValue = fValue; + } + } else if (ComtradeCfg.OneChannleCfg.get(j).szValueType.toUpperCase().equals("P"))//P是一次值 S是二次值 + { + if (ComtradeCfg.OneChannleCfg.get(j).szUnitName.toUpperCase().equals("V"))//判断单位是V还是kV + { + if (ComtradeCfg.OneChannleCfg.get(j).fPrimary != 0.0f)//根据cfg内的变比,将一次值转换成二次值 + { + fValue = fValue * ComtradeCfg.OneChannleCfg.get(j).fSecondary / ComtradeCfg.OneChannleCfg.get(j).fPrimary; + } else { + fValue = fValue; + } + } else if (ComtradeCfg.OneChannleCfg.get(j).szUnitName.toUpperCase().equals("KV"))//判断单位是V还是kV + { + if (ComtradeCfg.OneChannleCfg.get(j).fPrimary != 0.0f)//根据cfg内的变比,将一次值转换成二次值 + { + fValue = fValue * 1000.0f * ComtradeCfg.OneChannleCfg.get(j).fSecondary / ComtradeCfg.OneChannleCfg.get(j).fPrimary; + } else { + fValue = fValue; + } + } else //还有可能是电流,单位是A + { + if (ComtradeCfg.OneChannleCfg.get(j).fPrimary != 0.0f)//根据cfg内的变比,将一次值转换成二次值 + { + fValue = ComtradeCfg.OneChannleCfg.get(j).fSecondary / ComtradeCfg.OneChannleCfg.get(j).fPrimary; + } else { + fValue = fValue; + } + } + } + + //ComtradeCfg.OneChannleCfg.get(j) + + //xValue前移量,假如是第一次时候则需要前移 + if (!blxValue && j == 0) { + xValueAll = (float) (i * 20) / RatesCfg.OneRate.get(nIndex).nOneSample - iPush; + blxValue = true; + //只增加一个xValue的值 + tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);//增加时间值 + } else if (j == 0) { + xValueAll += (float) nWaveSpan * dfValue; + //只增加一个xValue的值 + tmpWaveData.add((float) (Math.round(xValueAll * 100)) / 100);//增加时间值 + } + + //不同通道yValue的值都需要增加,最终成ABC三相 + tmpWaveData.add((float) (Math.round(fValue * 100)) / 100);//每个通道的值 + } + listWaveData.add(tmpWaveData);//把每个单独的值赋予到整体里面去 + } + } + } catch (Exception e) { + logger.error("读取文件出错:" + e.getMessage()); + return listWaveData; + }finally { + + } + + return listWaveData; + } + + /********************************* + * 根据波形数据算出rms值数据 + * param tmplistwave 瞬时波形数据 + * List> 返回RMS波形 + **********************************/ + @SuppressWarnings("unused") + public List> showValidData(List> tmplistwave) { + List> listRms = new ArrayList<>();//返回rms的值 + + float fs = nOneWaveNum; + int nWaveNum = (int) nAllWaveNum; + + int HalfTs = (int) fs;// 全波有效值 (int)fs / 2;//半波有效值 + // 计算有效值算法 + /********************************* + * modify by yexibao 2020-10-29 + * 增加多波形算法 ---------start + ********************************/ + double iWave = 0; + if (tmplistwave.size() > 0) { + //ComtradeCfg.nAnalogNum为值的个数(-1的原因是一个存的是时间) + iWave = Math.floor((tmplistwave.get(0).size() - 1) / ComtradeCfg.nPhasic); + List tmpListRms; + //每一项一项计算 + for (int j = 0; j < iWave; j++) { + double fSumA = 0.0, fSumB = 0.0, fSumC = 0.0; + double fValidA = 0.0, fValidB = 0.0, fValidC = 0.0; + //循环原始数据 + for (int i = 0; i < tmplistwave.size(); i++) { + // 当第一次循环的时候实例化,其余的获取已有的List + List tmpListValue = tmplistwave.get(i); //获取每一项的值 + if (j == 0) { + tmpListRms = new ArrayList<>(); + tmpListRms.add(tmpListValue.get(0));//获取时间 + listRms.add(tmpListRms); + } else { + tmpListRms = listRms.get(i); + } + + //包含了时间、电压(A、B、C)三相、电流(A、B、C)三相 + if (tmpListValue.size() >= 2) { + //电压有效值算法,根据相别进行处理 + switch (ComtradeCfg.nPhasic) { + case 1: + fSumA += Math.pow(tmpListValue.get(1 + ComtradeCfg.nPhasic * j), 2); + if (i >= HalfTs)// 计算有效值 + { + List forwardListValue = tmplistwave.get(i - HalfTs);//获取前推周波的值 + fSumA -= Math.pow(forwardListValue.get(1 + ComtradeCfg.nPhasic * j), 2); + } + fValidA = Math.sqrt(fSumA / HalfTs); + + tmpListRms.add((float) fValidA); + listRms.set(i, tmpListRms); + break; + case 2: + fSumA += Math.pow(tmpListValue.get(1 + ComtradeCfg.nPhasic * j), 2); + fSumB += Math.pow(tmpListValue.get(2 + ComtradeCfg.nPhasic * j), 2); + if (i >= HalfTs)// 计算有效值 + { + List forwardListValue = tmplistwave.get(i - HalfTs);//获取前推周波的值 + fSumA -= Math.pow(forwardListValue.get(1 + ComtradeCfg.nPhasic * j), 2); + fSumB -= Math.pow(forwardListValue.get(2 + ComtradeCfg.nPhasic * j), 2); + } + fValidA = Math.sqrt(fSumA / HalfTs); + fValidB = Math.sqrt(fSumB / HalfTs); + + tmpListRms.add((float) fValidA); + tmpListRms.add((float) fValidB); + listRms.set(i, tmpListRms); + break; + case 3: + fSumA += Math.pow(tmpListValue.get(1 + ComtradeCfg.nPhasic * j), 2); + fSumB += Math.pow(tmpListValue.get(2 + ComtradeCfg.nPhasic * j), 2); + fSumC += Math.pow(tmpListValue.get(3 + ComtradeCfg.nPhasic * j), 2); + if (i >= HalfTs)// 计算有效值 + { + List forwardListValue = tmplistwave.get(i - HalfTs);//获取前推周波的值 + fSumA -= Math.pow(forwardListValue.get(1 + ComtradeCfg.nPhasic * j), 2); + fSumB -= Math.pow(forwardListValue.get(2 + ComtradeCfg.nPhasic * j), 2); + fSumC -= Math.pow(forwardListValue.get(3 + ComtradeCfg.nPhasic * j), 2); + } + fValidA = Math.sqrt(fSumA / HalfTs); + fValidB = Math.sqrt(fSumB / HalfTs); + fValidC = Math.sqrt(fSumC / HalfTs); + + tmpListRms.add((float) fValidA); + tmpListRms.add((float) fValidB); + tmpListRms.add((float) fValidC); + listRms.set(i, tmpListRms); + break; + } + } + } + } + } + //过滤前一个周波 + //HalfTs表示一个周波 + try { + for (int i = 0; i < HalfTs; i++) { + //电压有效值算法 + List tmpListRms = new ArrayList<>();//没相具体的值 + for (int j = 0; j < iWave; j++) { + if (j == 0) { + tmpListRms.add(listRms.get(i).get(0));//获取时间 + } + + switch (ComtradeCfg.nPhasic) { + case 1: + tmpListRms.add(listRms.get(i + HalfTs).get(1 + ComtradeCfg.nPhasic * j)); + break; + case 2: + tmpListRms.add(listRms.get(i + HalfTs).get(1 + ComtradeCfg.nPhasic * j)); + tmpListRms.add(listRms.get(i + HalfTs).get(2 + ComtradeCfg.nPhasic * j)); + break; + case 3: + tmpListRms.add(listRms.get(i + HalfTs).get(1 + ComtradeCfg.nPhasic * j)); + tmpListRms.add(listRms.get(i + HalfTs).get(2 + ComtradeCfg.nPhasic * j)); + tmpListRms.add(listRms.get(i + HalfTs).get(3 + ComtradeCfg.nPhasic * j)); + break; + } + } + listRms.set(i, tmpListRms);//重新赋值 + } + } catch (Exception e) { + logger.error("更改收个周波值出错"); + } + return listRms; + } + + /*public static void main(String[] args) { + AnalyWave analyWave = new AnalyWave(); + AnalyWaveModel.tagDataValue realWave = analyWave.readComtrade("C:\\Users\\DELL\\Desktop\\hikvision\\1_20230426_153245_471.cfg", null, 1);//获取原始波形值 + //List> realWave = analyWave.readComtrade("C:\\Users\\Lenovo\\Desktop\\Comtrade\\waveTemp9200\\192.168.10.128\\1_20200927_135822_644.CFG", null, 0);//获取原始波形值 + List> result1=analyWave.showValidData(realWave.getListWaveData()); + realWave.getListWaveData(); + *//******************************************************** + * iFlag == 0 高级算法的要求,采样率只能是32-128 + * iFlag == 1 普通展示,采样率按照cfg里面最小的(大于32) + * iFlag == 2 App抽点要求,采样率抽点成32 + * iFlag == 3 高级算法原始波形(大于32) + ********************************************************//* + List> result = analyWave.getEigenvalue(realWave.getListWaveData(), true); + List> result2 = analyWave.getEigenvalue(realWave.getListWaveData(), true); + + }*/ + + /***************************** + *获取暂降特征值,包含离线 + ** ** strFilePath *** cfg文件路径 + *** auth *** 读取方式 null则使用本地读取方式读取 + *****************************/ + public List> getEigenvalue(List> realWave, boolean iFlag) { + List> result = null;//返回值 + if (realWave.size() > 0) { + //获取突变量和rms值 + if (GetAnaylseValue(realWave)) { + if (listRms_Offline.size() > 0 && listTBL_Offline.size() > 0) { + result = GetEventValue(realWave, listTBL_Offline, listRms_Offline, (int) nOneWaveNum, iFlag); + if (result.size() == 3) { + if ((result.get(0).get(1) > 0.9 && result.get(0).get(1) < 1.1) && (result.get(1).get(1) > 0.9 && result.get(1).get(1) < 1.1) && + (result.get(2).get(1) > 0.9 && result.get(2).get(1) < 1.1)) { + result = GetEventValue(realWave, listTBL_Offline, listRms_Offline, (int) nOneWaveNum, iFlag); + } +// //第五行显示电压PU +// //String strDes = TimeTrige.ToString("yyyy-MM-dd HH:mm:ss.fff"); +// String strDes = ""; +// if (result.get(0).get(1) <= 0.9 || result.get(1).get(1) <= 0.9 || result.get(2).get(1) <= 0.9) +// strDes += "事件类型:暂降事件 "; +// else if (result.get(0).get(1) <= 0.05 || result.get(1).get(1) <= 0.05 || result.get(2).get(1) <= 0.05) +// strDes += "事件类型:中断事件 "; +// else if (result.get(0).get(1) >= 1.1 || result.get(1).get(1) >= 1.1 || result.get(2).get(1) >= 1.1) +// strDes += "事件类型:暂升事件 "; +// for (int iTemp = 0; iTemp < 3; iTemp++) { +// String strPhasic = "A相"; +// switch (iTemp) { +// case 0: +// strPhasic = "A相"; +// break; +// case 1: +// strPhasic = "B相"; +// break; +// case 2: +// strPhasic = "C相"; +// break; +// } +// String strType = ""; +// if (result.get(iTemp).get(1) <= 0.05) +// strType = "电压中断"; +// else if (result.get(iTemp).get(1) <= 0.9) +// strType = "电压暂降"; +// else if (result.get(iTemp).get(1) >= 1.1) +// strType = "电压暂升"; +// if (strType != "") { +// strDes +="暂降事件:"+ strPhasic + strType + ",运行电压:" + result.get(iTemp).get(2) + "V,残余电压:" + result.get(iTemp).get(2) + +// "V,残余电压(百分比):" + result.get(iTemp).get(1) * 100.0f + "%,持续时间:" + result.get(iTemp).get(1) + "毫秒; "; +// } +// } + } + } + } + } + return result; + } + + /********************************* + * 离线波形导入时获取突变量算法 + * param tmpListWave 波形原始数据 + **********************************/ + private List> listRms_Offline;//离线数据RMS有效值数据 + private List> listTBL_Offline;//离线数据突变量数据 + private double fMinMagA = 0; + private double fMinMagB = 0; + private double fMinMagC = 0; + + public Boolean GetAnaylseValue(List> realWave) { + boolean blFlag = true; + //实例化 + listRms_Offline = new ArrayList<>(); + listTBL_Offline = new ArrayList<>(); + + float fs = nOneWaveNum; + int nWaveNum = (int) nAllWaveNum; + + // 计算有效值 + double fSumA = 0.0, fSumB = 0.0, fSumC = 0.0; + double fValidA = 0.0, fValidB = 0.0, fValidC = 0.0; + fMinMagA = 99999; + fMinMagB = 99999; + fMinMagC = 99999; + double fValue = 0.0; + int HalfTs = (int) fs;// 全波有效值 ; (int)fs / 2;//半波有效值 + //瞬时波形数据_瞬时 + List tmpRealValue; + //获取前推周波的值_瞬时 + List forwardRealValue; + //获取前推周波的值_突变量 + List tblValue; + //获取前推周波的值_突变量 + List forwardTblValue; + + // 计算有效值算法 + for (int i = 0; i < realWave.size(); i++) { + //获取每一项的值 + tmpRealValue = realWave.get(i); + //包含了时间、A、B、C三相 + if (tmpRealValue.size() >= 4) { + fSumA += Math.pow(tmpRealValue.get(1), 2); + fSumB += Math.pow(tmpRealValue.get(2), 2); + fSumC += Math.pow(tmpRealValue.get(3), 2); + // 计算有效值 + List tmpRmsValue = new ArrayList<>(); + if (i >= fs) { + forwardRealValue = realWave.get(i - HalfTs); + fSumA -= Math.pow(forwardRealValue.get(1), 2); + fSumB -= Math.pow(forwardRealValue.get(2), 2); + fSumC -= Math.pow(forwardRealValue.get(3), 2); + } + // 计算突变量值 + List tmpTblValue = new ArrayList<>(); + tmpTblValue.add(tmpRealValue.get(0));//获取时间 + if (i >= HalfTs) { + tblValue = realWave.get(i);//获取前推周波的值 + forwardTblValue = realWave.get(i - HalfTs);//获取前推周波的值 + tmpTblValue.add(tblValue.get(1) - forwardTblValue.get(1)); + tmpTblValue.add(tblValue.get(2) - forwardTblValue.get(2)); + tmpTblValue.add(tblValue.get(3) - forwardTblValue.get(3)); + } else { + tmpTblValue.add(0f); + tmpTblValue.add(0f); + tmpTblValue.add(0f); + } + fValidA = Math.sqrt(fSumA / HalfTs); + fValidB = Math.sqrt(fSumB / HalfTs); + fValidC = Math.sqrt(fSumC / HalfTs); + + if (i >= fs) { + if (fValidA < fMinMagA) { + fMinMagA = fValidA; + } + if (fValidB < fMinMagB) { + fMinMagB = fValidB; + } + if (fValidC < fMinMagC) { + fMinMagC = fValidC; + } + } + //RMS获取 + tmpRmsValue.add(tmpRealValue.get(0));//获取时间 + tmpRmsValue.add((float) fValidA); + tmpRmsValue.add((float) fValidB); + tmpRmsValue.add((float) fValidC); + listRms_Offline.add(tmpRmsValue); + + //RMS获取 + listTBL_Offline.add(tmpTblValue); + } + } + return blFlag; + } + + /********************************* + * 离线波形导入时获取暂降特征值的算法 + * List> 返回暂降数据 + **********************************/ + private List> GetEventValue(List> realWave, List> tblWave, List> rmstWave, int nCirclePoint, boolean blFlag) { + //额定电压 + float fBase = 57.74f; + //假如所选的是380V,那么PT变比是1:1,因此额定电压要选220 + if (ComtradeCfg.OneChannleCfg.size() > 0) { + if (ComtradeCfg.OneChannleCfg.get(0).fPrimary / ComtradeCfg.OneChannleCfg.get(0).fSecondary <= 1) { + fBase = 220f; + } + } + //采样率 + int nSJ = nCirclePoint; + /********************************* + * 0是特征幅值(残余电压百分比) + * 1是特征幅值(残余电压) + * 2额定定压(动态电压) + * 3是持续时间 + **********************************/ + List> listEventValue = new ArrayList<>();//ABC三相分析结果 + for (int i = 0; i < 3; i++) { + int iDDY = 0, iGDY = 0;//低电压和郭电压标识值 + List tmpListEventValue = new ArrayList<>();//某一项分析结果 + iDDY = App_Disturb_DDY1(realWave, tblWave, rmstWave, nSJ, i, blFlag); + if (Disturb_Val == 0 && Disturb_SJ == 0) { + //判断A相的暂态事件类型是否为短时中断或电压暂降 + iGDY = App_Disturb_GDY1(realWave, tblWave, rmstWave, nSJ, i, blFlag); + if (iGDY != 0) { + if (Disturb_Val != 0) { + if (blFlag) { + tmpListEventValue.add(Disturb_Val / rmstWave.get(nSJ + 2).get(i + 1));//征幅值(残余电压百分比) + tmpListEventValue.add(Disturb_Val);//特征幅值(残余电压) + tmpListEventValue.add(rmstWave.get(nSJ + 2).get(i + 1));//额定定压(动态电压) + } else { + tmpListEventValue.add(Disturb_Val / 57.74f);//征幅值(残余电压百分比) + tmpListEventValue.add(Disturb_Val);//特征幅值(残余电压) + tmpListEventValue.add(57.74f);//额定定压(动态电压) + } + } + } else//如果都没有找到,那么需要从曲线里面找出比较小的值来计算 + { + double rate = 0f; + double residualVoltage = 0.f;//残余电压 + switch (i) { + case 0: + residualVoltage = fMinMagA; + break; + case 1: + residualVoltage = fMinMagB; + break; + case 2: + residualVoltage = fMinMagC; + break; + } + + if (residualVoltage != -1) { + rate = residualVoltage / fBase > 1 ? 1.0f : residualVoltage / fBase; + } + tmpListEventValue.add((float) rate);//征幅值(残余电压百分比) + tmpListEventValue.add((float) residualVoltage);//特征幅值(残余电压) + tmpListEventValue.add(fBase);//额定定压(动态电压) + } + } else { + if (Disturb_Val != 0) { + if (Disturb_Val != 0) { + if (blFlag) { + tmpListEventValue.add(Disturb_Val / rmstWave.get(nSJ + 2).get(i + 1));//征幅值(残余电压百分比) + tmpListEventValue.add(Disturb_Val);//特征幅值(残余电压) + tmpListEventValue.add(rmstWave.get(nSJ + 2).get(i + 1));//额定定压(动态电压) + } else { + tmpListEventValue.add(Disturb_Val / 57.74f);//征幅值(残余电压百分比) + tmpListEventValue.add(Disturb_Val);//特征幅值(残余电压) + tmpListEventValue.add(57.74f);//额定定压(动态电压) + } + } + } + } + tmpListEventValue.add(Disturb_SJ / nSJ * 20.0f);//持续时间 + listEventValue.add(tmpListEventValue); + } + return listEventValue; + } + + private float Disturb_Val = 0;//暂降幅值 + private double Disturb_Time = 0;//持续时间 + private float Disturb_SJ = 0;//暂态启动点号 + + private float Un09 = (0.90f * 57.74f);//暂降幅值90% + private float Un002 = (0.02f * 57.74f);//暂降幅值2% + private float Un110 = (1.10f * 57.74f);//暂降幅值110% + + /************************************ + *低电压的判据 包含了暂降和中断 + * @param realWave 原始波形数据 + * @param tblWave 突变量波形数据 + * @param rmstWave RMS波形数据 + * @param nCirclePoint 采样率 + * @param nType 类别 0:A相,1:B相,2:C相 + * @param blFlag 浮动门槛和固定门槛 + * @return + *************************************/ + private int App_Disturb_DDY1(List> realWave, List> tblWave, List> rmstWave, int nCirclePoint, int nType, boolean blFlag) { + Disturb_Val = 0; + Disturb_Time = 0; + Disturb_SJ = 0; + + /**************************** + * ADC 临时的突变量判据 + * Disturb_JS_Val 事件启动点时刻的有效值 + ****************************/ + double temp, ADC, Disturb_JS_Val = 0; + int iTbl = 0; + long Disturb_QD = 0; + //nSJ就是全波的采样率,nHalfSJ是半波的采样率 + int nSJ = nCirclePoint, nHalfSJ = nCirclePoint / 2; + //定义90%和20%额定电压 + float fUN09 = Un09, fUN002 = Un002; + //增加浮动门槛判断 + if (blFlag) { + /**************************** + * 计算值去掉一个前一个周波后 + * 取第二个周波的第二个有效值 + * 第一个值是时间、A,B,C三相 + ****************************/ + if (rmstWave.size() > nSJ + 2) { + fUN09 = rmstWave.get(nSJ + 2).get(nType + 1) * 0.9f; + fUN002 = rmstWave.get(nSJ + 2).get(nType + 1) * 0.02f; + } + } + /**************************** + * 从第二个周波开始 + ****************************/ + for (int i = nSJ; i < realWave.size(); i++) { + //获取RMS有效值 + float rmsValue = rmstWave.get(i).get(nType + 1); + //电压扰动启动判别 + if (Disturb_QD == 0) { + //有效值小于90% + if (rmsValue < fUN09) { + Disturb_QD = 0xff; + Disturb_Val = rmsValue; + Disturb_JS_Val = rmsValue; + //寻找突变点 + for (int j = 0; j < nHalfSJ; j++) { + //临时的突变量 + ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1); + //临时的突变量小于0时候取绝对值 + if (ADC < 0) { + ADC = 0 - ADC; + } + if (ADC > fUN002) { + Disturb_SJ += (nHalfSJ - j); + iTbl = (int) (i - nHalfSJ + j); + break; + } + } + } + } + //电压扰动返回判别 + else { + if (rmsValue < (fUN09 + fUN002)) { + Disturb_SJ++; + if (Disturb_Val > rmsValue) { + Disturb_Val = rmsValue; + } + Disturb_JS_Val = rmsValue; + } else { + if (Disturb_SJ >= (nSJ + nHalfSJ)) { + //20%突变量标志 + int iFlag = 0; + for (int j = 0; j < nHalfSJ; j++) { + iFlag = j; + //临时的突变量 + ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1); + //临时的突变量小于0时候取绝对值 + if (ADC < 0) { + ADC = 0 - ADC; + } + if (ADC > fUN002) { + break; + } + } + Disturb_SJ -= (nHalfSJ - iFlag); + Disturb_Time = ((double) Disturb_SJ) * 20 / nSJ; + return iTbl; + } else { + Disturb_SJ++; + ADC = realWave.get(i).get(nType + 1); + if (ADC < 0) { + ADC = 0 - ADC; + } + temp = rmsValue - Disturb_JS_Val; + if (temp < 0) { + temp = 0 - temp; + } + if ((ADC > 100) && (temp < 0.1)) { + Disturb_SJ -= (nHalfSJ + 1); + Disturb_Time = ((double) Disturb_SJ) * 20 / nSJ + 1; + return iTbl; + } + } + Disturb_JS_Val = rmsValue; + } + } + } + return iTbl; + } + + /************************************ + *过电压的判据 + * @param realWave 原始波形数据 + * @param tblWave 突变量波形数据 + * @param rmstWave RMS波形数据 + * @param nCirclePoint 采样率 + * @param nType 类别 0:A相,1:B相,2:C相 + * @param blFlag 浮动门槛和固定门槛 + * @return + *************************************/ + private int App_Disturb_GDY1(List> realWave, List> tblWave, List> rmstWave, int nCirclePoint, int nType, boolean blFlag) { + Disturb_Val = 0; + Disturb_Time = 0; + Disturb_SJ = 0; + + /**************************** + * ADC 临时的突变量判据 + * Disturb_JS_Val 事件启动点时刻的有效值 + ****************************/ + double temp, ADC, Disturb_JS_Val = 0; + int iTbl = 0; + long Disturb_QD = 0; + //nSJ就是全波的采样率,nHalfSJ是半波的采样率 + int nSJ = nCirclePoint, nHalfSJ = nCirclePoint / 2; + //定义110%和20%额定电压 + float fUN110 = Un110, fUN002 = Un002; + //增加浮动门槛判断 + if (blFlag) { + /**************************** + * 计算值去掉一个前一个周波后 + * 取第二个周波的第二个有效值 + * 第一个值是时间、A,B,C三相 + ****************************/ + if (rmstWave.size() > nSJ + 2) { + fUN110 = rmstWave.get(nSJ + 2).get(nType + 1) * 1.1f; + fUN002 = rmstWave.get(nSJ + 2).get(nType + 1) * 0.02f; + } + } + /**************************** + * 从第二个周波开始 + ****************************/ + for (int i = nSJ; i < realWave.size(); i++) { + //获取RMS有效值 + float rmsValue = rmstWave.get(i).get(nType + 1); + //电压扰动启动判别 + if (Disturb_QD == 0) { + if (rmsValue > fUN110) { + Disturb_QD = 0xff; + Disturb_Val = rmsValue; + Disturb_JS_Val = rmsValue; + //寻找突变点 + for (int j = 0; j < nHalfSJ; j++) { + //临时的突变量 + ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1); + //临时的突变量小于0时候取绝对值 + if (ADC < 0) { + ADC = 0 - ADC; + } + if (ADC > fUN002) { + Disturb_SJ += (nHalfSJ - j); + iTbl = (int) (i - nHalfSJ + j); + break; + } + } + } + } + //电压扰动返回判别 + else { + if (rmsValue > (fUN110 - fUN002)) { + Disturb_SJ++; + if (Disturb_Val < rmsValue) { + Disturb_Val = rmsValue; + } + Disturb_JS_Val = rmsValue; + } else { + if (Disturb_SJ >= (nSJ + nHalfSJ)) { + int iFlag = 0; + for (int j = 0; j < nHalfSJ; j++) { + iFlag = j; + ADC = tblWave.get(i - nHalfSJ + j).get(nType + 1); + if (ADC < 0) { + ADC = 0 - ADC; + } + if (ADC > fUN002) { + break; + } + } + Disturb_SJ -= (nHalfSJ - iFlag); + Disturb_Time = (double) Disturb_SJ * 20 / nSJ; + return iTbl; + } else { + Disturb_SJ++; + ADC = realWave.get(i).get(nType + 1); + if (ADC < 0) { + ADC = 0 - ADC; + } + temp = rmsValue - Disturb_JS_Val; + if (temp < 0) { + temp = 0 - temp; + } + if ((ADC > 100) && (temp < 0.1)) { + Disturb_SJ -= (nHalfSJ + 1); + Disturb_Time = Disturb_SJ * 20 / nSJ + 1; + return iTbl; + } + } + Disturb_JS_Val = rmsValue; + } + } + } + return iTbl; + } + + + /********************************* + * 获取最小采样率方法 + * @param OneRate cfg中关于采样率参数 + * @return 返回最小采样率 + **********************************/ + private long MinWaveSample(List OneRate) { + long nMinOneSample = OneRate.get(0).nOneSample; + for (int i = 0; i < OneRate.size(); i++) { + if (OneRate.get(i).nOneSample >= 32) { + if (nMinOneSample > OneRate.get(i).nOneSample) { + nMinOneSample = OneRate.get(i).nOneSample; + } + } + } + return nMinOneSample; + } + +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/AnalyWaveModel.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/AnalyWaveModel.java new file mode 100644 index 000000000..e9e240460 --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/AnalyWaveModel.java @@ -0,0 +1,200 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + +import java.util.LinkedList; +import java.util.List; + +public class AnalyWaveModel { + + /******************************** + * 解析Comtrate文件相关实体类 + * @author yexb 转ww C#代码 + **********************************/ + + // 模拟量通道记录类 + public static class tagOneChannleCfg { + // 通道序号 + public int nIndex; + // 通道名称 + public String szChannleName; + // 相位名称 + public String szPhasicName; + // 监视的通道名称 + public String szMonitoredChannleName; + // 通道的单位 + public String szUnitName; + // 通道的系数 + public float fCoefficent; + // 通道的便宜量 + public float fOffset; + // 起始采样时间的偏移量 + public float fTimeOffset; + // 采样值的最小值 + public int nMin; + // 采样值的最大值 + public int nMax; + // 一次变比 + public float fPrimary; + // 二次变比 + public float fSecondary; + // 一次值还是二次值标志 + public String szValueType; + } + + // 数字量通道记录类 + public static class tagOneChannleCfg_digital { + // 通道序号 + public int nIndex; + // 通道名称 + public String szChannleName; + // 相位名称 + public String szPhasicName; + // 监视的通道名称 + public String szMonitoredChannleName; + // 通道的单位 + public int Initial; + + } + + // 配置文件总类 + public static class tagComtradeCfg { + public int nChannelNum; + public int nPhasic;// 模拟量通道的个数 yexibao 2020-12-15 + public int nAnalogNum;// 模拟量通道的个数 WW 2013-05-15 + public int nDigitalNum;// 数字量通道的个数 WW 2013-05-15 + public List OneChannleCfg; + public List OneChannleCfgDig; + + public tagComtradeCfg() { + OneChannleCfg = new LinkedList(); + OneChannleCfgDig = new LinkedList(); + } + } + + public static class tagOneRate{ + // 1秒钟内的采样点数 + public long nOneSample; + // 总采样点数 + public long nSampleNum; + } + + // 采样总结构 + public static class tagRates { + public int nRates; + public List OneRate; + + public tagRates() { + OneRate = new LinkedList(); + } + } + + // 采样值结构 + public static class tagOneValue { + // 数据点时间 + public String szTime; + // 数据点序号 + public int nIndex; + // int nValueNum; WW 2013-05-15 + // 模拟量数据个数 + public int nAnalogValueNum; + // 数字量数据个数 + public int nDigitalValueNum; + // 数据区 + // float fValue[8]; + public List fValue;// WW 2013-05-15 原来的8通道也是仅考虑了单路的情况,如果遇到多路这里会超出 + public List DigitalValue;// WW 2013-05-15 + + public tagOneValue() { + fValue = new LinkedList(); + DigitalValue = new LinkedList(); + } + } + + // 采样值总结构 + public static class tagValue { + // 数据个数 + public int nValueNum; + // 数据区 + public List OneValueList; + + public tagValue() { + OneValueList = new LinkedList(); + } + } + + public static class tagWave { + // 标识 1-二次值的事件波形 2-二次值的RMS 3-一次值的事件波形 4-一次值的RMS + //标识 5-二次值的事件波形 6-二次值的RMS 7-一次值的事件波形 8-一次值的RMS + private int type; + // 相别 + private int phaseType;// 0:A相;1:B相;2:c相 + // X坐标值 + private int xvalue; + // y坐标值 + private float yvalue; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public int getPhaseType() { + return phaseType; + } + + public void setPhaseType(int phaseType) { + this.phaseType = phaseType; + } + + public int getXvalue() { + return xvalue; + } + + public void setXvalue(int xvalue) { + this.xvalue = xvalue; + } + + public float getYvalue() { + return yvalue; + } + + public void setYvalue(float yvalue) { + this.yvalue = yvalue; + } + } + //增加返回值描述 + public static class tagDataValue { + //波形对应的标题 + private List tmpWaveTitle; + //波形对应的值 + private List> listWaveData; + //波形对应的相别数量 + private int iPhasic; + + public List getTmpWaveTitle() { + return tmpWaveTitle; + } + + public void setTmpWaveTitle(List tmpWaveTitle) { + this.tmpWaveTitle = tmpWaveTitle; + } + + public List> getListWaveData() { + return listWaveData; + } + + public void setListWaveData(List> listWaveData) { + this.listWaveData = listWaveData; + } + + public int getiPhasic() { + return iPhasic; + } + + public void setiPhasic(int iPhasic) { + this.iPhasic = iPhasic; + } + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/BackData.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/BackData.java new file mode 100644 index 000000000..bbf46f5e4 --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/BackData.java @@ -0,0 +1,94 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + +import com.sun.jna.Structure; + +import java.util.Arrays; +import java.util.List; + +/** + * 输出参数 + * qvvr_cata_cause 暂降原因(目前算法不支持,不填) + * qvvr_phasetype 暂降相别 1:一相 2:两相 3:三相 + * qvvr_cata_type 暂降类型 + * 持续时间(单位秒) + * hold_time_rms 有效值算法持续时间 + * hold_time_dq dq变换算法持续时间 + * 波形起始点(单位度) + * POW_a A相波形起始点 + * POW_b B相波形起始点 + * POW_c C相波形起始点 + * 跳变段电压变化率(单位V/S) + * Voltagechange_Va A相跳变段电压变化率 + * Voltagechange_Vb B相跳变段电压变化率 + * Voltagechange_Vc C相跳变段电压变化率 + * 分段信息 + * SEG_T_num 分段数目 + * SEG_T0_idx 原始分段位置 + * SEG_T_idx 修正分段位置 + * 有效值分段信息 + * SEG_RMS_T_num 分段数目 + * SEG_RMS_T_idx 分段位置 + * 特征幅值(单位V) + * u_min_num 特征值个数 + * ua_min A相电压特征值 + * ub_min B相电压特征值 + * uc_min C相电压特征值 + * u3_min 三相电压特征值 + * order_min_idx 最小值位置 + * 相位跳变(单位度) + * angle_diff_ap A相相位正跳变 + * angle_diff_bp B相相位正跳变 + * angle_diff_cp C相相位正跳变 + * angle_diff_an A相相位负跳变 + * angle_diff_bn B相相位负跳变 + * angle_diff_cn C相相位负跳变 + * bph_max_value 不平衡度(单位%) + */ +public class BackData extends Structure { + public int qvvr_cata_cause[] = new int[256]; + public int qvvr_phasetype[] = new int[256]; + public int qvvr_cata_type[] = new int[256]; + public float hold_time_rms; + public float hold_time_dq; + public float POW_a; + public float POW_b; + public float POW_c; + public float Voltagechange_Va; + public float Voltagechange_Vb; + public float Voltagechange_Vc; + public int SEG_T_num; + public int SEG_T0_idx[] = new int[256]; + public int SEG_T_idx[] = new int[256]; + public int SEG_RMS_T_num; + public int SEG_RMS_T_idx[] = new int[256]; + public int u_min_num; + public float ua_min[] = new float[256]; + public float ub_min[] = new float[256]; + public float uc_min[] = new float[256]; + public float u3_min[] = new float[256]; + public int order_min_idx[] = new int[256]; + public float angle_diff_ap[] = new float[256]; + public float angle_diff_bp[] = new float[256]; + public float angle_diff_cp[] = new float[256]; + public float angle_diff_an[] = new float[256]; + public float angle_diff_bn[] = new float[256]; + public float angle_diff_cn[] = new float[256]; + public float bph_max_value[] = new float[256]; + + public static class ByReference extends BackData implements Structure.ByReference { + + } + + public static class ByValue extends BackData implements Structure.ByValue { + + } + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[] { "qvvr_cata_cause", "qvvr_phasetype", "qvvr_cata_type", "hold_time_rms", + "hold_time_dq", "POW_a", "POW_b", "POW_c", "Voltagechange_Va", "Voltagechange_Vb", "Voltagechange_Vc", + "SEG_T_num", "SEG_T0_idx", "SEG_T_idx","SEG_RMS_T_num","SEG_RMS_T_idx", "u_min_num", "ua_min", "ub_min", "uc_min", "u3_min", + "order_min_idx", "angle_diff_ap", "angle_diff_bp", "angle_diff_cp", "angle_diff_an", "angle_diff_bn", + "angle_diff_cn", "bph_max_value" }); + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/CauseStruct.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/CauseStruct.java new file mode 100644 index 000000000..c16248b08 --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/CauseStruct.java @@ -0,0 +1,30 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + +import com.sun.jna.Structure; + +import java.util.Arrays; +import java.util.List; + +public class CauseStruct extends Structure { + //最大能容纳的数据 + public static final int MAX_SMP_DATA_LEN = 128 * 50 * 120; + public float smp_va[] = new float[MAX_SMP_DATA_LEN]; + public float smp_vb[] = new float[MAX_SMP_DATA_LEN]; + public float smp_vc[] = new float[MAX_SMP_DATA_LEN]; + public int smp_rate; + public int smp_len; + public float threshold[] = new float[50]; + public int cause = 0; + public int no_cal = 0; + + public static class ByReference extends CauseStruct implements Structure.ByReference { + } + + public static class ByValue extends CauseStruct implements Structure.ByValue { + } + + @Override + protected List getFieldOrder() { // 返回值填入的顺序 + return Arrays.asList(new String[] { "cause", "no_cal" }); + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/DirectionData.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/DirectionData.java new file mode 100644 index 000000000..a4199bff2 --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/DirectionData.java @@ -0,0 +1,47 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + +public class DirectionData{ + private int trigTime[] = new int[256]; + private float qvvrBeforeRms[] = new float[256]; + private float qvvrBeforeZk[] = new float[256]; + private float qvvrOccurRms[] = new float[256]; + private float qvvrOccurZk[] = new float[256]; + private String qvvrPosInfo[] = new String[256]; + + public int[] getTrigTime() { + return trigTime; + } + public void setTrigTime(int[] trigTime) { + this.trigTime = trigTime; + } + public float[] getQvvrBeforeRms() { + return qvvrBeforeRms; + } + public void setQvvrBeforeRms(float[] qvvrBeforeRms) { + this.qvvrBeforeRms = qvvrBeforeRms; + } + public float[] getQvvrBeforeZk() { + return qvvrBeforeZk; + } + public void setQvvrBeforeZk(float[] qvvrBeforeZk) { + this.qvvrBeforeZk = qvvrBeforeZk; + } + public float[] getQvvrOccurRms() { + return qvvrOccurRms; + } + public void setQvvrOccurRms(float[] qvvrOccurRms) { + this.qvvrOccurRms = qvvrOccurRms; + } + public float[] getQvvrOccurZk() { + return qvvrOccurZk; + } + public void setQvvrOccurZk(float[] qvvrOccurZk) { + this.qvvrOccurZk = qvvrOccurZk; + } + public String[] getQvvrPosInfo() { + return qvvrPosInfo; + } + public void setQvvrPosInfo(String[] qvvrPosInfo) { + this.qvvrPosInfo = qvvrPosInfo; + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/EntityAdvancedData.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/EntityAdvancedData.java new file mode 100644 index 000000000..5a554eda9 --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/EntityAdvancedData.java @@ -0,0 +1,39 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + +import lombok.Data; + +/** + * @author njcn + * @高级算法返回数据 + * @包含RMS值 + * @X轴坐标 + * @处理返回的结果 + */ +@Data +public class EntityAdvancedData { + public float smp_a[]; + public float smp_b[]; + public float smp_c[]; + public float smp_x[]; + public int smp_len; + public String sagReason[]; // 暂降原因描述,数据库获取 + public String sagType[]; // 暂降类型描述,数据库获取 + public String sagPhaseType[]; // 暂降相别 1-一相 2-两相 3-三相 + public int backNumber = -1; + public BackData evt_buf[]; + public PowerData power_before_buf[]; + public PowerData power_after_buf[]; + public DirectionData qvvr_direction_info[]; + public UtblData qvvr_utbl_info[]; + + public EntityAdvancedData(int lengthRMS) { + super(); + this.smp_a = new float[lengthRMS]; + this.smp_b = new float[lengthRMS]; + this.smp_c = new float[lengthRMS]; + this.smp_x = new float[lengthRMS]; + this.sagReason = new String[256]; + this.sagType = new String[256]; + this.sagPhaseType = new String[256]; + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/PowerData.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/PowerData.java new file mode 100644 index 000000000..d49017a5c --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/PowerData.java @@ -0,0 +1,27 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + +public class PowerData{ + private float fundP[] = new float[256]; + private float fundQ[] = new float[256]; + private float fundS[] = new float[256]; + + public float[] getFundP() { + return fundP; + } + public void setFundP(float[] fundP) { + this.fundP = fundP; + } + public float[] getFundQ() { + return fundQ; + } + public void setFundQ(float[] fundQ) { + this.fundQ = fundQ; + } + public float[] getFundS() { + return fundS; + } + public void setFundS(float[] fundS) { + this.fundS = fundS; + } + +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/PubWaveModel.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/PubWaveModel.java new file mode 100644 index 000000000..a43e9605f --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/PubWaveModel.java @@ -0,0 +1,168 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + +import java.util.LinkedList; +import java.util.List; + +public class PubWaveModel { + + /************************ + * Comtrate文件相关 + * + * @author Yexb + * + **************************/ + + // 模拟量通道记录类 + public static class tagOneChannleCfg { + // 通道序号 + public int nIndex; + // 通道名称 + public String szChannleName; + // 相位名称 + public String szPhasicName; + // 监视的通道名称 + public String szMonitoredChannleName; + // 通道的单位 + public String szUnitName; + // 通道的系数 + public float fCoefficent; + // 通道的便宜量 + public float fOffset; + // 起始采样时间的偏移量 + public float fTimeOffset; + // 采样值的最小值 + public int nMin; + // 采样值的最大值 + public int nMax; + // 一次变比 + public float fPrimary; + // 二次变比 + public float fSecondary; + // 一次值还是二次值标志 + public String szValueType; + } + + // 数字量通道记录类 + public static class tagOneChannleCfg_digital { + // 通道序号 + public int nIndex; + // 通道名称 + public String szChannleName; + // 相位名称 + public String szPhasicName; + // 监视的通道名称 + public String szMonitoredChannleName; + // 通道的单位 + public int Initial; + + } + + // 配置文件总类 + public static class tagComtradeCfg { + public int nChannelNum; + public int nAnalogNum;// 模拟量通道的个数 WW 2013-05-15 + public int nDigitalNum;// 数字量通道的个数 WW 2013-05-15 + public List OneChannleCfg; + public List OneChannleCfgDig; + + public tagComtradeCfg() { + OneChannleCfg = new LinkedList(); + OneChannleCfgDig = new LinkedList(); + } + } + + public static class tagOneRate { + // 1秒钟内的采样点数 + public long nOneSample; + // 总采样点数 + public long nSampleNum; + } + + // 采样总结构 + public static class tagRates { + public int nRates; + public List OneRate; + + public tagRates() { + OneRate = new LinkedList(); + } + } + + // 采样值结构 + public static class tagOneValue { + // 数据点时间 + public String szTime; + // 数据点序号 + public int nIndex; + // int nValueNum; WW 2013-05-15 + // 模拟量数据个数 + public int nAnalogValueNum; + // 数字量数据个数 + public int nDigitalValueNum; + // 数据区 + // float fValue[8]; + public List fValue;// WW 2013-05-15 原来的8通道也是仅考虑了单路的情况,如果遇到多路这里会超出 + public List DigitalValue;// WW 2013-05-15 + + public tagOneValue() { + fValue = new LinkedList(); + DigitalValue = new LinkedList(); + } + } + + // 采样值总结构 + public static class tagValue { + // 数据个数 + public int nValueNum; + // 数据区 + public List OneValueList; + + public tagValue() { + OneValueList = new LinkedList(); + } + } + + public static class tagWave { + // 标识 1-二次值的事件波形 2-二次值的RMS 3-一次值的事件波形 4-一次值的RMS + //标识 5-二次值的事件波形 6-二次值的RMS 7-一次值的事件波形 8-一次值的RMS + private int type; + // 相别 + private int phaseType;// 0:A相;1:B相;2:c相 + // X坐标值 + private float xvalue; + // y坐标值 + private float yvalue; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public int getPhaseType() { + return phaseType; + } + + public void setPhaseType(int phaseType) { + this.phaseType = phaseType; + } + + public float getXvalue() { + return xvalue; + } + + public void setXvalue(float xvalue) { + this.xvalue = xvalue; + } + + public float getYvalue() { + return yvalue; + } + + public void setYvalue(float yvalue) { + this.yvalue = yvalue; + } + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/Rect.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/Rect.java new file mode 100644 index 000000000..b7e3ed46c --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/Rect.java @@ -0,0 +1,42 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + +import com.sun.jna.Structure; + +import java.util.Arrays; +import java.util.List; + +/** + * + * @author njcn + * 传入参数 + * smp_va A相电压波形数据 + * smp_vb B相电压波形数据 + * smp_vc C相电压波形数据 + * smp_rate 波形采样率 + * smp_len 每个通道波形数据个数 + * evt_num 高级算法返回事件个数 + * evt_buf 高级算法返回数据 + */ +public class Rect extends Structure { + public static final int MAX_SMP_DATA_LEN = 128*50*120; + public float smp_va[] = new float[MAX_SMP_DATA_LEN]; + public float smp_vb[] = new float[MAX_SMP_DATA_LEN]; + public float smp_vc[] = new float[MAX_SMP_DATA_LEN]; + public int smp_rate; + public int smp_len; + public int evt_num = -1; + public BackData evt_buf[] = new BackData[32]; + + public static class ByReference extends Rect implements Structure.ByReference { + + } + + public static class ByValue extends Rect implements Structure.ByValue { + + } + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[] { "evt_num","evt_buf" }); + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/UtblData.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/UtblData.java new file mode 100644 index 000000000..a528137ba --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/UtblData.java @@ -0,0 +1,13 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + +public class UtblData{ + private long trigTime[] = new long[1]; + + public long[] getTrigTime() { + return trigTime; + } + + public void setTrigTime(long[] trigTime) { + this.trigTime = trigTime; + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/WaveData.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/WaveData.java new file mode 100644 index 000000000..f38d25d4b --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/dto/waveAnalysis/WaveData.java @@ -0,0 +1,296 @@ +package com.njcn.advance.pojo.dto.waveAnalysis; + + + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author hongawen + * @Date: 2018/12/4 10:03 + */ +public class WaveData implements Serializable { + //标题数据 + private List tmpWaveTitle = new ArrayList<>(); + + //瞬时波形的数据 + List> sunData = new ArrayList<>(); + + //RMS波形的数据 + List> rmsData = new ArrayList<>(); + + //相别个数 + private int iPhasic = 0; + + //PT变比 + Float pt = 0.0f; + + //CT变比 + Float ct = 0.0f; + + private String a="A相"; + + private String b="B相"; + + private String c="C相"; + + //波形采样率 + private long nOneWaveNum = 32; + private Date firstTime;//暂降触发第一次 + private Integer firstMs; + + + //发生时刻 + String time; + + //暂降类型 + String waveType; + + //严重度 + float yzd; + + //监测点名称 + String lineName; + + //暂降幅值 + Float eventValue; + + //持续时间 + Float persistTime; + + //暂降触发时间 + private Date trigeTime; + + private boolean openTri=false; + + //最大最小值集合 + private List readComtrade = new ArrayList<>(); + + //变电站名称 + private String subName; + + + + public WaveData() { + iPhasic = 0; + } + + public AnalyWaveModel.tagRates getRatesCfg() { + return RatesCfg; + } + + public void setRatesCfg(AnalyWaveModel.tagRates ratesCfg) { + RatesCfg = ratesCfg; + } + + private AnalyWaveModel.tagRates RatesCfg;//cfg_采样率实体类 + + public List getReadComtrade() { + return readComtrade; + } + + public void setReadComtrade(List readComtrade) { + this.readComtrade = readComtrade; + } + + public List> getSunData() { + return sunData; + } + + public void setSunData(List> sunData) { + this.sunData = sunData; + } + + public List> getRmsData() { + return rmsData; + } + + public void setRmsData(List> rmsData) { + this.rmsData = rmsData; + } + + public Float getPt() { + return pt; + } + + public void setPt(Float pt) { + this.pt = pt; + } + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public String getWaveType() { + return waveType; + } + + public void setWaveType(String waveType) { + this.waveType = waveType; + } + + public float getYzd() { + return yzd; + } + + public void setYzd(float yzd) { + this.yzd = yzd; + } + + public Float getCt() { + return ct; + } + + public void setCt(Float ct) { + this.ct = ct; + } + + public long getnOneWaveNum() { + return nOneWaveNum; + } + + public void setnOneWaveNum(long nOneWaveNum) { + this.nOneWaveNum = nOneWaveNum; + } + + public Date getFirstTime() { + return firstTime; + } + + public void setFirstTime(Date firstTime) { + this.firstTime = firstTime; + } + + public Integer getFirstMs() { + return firstMs; + } + + public void setFirstMs(Integer firstMs) { + this.firstMs = firstMs; + } + + public String getLineName() { + return lineName; + } + + public void setLineName(String lineName) { + this.lineName = lineName; + } + + public Float getEventValue() { + return eventValue; + } + + public void setEventValue(Float eventValue) { + this.eventValue = eventValue; + } + + public Float getPersistTime() { + return persistTime; + } + + public void setPersistTime(Float persistTime) { + this.persistTime = persistTime; + } + + + public Date getTrigeTime() { + return trigeTime; + } + + public void setTrigeTime(Date trigeTime) { + this.trigeTime = trigeTime; + } + + public boolean getOpenTri() { + return openTri; + } + + public void setOpen(boolean open) { + this.openTri = open; + } + + public List getTmpWaveTitle() { + return tmpWaveTitle; + } + + public void setTmpWaveTitle(List tmpWaveTitle) { + this.tmpWaveTitle = tmpWaveTitle; + } + + public String getA() { + return a; + } + + public void setA(String a) { + this.a = a; + } + + public String getB() { + return b; + } + + public void setB(String b) { + this.b = b; + } + + public String getC() { + return c; + } + + public void setC(String c) { + this.c = c; + } + + public String getSubName() { + return subName; + } + + public void setSubName(String subName) { + this.subName = subName; + } + + + public int getiPhasic() { + return iPhasic; + } + + public void setiPhasic(int iPhasic) { + this.iPhasic = iPhasic; + } + + @Override + public String toString() { + return "WaveData{" + + "tmpWaveTitle=" + tmpWaveTitle + + ", sunData=" + sunData + + ", rmsData=" + rmsData + + ", iPhasic=" + iPhasic + + ", pt=" + pt + + ", ct=" + ct + + ", a='" + a + '\'' + + ", b='" + b + '\'' + + ", c='" + c + '\'' + + ", nOneWaveNum=" + nOneWaveNum + + ", firstTime=" + firstTime + + ", firstMs=" + firstMs + + ", RatesCfg=" + RatesCfg + + ", time='" + time + '\'' + + ", waveType='" + waveType + '\'' + + ", yzd=" + yzd + + ", lineName='" + lineName + '\'' + + ", eventValue=" + eventValue + + ", persistTime=" + persistTime + + ", trigeTime=" + trigeTime + + ", openTri=" + openTri + + ", readComtrade=" + readComtrade + + ", subName='" + subName + '\'' + + '}'; + } +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/po/PqsRelevanceLog.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/po/PqsRelevanceLog.java new file mode 100644 index 000000000..051c0337e --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/pojo/po/PqsRelevanceLog.java @@ -0,0 +1,33 @@ +package com.njcn.advance.pojo.po; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.njcn.db.bo.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.util.Date; + + +@EqualsAndHashCode(callSuper = true) +@Data +@TableName("pqs_relevancy_log") +public class PqsRelevanceLog extends BaseEntity { + + /** + * 归一化算法时间 + */ + @TableId("Time_Id") + private LocalDateTime timeId; + + + /** + * 归一化算法描述 + */ + private String contentDes; + + private Integer state; + +} diff --git a/pqs-advance/advance-api/src/main/java/com/njcn/advance/utils/WaveUtils.java b/pqs-advance/advance-api/src/main/java/com/njcn/advance/utils/WaveUtils.java new file mode 100644 index 000000000..3d971800a --- /dev/null +++ b/pqs-advance/advance-api/src/main/java/com/njcn/advance/utils/WaveUtils.java @@ -0,0 +1,49 @@ +package com.njcn.advance.utils; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.CharsetUtil; +import com.njcn.event.api.RmpEventDetailFeignClient; +import com.njcn.oss.utils.FileStorageUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.InputStream; + +/** + * pqs + * 波形操作工具类 + * @author cdf + * @date 2023/8/1 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class WaveUtils { + + private final FileStorageUtil fileStorageUtil; + + + + /** + * 读取文件服务器波形数据 + * @author cdf + * @date 2023/8/1 + */ + public String getFile(String filePath){ + String temJson = null; + try(InputStream inputStream = fileStorageUtil.getFileStream(filePath)){ + temJson = IoUtil.read(inputStream, CharsetUtil.UTF_8); + + } catch (IOException e) { + e.printStackTrace(); + } + return temJson; + } + + + public static void main(String[] args) { + + } +} diff --git a/pqs-advance/advance-boot/pom.xml b/pqs-advance/advance-boot/pom.xml index 081b7cba7..c3e782980 100644 --- a/pqs-advance/advance-boot/pom.xml +++ b/pqs-advance/advance-boot/pom.xml @@ -42,21 +42,20 @@ com.njcn pq-device-api - 1.0.0 + ${project.version} compile com.njcn advance-api - 1.0.0 - compile + ${project.version} com.njcn event-api - 1.0.0 + ${project.version} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/controller/EventRelevantAnalysisController.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/controller/EventRelevantAnalysisController.java new file mode 100644 index 000000000..1f0f03f7f --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/controller/EventRelevantAnalysisController.java @@ -0,0 +1,74 @@ +package com.njcn.advance.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.netflix.ribbon.proxy.annotation.Http; +import com.njcn.advance.pojo.dto.BalanceInfo; +import com.njcn.advance.pojo.param.AdvanceBaseParam; +import com.njcn.advance.service.EventRelevantAnalysisService; +import com.njcn.common.pojo.annotation.OperateInfo; +import com.njcn.common.pojo.enums.common.LogEnum; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.common.utils.HttpResultUtil; +import com.njcn.common.utils.PubUtils; +import com.njcn.event.pojo.vo.AdvanceEventDetailVO; +import com.njcn.web.controller.BaseController; +import com.njcn.web.pojo.annotation.DateTimeStrValid; +import com.njcn.web.pojo.param.BaseParam; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.io.DataInputStream; +import java.net.URLDecoder; +import java.time.LocalDateTime; +import java.util.List; + +/** + * pqs + * 事件关联分析 + * + * @author cdf + * @date 2023/6/30 + */ +@RestController +@RequestMapping("process") +@Api(tags = "暂降事件关联分析") +@RequiredArgsConstructor +@Slf4j +public class EventRelevantAnalysisController extends BaseController { + + private final EventRelevantAnalysisService eventRelevantAnalysisService; + + @GetMapping("processEvents") + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @ApiOperation("启动关联分析") + public HttpResult processEvents(@RequestParam("startTime") String startTime, @RequestParam("endTime")String endTime) { + String methodDescribe = getMethodDescribe("processEvents"); + List timeVal = PubUtils.checkLocalDateTime(startTime,endTime); + eventRelevantAnalysisService.processEvents(timeVal.get(0),timeVal.get(1)); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe); + } + + + + /** + * 高级算法-暂降事件关联分析主列表 + * @author cdf + * @date 2023/7/20 + */ + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/querySagEventsPage") + @ApiOperation("高级算法-暂降事件关联分析主列表") + public HttpResult> querySagEventsPage(BaseParam baseParam){ + String methodDescribe = getMethodDescribe("querySagEventsPage"); + Page list = eventRelevantAnalysisService.querySagEventsPage(baseParam); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, list, methodDescribe); + } + +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/controller/EventWaveAnalysisController.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/controller/EventWaveAnalysisController.java new file mode 100644 index 000000000..23eaa84c7 --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/controller/EventWaveAnalysisController.java @@ -0,0 +1,48 @@ +package com.njcn.advance.controller; + +import com.njcn.advance.pojo.dto.waveAnalysis.EntityAdvancedData; +import com.njcn.advance.service.EventWaveAnalysisService; +import com.njcn.common.pojo.annotation.OperateInfo; +import com.njcn.common.pojo.enums.common.LogEnum; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.common.utils.HttpResultUtil; +import com.njcn.web.controller.BaseController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * pqs + * 波形高级分析 + * + * @author cdf + * @date 2023/7/28 + */ +@RestController +@RequestMapping("waveAnalysis") +@Api(tags = "波形高级分析") +@RequiredArgsConstructor +@Slf4j +public class EventWaveAnalysisController extends BaseController { + + private final EventWaveAnalysisService eventWaveAnalysisService; + + + @PostMapping("analysis") + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @ApiOperation("波形高级分析") + @ApiImplicitParam(name = "eventIndex", value = "暂降事件id", required = true) + public HttpResult analysis(@RequestParam("eventIndex") String eventIndex) { + String methodDescribe = getMethodDescribe("analysis"); + EntityAdvancedData entityAdvancedData = eventWaveAnalysisService.analysis(eventIndex); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, entityAdvancedData, methodDescribe); + + } +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RelevantMapper.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RelevantMapper.java new file mode 100644 index 000000000..682e7bd8e --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RelevantMapper.java @@ -0,0 +1,26 @@ +package com.njcn.advance.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.advance.pojo.dto.relevent.EntityLogic; +import com.njcn.advance.pojo.po.PqsRelevanceLog; + +import java.util.List; + +/** + * pqs + * + * @author cdf + * @date 2023/6/19 + */ +public interface RelevantMapper extends BaseMapper { + + + + /** + * 获取母线物理隔绝信息 + * @author cdf + * @date 2023/7/21 + */ + List getLogic(); + +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RmpEventAdvanceMapper.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RmpEventAdvanceMapper.java new file mode 100644 index 000000000..3b3092793 --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RmpEventAdvanceMapper.java @@ -0,0 +1,21 @@ +package com.njcn.advance.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.advance.pojo.dto.SagEvent; +import com.njcn.event.pojo.po.RmpEventDetailPO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * pqs + * + * @author cdf + * @date 2023/6/19 + */ +public interface RmpEventAdvanceMapper extends BaseMapper { + + + + +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RmpEventDetailAssMapper.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RmpEventDetailAssMapper.java new file mode 100644 index 000000000..50a68d4b3 --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/RmpEventDetailAssMapper.java @@ -0,0 +1,23 @@ +package com.njcn.advance.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.advance.pojo.dto.SagEvent; +import com.njcn.advance.pojo.dto.relevent.EventAssObj; +import com.njcn.event.pojo.po.RmpEventDetailAssPO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * pqs + * + * @author cdf + * @date 2023/8/9 + */ +public interface RmpEventDetailAssMapper extends BaseMapper { + + + int insertEventAssData(@Param("list") List list); + + +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/EventWaveAnalysisMapper.xml b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/EventWaveAnalysisMapper.xml new file mode 100644 index 000000000..9eedce234 --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/EventWaveAnalysisMapper.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/RelevantMapper.xml b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/RelevantMapper.xml new file mode 100644 index 000000000..c523ae44b --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/RelevantMapper.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/RmpEventDetailAssMapper.xml b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/RmpEventDetailAssMapper.xml new file mode 100644 index 000000000..5bcdd64e3 --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/mapper/mapping/RmpEventDetailAssMapper.xml @@ -0,0 +1,24 @@ + + + + + + + insert into r_mp_event_detail_ass values + + ( + #{eventAssData.indexEventAss},#{eventAssData.time},#{eventAssData.describe}, + #{eventAssData.bRange},#{eventAssData.indexUser},#{eventAssData.indexUser},#{eventAssData.updateTime},#{eventAssData.updateTime} + ) + + + + + + + + + + + diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/BalanceService.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/BalanceService.java index bef5aaf0b..fe7706580 100644 --- a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/BalanceService.java +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/BalanceService.java @@ -1,10 +1,8 @@ package com.njcn.advance.service; + import com.njcn.advance.pojo.dto.BalanceInfo; import com.njcn.advance.pojo.param.AdvanceBaseParam; -import com.njcn.common.pojo.response.HttpResult; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestBody; import java.util.List; diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/EventRelevantAnalysisService.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/EventRelevantAnalysisService.java new file mode 100644 index 000000000..eb9a2e104 --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/EventRelevantAnalysisService.java @@ -0,0 +1,30 @@ +package com.njcn.advance.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.njcn.advance.mapper.RmpEventAdvanceMapper; +import com.njcn.event.pojo.po.RmpEventDetailPO; +import com.njcn.event.pojo.vo.AdvanceEventDetailVO; +import com.njcn.web.pojo.param.BaseParam; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * pqs + * + * @author cdf + * @date 2023/6/30 + */ +public interface EventRelevantAnalysisService extends IService { + + /** + * + * @author cdf + * @date 2023/6/30 + */ + void processEvents(LocalDateTime startTime,LocalDateTime endTime); + + + Page querySagEventsPage(BaseParam baseParam); +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/EventWaveAnalysisService.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/EventWaveAnalysisService.java new file mode 100644 index 000000000..31cbbfe1d --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/EventWaveAnalysisService.java @@ -0,0 +1,14 @@ +package com.njcn.advance.service; + +import com.njcn.advance.pojo.dto.waveAnalysis.EntityAdvancedData; + +/** + * pqs + * + * @author cdf + * @date 2023/8/1 + */ +public interface EventWaveAnalysisService { + + EntityAdvancedData analysis(String eventIndex); +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/BalanceServiceImpl.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/BalanceServiceImpl.java index af181af26..a2130a97d 100644 --- a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/BalanceServiceImpl.java +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/BalanceServiceImpl.java @@ -1,12 +1,10 @@ package com.njcn.advance.service.impl; import cn.hutool.core.collection.CollUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.njcn.advance.mapper.BalanceMapper; import com.njcn.advance.pojo.dto.AdvanceBaseDTO; import com.njcn.advance.pojo.dto.BalanceInfo; -import com.njcn.advance.pojo.dto.QtIdx; +import com.njcn.advance.pojo.dto.relevent.QtIdx; import com.njcn.advance.pojo.param.AdvanceBaseParam; import com.njcn.advance.service.BalanceService; import com.njcn.advance.utils.GetBalanceUtils; @@ -16,7 +14,6 @@ import com.njcn.common.utils.PubUtils; import com.njcn.device.pq.api.GeneralDeviceInfoClient; import com.njcn.device.pq.pojo.dto.GeneralDeviceDTO; import com.njcn.device.pq.pojo.param.DeviceInfoParam; -import com.njcn.event.pojo.po.RmpEventDetailPO; import com.njcn.system.pojo.enums.StatisticsEnum; import lombok.RequiredArgsConstructor; import org.apache.commons.collections.MapUtils; @@ -25,7 +22,6 @@ import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.function.Function; import java.util.stream.Collectors; /** @@ -99,7 +95,9 @@ public class BalanceServiceImpl implements BalanceService { balanceInfoList.add(balanceInfo); } // 打包数据传入dll/so计算结果 + getBalanceUtils.translateData(balanceInfoList); + return balanceInfoList; } } diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/EventRelevantAnalysisServiceImpl.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/EventRelevantAnalysisServiceImpl.java new file mode 100644 index 000000000..4082a4f88 --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/EventRelevantAnalysisServiceImpl.java @@ -0,0 +1,475 @@ +package com.njcn.advance.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.date.TimeInterval; +import cn.hutool.core.util.IdUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.njcn.advance.enums.AdvanceResponseEnum; +import com.njcn.advance.mapper.RelevantMapper; +import com.njcn.advance.mapper.RmpEventAdvanceMapper; +import com.njcn.advance.mapper.RmpEventDetailAssMapper; +import com.njcn.advance.pojo.dto.SagEvent; +import com.njcn.advance.pojo.dto.relevent.*; +import com.njcn.advance.pojo.po.PqsRelevanceLog; +import com.njcn.advance.service.EventRelevantAnalysisService; + +import com.njcn.advance.utils.UtilNormalization; +import com.njcn.common.pojo.enums.common.DataStateEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.utils.PubUtils; +import com.njcn.device.pq.api.GeneralDeviceInfoClient; +import com.njcn.device.pq.api.LineFeignClient; +import com.njcn.device.pq.pojo.vo.AreaLineInfoVO; +import com.njcn.event.api.RmpEventDetailFeignClient; +import com.njcn.event.pojo.po.RmpEventDetailPO; +import com.njcn.event.pojo.vo.AdvanceEventDetailVO; +import com.njcn.system.api.DicDataFeignClient; +import com.njcn.system.enums.DicDataEnum; +import com.njcn.system.enums.DicDataTypeEnum; +import com.njcn.system.enums.SystemResponseEnum; +import com.njcn.system.pojo.po.DictData; +import com.njcn.web.pojo.param.BaseParam; +import com.njcn.web.utils.RequestUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.RequestParam; + +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * pqs + * + * @author cdf + * @date 2023/6/30 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class EventRelevantAnalysisServiceImpl extends ServiceImpl implements EventRelevantAnalysisService { + + private final RmpEventDetailFeignClient rmpEventDetailFeignClient; + + private final DicDataFeignClient dicDataFeignClient; + + private final RelevantMapper relevantMapper; + + private final GeneralDeviceInfoClient generalDeviceInfoClient; + + private final RmpEventAdvanceMapper eventAdvanceMapper; + + private final LineFeignClient lineFeignClient; + + private final RmpEventDetailAssMapper rmpEventDetailAssMapper; + + + @Override + @Transactional(rollbackFor = Exception.class) + public void processEvents(LocalDateTime startTime,LocalDateTime endTime) { + + TimeInterval timeInterval = new TimeInterval(); + + DictData dictData = dicDataFeignClient.getDicDataByNameAndTypeName(DicDataTypeEnum.EVENT_REASON.getName(), DicDataEnum.SHORT_TROUBLE.getName()).getData(); + if (Objects.isNull(dictData)) { + throw new BusinessException(SystemResponseEnum.ADVANCE_REASON); + } + + + LocalDateTime date = LocalDateTime.now(); + HandleEvent handleEvent = new HandleEvent(); + // 分析的事件进行处理 + List baseList = handleEvent.getData(generalDeviceInfoClient,startTime,endTime); + + // 传入的处理事件根据物理隔绝进行分组 + + List strategyList = relevantMapper.getLogic(); + + if (CollectionUtil.isNotEmpty(strategyList)) { + List listSagEvent = new ArrayList<>(); + List listEventAssObj = new ArrayList<>(); + + Map> strategyToBusBarMap = new HashMap<>(); + + Map mapRedis = new HashMap<>(); + + Map> strategyMap = strategyList.stream().collect(Collectors.groupingBy(EntityLogic::getTPIndex)); + strategyMap.forEach((key, list) -> { + List before = list.stream().map(EntityLogic::getNodeBefore).distinct().collect(Collectors.toList()); + List after = list.stream().map(EntityLogic::getNodeNext).distinct().collect(Collectors.toList()); + before.addAll(after); + before = before.stream().distinct().collect(Collectors.toList()); + strategyToBusBarMap.put(key, before); + + FinalData.NODE_NUM = before.size(); + EntityMtrans entityMtrans = new EntityMtrans(); + handleEvent.create_matrixcata(list, entityMtrans); + + mapRedis.put(key, entityMtrans); + }); + //TODO 是否要处理排序 + + strategyToBusBarMap.forEach((lastKey, lastVal) -> { + int index = 1; + List list = new ArrayList(); + for (EntityGroupEvtData entityGroupEvtData : baseList) { + if (lastVal.contains(entityGroupEvtData.getNodePhysics()) && dictData.getId().equals(entityGroupEvtData.getSagReason())) { + entityGroupEvtData.setNode(index++); + list.add(entityGroupEvtData); + } + } + + baseList.removeIf(entityGroupEvtData -> lastVal.contains(entityGroupEvtData.getNodePhysics()) && dictData.getId().equals(entityGroupEvtData.getSagReason())); + + + EntityGroupEvtData[] entityGroupEvtData = new EntityGroupEvtData[list.size()]; + Collections.sort(list); + list.toArray(entityGroupEvtData); + + mapRedis.forEach((mKey, mVal) -> { + if (mKey.equals(lastKey)) { + /******************************************************************** + * 算法最多处理1000条数据,超过限制需分批处理 先将数据根据某种方式进行升序/降序排序,然后分段处理 加入循环处理 + *********************************************************************/ + int circulation = entityGroupEvtData.length % FinalData.MAX_EVT_NUM == 0 + ? entityGroupEvtData.length / FinalData.MAX_EVT_NUM + : entityGroupEvtData.length / FinalData.MAX_EVT_NUM + 1; + + for (int i = 0; i < circulation; i++) { + int to = 0; + + if (i == circulation - 1) { + to = entityGroupEvtData.length % FinalData.MAX_EVT_NUM > 0 + ? entityGroupEvtData.length + : (i + 1) * FinalData.MAX_EVT_NUM - 1; + } else { + to = (i + 1) * FinalData.MAX_EVT_NUM - 1; + } + + EntityGroupEvtData[] arrayObj = Arrays.copyOfRange(entityGroupEvtData, + i * FinalData.MAX_EVT_NUM, to); + EntityGroupData entityGroupData = handleEvent.translate(arrayObj, mVal); + // 处理分析结果 + handleEvent.show_group_info(entityGroupData, listSagEvent, listEventAssObj, date); + } + } + }); + + }); + + + /****************************************************************************** + * 事件ID不在矩阵中,结果集为基础以时标为标准进行归集处理 注意:三相与(单相/两相)互斥 + *****************************************************************************/ + disposeNonStandardData(handleEvent, baseList, listEventAssObj, listSagEvent, date); + + + int listSize = listEventAssObj.size(); + int toIndex = 1000; + for (int i = 0; i < listSize; i += 1000) { + //作用为toIndex最后没有toIndex条数据则剩余几条newList中就装几条 + if (i + 1000 > listSize) { + toIndex = listSize - i; + } + //分割lst + List newList = listEventAssObj.subList(i, i + toIndex); + //写入添加方法,需要写你的新增方法,把newList分切后的数据新增进入数据库。 + rmpEventDetailAssMapper.insertEventAssData(newList); + } + + List eventUpdateList = new ArrayList<>(); + for (int i = 0; i < listSagEvent.size(); i++) { + RmpEventDetailPO rmp = new RmpEventDetailPO(); + rmp.setEventId(listSagEvent.get(i).getIndexEventDetail()); + rmp.setEventassIndex(listSagEvent.get(i).getIndexEventAss()); + rmp.setDealTime(listSagEvent.get(i).getDealTime()); + eventUpdateList.add(rmp); + if ((i + 1) % 1000 == 0) { + this.updateBatchById(eventUpdateList); + eventUpdateList.clear(); + } else if (i == listSagEvent.size() - 1) { + this.updateBatchById(eventUpdateList); + } + } + + // 增加策略记录 + String describe = "用户" + RequestUtil.getUserNickname() + "进行了关联分析"; + PqsRelevanceLog entityPqsRelevance = new PqsRelevanceLog(); + entityPqsRelevance.setContentDes(describe); + entityPqsRelevance.setState(DataStateEnum.ENABLE.getCode()); + entityPqsRelevance.setTimeId(date); + relevantMapper.insert(entityPqsRelevance); + + } + + log.info("事件关联分析用时:" + timeInterval.interval() / 1000 + "秒"); + } + + @Override + public Page querySagEventsPage(BaseParam baseParam) { + return null; + } + + + /********************************************************************** + * 归集结果与非矩阵事件进行比对 + **********************************************************************/ + public void disposeNonStandardData(HandleEvent handleEvent, List noDealList, List list, List list2, LocalDateTime date) { + // 如果还有未归集的数据则单独拎为单一事件处理 + for (EntityGroupEvtData entityGroupEvtData : noDealList) { + String strUUID = IdUtil.simpleUUID(); + entityGroupEvtData.getSagEvent().setIndexEventAss(strUUID); + entityGroupEvtData.getSagEvent().setDealTime(date); + + List dealList = new ArrayList<>(); + dealList.add(entityGroupEvtData.getSagEvent()); + handleEvent.processing(dealList, list, date); + list2.add(entityGroupEvtData.getSagEvent()); + } + } + + + class HandleEvent { + public EntityGroupData translate(EntityGroupEvtData entityGroupEvtData[], EntityMtrans entityMtrans) { + // 获取测试数据的数组长度 + int test_log_num = entityGroupEvtData.length; + + // 实例化EntityGroupData,给其中的数组分配空间 + EntityGroupData group_buf = new EntityGroupData(); + + // 填入日志 + setMatrixcata(group_buf, entityMtrans); + create_evt_buf(entityGroupEvtData, group_buf, test_log_num); + + UtilNormalization.sort_Tstart(group_buf); // 根据时标进行划分 + // 根据暂降类型进行划分 + for (int i = 0; i < group_buf.getGrp_all_num(); i++) { + UtilNormalization.sort_cata(group_buf, i); + } + + return group_buf; + } + + public List getData(GeneralDeviceInfoClient generalDeviceInfoClient,LocalDateTime startTime,LocalDateTime endTime) { + List entityGroupEvtDataList = new ArrayList<>(); + + List advanceType = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.EVENT_TYPE.getCode()).getData(); + Map advanceMap = advanceType.stream().collect(Collectors.toMap(DictData::getId, Function.identity())); + + List advanceEventDetailVOLsit = querySagEventsAll(startTime,endTime); + + + for (int i = 0; i < advanceEventDetailVOLsit.size(); i++) { // 获取监测点线路序号 + //母线id + String nodePhysics = advanceEventDetailVOLsit.get(i).getVoltageId(); + + // 根据暂降类型获取高级算法对应的编号 + int cata = 0; + long ll = 0L; + int start_time = 0; + + if (Objects.isNull(advanceEventDetailVOLsit.get(i).getFirstType())) { + cata = advanceMap.get(advanceEventDetailVOLsit.get(i).getAdvanceType()).getAlgoDescribe(); + ll = (long) (Timestamp.valueOf(advanceEventDetailVOLsit.get(i).getStartTime()).getTime() + + (advanceEventDetailVOLsit.get(i).getDuration() * 1000)); + start_time = (int) (ll / 1000); + } else { + cata = advanceMap.get(advanceEventDetailVOLsit.get(i).getAdvanceType()).getAlgoDescribe(); // 获取类型 + ll = (long) (Timestamp.valueOf(advanceEventDetailVOLsit.get(i).getFirstTime()).getTime() + + (advanceEventDetailVOLsit.get(i).getFirstMs())); + start_time = (int) (ll / 1000); + } + + // 填充SagEvent对象数据 + SagEvent sagEvent = new SagEvent(); + + sagEvent.setIndexEventDetail(advanceEventDetailVOLsit.get(i).getEventId()); + sagEvent.setSagTime(advanceEventDetailVOLsit.get(i).getStartTime()); + sagEvent.setFirstTime(PubUtils.ms2Date(ll));// 必须增加,否则序列化出错 + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + /*String tem = advanceEventDetailVOLsit.get(i).getFirstTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + sagEvent.setStrTime(tem + "." + + advanceEventDetailVOLsit.get(i).getFirstMs());*/ + sagEvent.setTime(Timestamp.valueOf(advanceEventDetailVOLsit.get(i).getStartTime()).getTime()); + sagEvent.setFirstTimeMills(ll); + sagEvent.setMsec(advanceEventDetailVOLsit.get(i).getDuration().intValue()); + //sagEvent.setSagTime(PubUtils.ms2Date(Timestamp.valueOf(advanceEventDetailVOLsit.get(i).getFirstTime()).getTime())); + PlantInfo plantInfo = new PlantInfo(); + plantInfo.setNameBD(advanceEventDetailVOLsit.get(i).getSubName()); + plantInfo.setNameGD(advanceEventDetailVOLsit.get(i).getGdName()); + plantInfo.setNamePoint(advanceEventDetailVOLsit.get(i).getLineId()); + sagEvent.setPlantInfo(plantInfo); + sagEvent.setIndexPoint(advanceEventDetailVOLsit.get(i).getLineId()); + sagEvent.setCata(cata); + + + EntityGroupEvtData entityGroupEvtData = new EntityGroupEvtData(nodePhysics, start_time, cata, -1, sagEvent, advanceEventDetailVOLsit.get(i).getAdvanceReason()); + entityGroupEvtDataList.add(entityGroupEvtData); + } + + return entityGroupEvtDataList; + } + + public void create_evt_buf(EntityGroupEvtData[] arr, EntityGroupData obj, int len) { + System.arraycopy(arr, 0, obj.getIn_buf(), 0, arr.length); + obj.setEvt_in_num(len); + } + + public void create_matrixcata(List list, EntityMtrans entityMtrans) { + EntityLogic[] node_data = new EntityLogic[list.size()]; + + for (int i = 0; i < list.size(); i++) { + node_data[i] = list.get(i); + } + + int len = node_data.length; + + UtilNormalization.matrixcata_pro(node_data, entityMtrans, len); + } + + public void setMatrixcata(EntityGroupData obj, EntityMtrans entityMtrans) { + int i, j; + + for (i = 0; i < (FinalData.MAX_CATA_NUM - 1); i++) { + for (j = 0; j < FinalData.NODE_NUM; j++) { + obj.getMatrixcata()[i][j] = entityMtrans.getMatrixcata1()[i][j]; + } + } + } + + public void show_group_info(EntityGroupData obj, List list, List assEvent, LocalDateTime date) { + int i, j, k; + for (i = 0; i < obj.getGrp_all_num(); i++) { + String strUUID = IdUtil.simpleUUID(); + List listTem = new ArrayList(); + + for (j = 0; j < FinalData.MAX_CATA_NUM + 2; j++) { + if (obj.getGrp_cata_num()[i][j] != 0) { + for (k = 0; k < obj.getGrp_cata_num()[i][j]; k++) { + obj.getGrp_cata_buf()[i][j][k].getSagEvent().setIndexEventAss(strUUID); + obj.getGrp_cata_buf()[i][j][k].getSagEvent().setDealTime(date); + listTem.add(obj.getGrp_cata_buf()[i][j][k].getSagEvent()); + list.add(obj.getGrp_cata_buf()[i][j][k].getSagEvent()); + } + } + } + + if (listTem.size() > 0) { + processing(listTem, assEvent, date); + } + } + } + + public void processing(List list, List lists, LocalDateTime date) { + // 根据暂降事件发生时间进行排序 + Collections.sort(list); + EventAssObj eventAssObj = new EventAssObj(); + String strUUID = list.get(0).getIndexEventAss(); + + // 归一化处理数据填充 + eventAssObj.setIndexEventAss(strUUID); + + // 事件发生时间 + eventAssObj.setTime(list.get(0).getSagTime()); + + + // 获取当前用户GUID + eventAssObj.setIndexUser(RequestUtil.getUserIndex()); + + // 是否进行范围分析 默认未分析 + eventAssObj.setbRange(1); + + // 更新时间 + eventAssObj.setUpdateTime(date); + + + // 暂降事件描述 + String codeName = LocalDateTimeUtil.format(eventAssObj.getTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")); + String describe = "事件关联分析编号" + codeName + "共包含" + list.size() + "个事件"; + eventAssObj.setDescribe(describe); + + eventAssObj.setList(list); + lists.add(eventAssObj); + } + } + + + /************************************************************************************* + * 获取变压器信息并生成矩阵 + *************************************************************************************/ + public void getNodeInfo(HandleEvent handleEvent) { + List list = relevantMapper.getLogic(); + + if (CollectionUtil.isNotEmpty(list)) { + Map> tfMap = list.stream().collect(Collectors.groupingBy(EntityLogic::getTPIndex)); + Map> tfBusBarMap = new HashMap<>(); + + Map entityMtranMap = new HashMap<>(); + + tfMap.forEach((key, val) -> { + List tem = new ArrayList<>(); + val.forEach(it -> { + tem.add(it.getNodeBefore()); + tem.add(it.getNodeNext()); + }); + tfBusBarMap.put(key, tem); + + EntityMtrans entityMtrans = new EntityMtrans(); + handleEvent.create_matrixcata(val, entityMtrans); + entityMtranMap.put(key, entityMtrans); + }); + + + } + } + + + + public List querySagEventsAll(LocalDateTime startTime,LocalDateTime endTime) { + List lineIds = generalDeviceInfoClient.deptGetRunLineEvent(RequestUtil.getDeptIndex()).getData(); + if (CollUtil.isNotEmpty(lineIds)) { + + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.and(i -> i.isNull(RmpEventDetailPO::getEventassIndex).or().eq(RmpEventDetailPO::getEventassIndex, "")) + .between(RmpEventDetailPO::getStartTime, startTime, endTime); + + + List rmpEventDetailPOList = eventAdvanceMapper.selectList(lambdaQueryWrapper); + if (CollectionUtil.isEmpty(rmpEventDetailPOList)) { + throw new BusinessException(AdvanceResponseEnum.EVENT_EMPTY); + } + List tempLineIds = rmpEventDetailPOList.stream().map(RmpEventDetailPO::getLineId).distinct().collect(Collectors.toList()); + + List temLine = lineFeignClient.getBaseLineAreaInfo(tempLineIds).getData(); + Map map = temLine.stream().collect(Collectors.toMap(AreaLineInfoVO::getLineId, Function.identity())); + + List advanceEventDetailVOList = BeanUtil.copyToList(rmpEventDetailPOList, AdvanceEventDetailVO.class); + advanceEventDetailVOList = advanceEventDetailVOList.stream().peek(item -> { + if (map.containsKey(item.getLineId())) { + AreaLineInfoVO areaLineInfoVO = map.get(item.getLineId()); + item.setGdName(areaLineInfoVO.getGdName()); + item.setSubName(areaLineInfoVO.getSubName()); + item.setNum(areaLineInfoVO.getNum()); + item.setVoltageId(areaLineInfoVO.getVoltageId()); + } + }).collect(Collectors.toList()); + + return advanceEventDetailVOList; + } + return new ArrayList<>(); + } +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/EventWaveAnalysisServiceImpl.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/EventWaveAnalysisServiceImpl.java new file mode 100644 index 000000000..24a539165 --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/service/impl/EventWaveAnalysisServiceImpl.java @@ -0,0 +1,828 @@ +package com.njcn.advance.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.TimeInterval; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.njcn.advance.enums.EnumEvt; +import com.njcn.advance.mapper.RmpEventAdvanceMapper; +import com.njcn.advance.pojo.dto.waveAnalysis.*; + +import com.njcn.advance.service.EventWaveAnalysisService; +import com.njcn.advance.utils.*; +import com.njcn.common.config.GeneralInfo; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.utils.FileUtil; +import com.njcn.common.utils.PubUtils; +import com.njcn.device.pq.api.LineFeignClient; +import com.njcn.device.pq.pojo.vo.AreaLineInfoVO; +import com.njcn.device.pq.pojo.vo.LineDetailDataVO; +import com.njcn.event.api.RmpEventDetailFeignClient; +import com.njcn.event.pojo.po.EventDetail; +import com.njcn.event.pojo.po.RmpEventDetailPO; +import com.njcn.oss.constant.GeneralConstant; +import com.njcn.oss.constant.OssPath; +import com.njcn.oss.utils.FileStorageUtil; +import com.njcn.system.api.DicDataFeignClient; +import com.njcn.system.enums.DicDataTypeEnum; +import com.njcn.system.pojo.po.DictData; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.sf.json.JSONObject; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.formula.functions.T; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * pqs + * + * @author cdf + * @date 2023/7/28 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class EventWaveAnalysisServiceImpl implements EventWaveAnalysisService { + + private final int MAXLENGTH = 128 * 3000; //波形最大值计算 + + private final RmpEventDetailFeignClient rmpEventDetailFeignClient; + + private final DicDataFeignClient dicDataFeignClient; + + private final LineFeignClient lineFeignClient; + + private final GeneralInfo generalInfo; + + private final FileStorageUtil fileStorageUtil; + + private final WaveUtils waveUtils; + + private final RmpEventAdvanceMapper rmpEventAdvanceMapper; + + + @Override + public EntityAdvancedData analysis(String eventIndex) { + TimeInterval timeInterval = new TimeInterval(); + //调用方法获取暂降事件详情 + RmpEventDetailPO rmpEventDetailPO = rmpEventAdvanceMapper.selectById(eventIndex); + EntityAdvancedData entityAdvancedData = null; + + //获取PT变比 + LineDetailDataVO lineDetailDataVO = lineFeignClient.getLineDetailData(rmpEventDetailPO.getLineId()).getData(); + + + + if (rmpEventDetailPO.getFileFlag() == 1) { + //获取所有暂态原因 + List dicDataList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.EVENT_REASON.getCode()).getData(); + Map eventReasonMap = dicDataList.stream().collect(Collectors.toMap(DictData::getAlgoDescribe, Function.identity())); + + InputStream inputStreamCfg = null; + InputStream inputStreamDat = null; + try { + inputStreamCfg = fileStorageUtil.getFileStream(OssPath.WAVE_DIR + lineDetailDataVO.getIp() + StrUtil.SLASH + rmpEventDetailPO.getWavePath() + GeneralConstant.CFG); + inputStreamDat = fileStorageUtil.getFileStream(OssPath.WAVE_DIR + lineDetailDataVO.getIp() + StrUtil.SLASH + rmpEventDetailPO.getWavePath() + GeneralConstant.DAT); + } catch (Exception e) { + throw new BusinessException("暂降cfg,dat文件缺失,请联系管理员"); + } + + //读取 + BufferedReader bufferedReader = null; + InputStreamReader read = null; + String strFileLine = null; + byte[] array = {}; + List temCfgList = new ArrayList<>(); + try { + // 判断文件是否存在 + array = IoUtil.readBytes(inputStreamDat); + + read = new InputStreamReader(inputStreamCfg, CharsetUtil.UTF_8);// 考虑到编码格式 + bufferedReader = new BufferedReader(read); + + while ((strFileLine = bufferedReader.readLine()) != null) { + temCfgList.add(strFileLine); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (read != null) { + read.close(); + } + if (inputStreamDat != null) { + inputStreamDat.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + //原始波形 + WaveData waveOriginalData = getWavedata(rmpEventDetailPO, temCfgList, array, 3); + List> originalList = waveOriginalData.getSunData(); + + entityAdvancedData = new EntityAdvancedData(originalList.size()); + + for (int i = 0; i < originalList.size(); i++) { + entityAdvancedData.smp_x[i] = originalList.get(i).get(0).floatValue();//坐标轴 + entityAdvancedData.smp_a[i] = originalList.get(i).get(1).floatValue(); + entityAdvancedData.smp_b[i] = originalList.get(i).get(2).floatValue(); + entityAdvancedData.smp_c[i] = originalList.get(i).get(3).floatValue(); + } + entityAdvancedData.smp_len = originalList.size(); + + //抽点方法计算波形 + WaveData wavePitchData = getWavedata(rmpEventDetailPO, temCfgList, array, 0); + List> pitchList = wavePitchData.getSunData(); + + // 将获取到的数据填充到结构体内 + Rect rect = new Rect(); + CauseStruct causeStruct = new CauseStruct(); + + for (int i = 0; i < pitchList.size(); i++) { + rect.smp_va[i] = pitchList.get(i).get(1).floatValue(); + causeStruct.smp_va[i] = pitchList.get(i).get(1).floatValue(); + + rect.smp_vb[i] = pitchList.get(i).get(2).floatValue(); + causeStruct.smp_vb[i] = pitchList.get(i).get(2).floatValue(); + + rect.smp_vc[i] = pitchList.get(i).get(3).floatValue(); + causeStruct.smp_vc[i] = pitchList.get(i).get(3).floatValue(); + } + + rect.smp_len = pitchList.size(); + + if (rect.smp_len >= MAXLENGTH) { //超过60s的波形直接抛异常给上面处理 + throw new BusinessException("波形超过60S"); + } + + rect.smp_rate = (int) wavePitchData.getnOneWaveNum(); + causeStruct.smp_len = pitchList.size(); + causeStruct.smp_rate = (int) wavePitchData.getnOneWaveNum(); + + + String hdrStr = waveUtils.getFile(OssPath.WAVE_DIR + lineDetailDataVO.getIp() + StrUtil.SLASH + rmpEventDetailPO.getWavePath() + GeneralConstant.HDR); + JSONObject jsonObject = JSONObject.fromObject(hdrStr); + translateData(jsonObject, rmpEventDetailPO.getStartTime(), entityAdvancedData); + + + if(rmpEventDetailPO.getDealFlag()!=1){ + //如果存在三个文件但是没有调用dll/so计算 + + getDataFromDLL(rmpEventDetailPO,waveOriginalData,rect,entityAdvancedData,causeStruct); + + } + + + + + /**************************************************************** + * 根据返回的结果计算,获取暂降类型描述 + ****************************************************************/ + if (entityAdvancedData.backNumber > 0) { + for (int i = 0; i < entityAdvancedData.backNumber; i++) { + entityAdvancedData.sagType[i] = eventReasonMap.get(entityAdvancedData.evt_buf[i].qvvr_cata_type[0]).getName(); + + switch (entityAdvancedData.evt_buf[i].qvvr_phasetype[0]) { + case 1: + entityAdvancedData.sagPhaseType[i] = "单相"; + break; + case 2: + entityAdvancedData.sagPhaseType[i] = "两相"; + break; + case 3: + entityAdvancedData.sagPhaseType[i] = "三相"; + break; + default: + ; + } + } + } + } else { + throw new BusinessException("暂降cfg,dat文件缺失,请联系管理员"); + } + + log.info("高级算法波形计算" + timeInterval.interval()); + return null; + } + + + // 1-值调用暂降类型dll 2-两个dll都调用 + private void judgeEvt(int type, String eventIndex, WaveData waveData, Rect rect, EntityAdvancedData entityAdvancedData) { + try { + //getDataFromDLL(type, eventIndex, waveData, rect, entityAdvancedData); + } catch (Exception e) { + //eventDetailMapper.updateDealFlag(3, eventIndex); //计算失败 + log.error(e.getMessage()); + } + } + + /** + * @return + * @事件未进行高级算法处理:系统调用dll处理并保存结果 + */ + @Transactional(rollbackFor = Exception.class) + public void getDataFromDLL(RmpEventDetailPO rmpEventDetailPOQuery,WaveData waveData, Rect rect, EntityAdvancedData entityAdvancedData, CauseStruct causeStruct) { + + if(StrUtil.isBlank(rmpEventDetailPOQuery.getAdvanceType())){ + JnaCallDllOrSo jnaCallDllOrSo = new JnaCallBalance("qvvr_dll"); + jnaCallDllOrSo.setPath(); + // 计算暂降类 + JnaCallBalance.Eventlibrary INSTANTCE = JnaCallBalance.Eventlibrary.INSTANTCE; + INSTANTCE.qvvr_fun(rect); + + initBackData(rect.evt_num, entityAdvancedData); + + /** + * @判断是否调用成功 + * @成功执行更新pqs_eventdetail操作:更新dq持续时间、暂降类型、暂降原因、总分段数目 + */ + if (rect.evt_num > 0) { + RmpEventDetailPO rmpEventDetailPO = new RmpEventDetailPO(); + rmpEventDetailPO.setEventId(rmpEventDetailPOQuery.getEventId()); + rmpEventDetailPO.setNum(rect.evt_num); + rmpEventDetailPO.setDqTime((double) rect.evt_buf[0].hold_time_dq); + rmpEventDetailPO.setFirstType((Integer.toString(rect.evt_buf[0].qvvr_cata_type[0]))); + rmpEventDetailPO.setFirstTime(waveData.getFirstTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()); + rmpEventDetailPO.setFirstMs((double)waveData.getFirstMs()); + + + // 排序并获取多段中最小的数据 + float[] f = new float[rect.evt_num]; + + for (int i = 0; i < rect.evt_num; i++) { + Arrays.parallelSort(rect.evt_buf[i].u3_min, 0, Math.max(rect.evt_buf[i].u_min_num - 1, 0)); + f[i] = rect.evt_buf[i].u3_min[0]; + } + + float min = f[0]; + int index = 0; + + for (int len = 1; len < f.length; len++) { + if (min - f[len] > 0) { + index = len; + min = f[len]; + } + } + + /******************************************************************** + * add by sw 返回的分段位置需根据采样率进行恢复 + ********************************************************************/ + List list = waveData.getRatesCfg().OneRate; + int rate = (int) waveData.getnOneWaveNum(); + int k = 0; + int l = 0; + + for (int i = 0; i < list.size(); i++) { + if (i == 0) { + for (int j = 0; j < rect.evt_buf[0].SEG_T_num; j++) { + if (list.get(i).nOneSample >= rate && rect.evt_buf[0].SEG_T_idx[j] < list.get(i).nSampleNum + / (list.get(i).nOneSample / rate)) { + rect.evt_buf[0].SEG_T_idx[j] = (int) (rect.evt_buf[0].SEG_T_idx[j] + * (list.get(i).nOneSample / rate)); + k++; + } + } + + for (int j = 0; j < rect.evt_buf[0].u_min_num; j++) { + if (list.get(i).nOneSample >= rate && rect.evt_buf[0].order_min_idx[j] < list.get(i).nSampleNum + / (list.get(i).nOneSample / rate)) { + rect.evt_buf[0].order_min_idx[j] = (int) (rect.evt_buf[0].order_min_idx[j] + * (list.get(i).nOneSample / rate)); + l++; + } + } + } else { + for (int j = k; j < rect.evt_buf[0].SEG_T_num; j++) { + int posb = 0; + int pose = 0; + int pos = 0; + + for (int kk = 0; kk <= i; kk++) { + pose += list.get(kk).nSampleNum / list.get(kk).nOneSample * rate; + + if (kk < i) { + posb += list.get(kk).nSampleNum / list.get(kk).nOneSample * rate; + pos += list.get(kk).nSampleNum; + } + } + + if (list.get(i).nOneSample >= rate + && rect.evt_buf[0].SEG_T_idx[j] > posb + && rect.evt_buf[0].SEG_T_idx[j] < pose) { + rect.evt_buf[0].SEG_T_idx[j] = (int) ((rect.evt_buf[0].SEG_T_idx[j] - posb) * list.get(i).nOneSample / rate) + pos; + k++; + } + } + + for (int j = l; j < rect.evt_buf[0].u_min_num; j++) { + int posb = 0; + int pose = 0; + int pos = 0; + + for (int kk = 0; kk <= i; kk++) { + pose += list.get(kk).nSampleNum / list.get(kk).nOneSample * rate; + + if (kk < i) { + posb += list.get(kk).nSampleNum / list.get(kk).nOneSample * rate; + pos += list.get(kk).nSampleNum; + } + } + + if (list.get(i).nOneSample >= rate + && rect.evt_buf[0].order_min_idx[j] > posb + && rect.evt_buf[0].order_min_idx[j] < pose) { + rect.evt_buf[0].order_min_idx[j] = (int) ((rect.evt_buf[0].order_min_idx[j] - posb) * list.get(i).nSampleNum / rate) + pos; + l++; + } + } + } + } + + + List dicDataList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.EVENT_TYPE.getCode()).getData(); + Map eventTypeMap = dicDataList.stream().collect(Collectors.toMap(DictData::getAlgoDescribe, Function.identity())); + + Integer tem = rect.evt_buf[index].qvvr_cata_type[0]; + if(eventTypeMap.containsKey(tem)) { + rmpEventDetailPO.setAdvanceType(eventTypeMap.get(tem).getId()); + } + rmpEventDetailPO.setDealFlag(1); + rmpEventAdvanceMapper.updateById(rmpEventDetailPO); + //setEntityAdvanceData(); + //WriteData2File(); + //eventDetailMapper.updateDealFlag(1, eventIndex); //计算有结果 + } else if (rect.evt_num == 0) { + //eventDetailMapper.updateDealFlag(2, eventIndex);//已计算无结果 + } + } + + + if (StrUtil.isBlank(rmpEventDetailPOQuery.getAdvanceReason())) { + + //暂降原因计算 + JnaCallDllOrSo jnaCallDllReason = new JnaCallBalance("qvvr_dll_cause"); + jnaCallDllReason.setPath(); + + JnaCallBalance.Balancelibrary CAUSE = JnaCallBalance.Balancelibrary.INSTANTCE; + CAUSE.qvvr_fun_cause(causeStruct); + + if (causeStruct.no_cal == 1) { + causeStruct.cause = 0; + } + + //获取所有暂态原因 + List dicDataList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.EVENT_REASON.getCode()).getData(); + Map eventReasonMap = dicDataList.stream().collect(Collectors.toMap(DictData::getAlgoDescribe, Function.identity())); + + // 暂降原因的结果更新到数据库 + if(eventReasonMap.containsKey(causeStruct.cause)) { + RmpEventDetailPO updateRmpEventDetailPO = new RmpEventDetailPO(); + updateRmpEventDetailPO.setEventId(rmpEventDetailPOQuery.getEventId()); + updateRmpEventDetailPO.setAdvanceReason(eventReasonMap.get(causeStruct.cause).getId()); + rmpEventAdvanceMapper.updateById(updateRmpEventDetailPO); + entityAdvancedData.sagReason[0] = eventReasonMap.get(causeStruct.cause).getName(); + } + + } + + + } + + public void initBackData(int len, EntityAdvancedData entityAdvancedData) { + len = (len == 0 ? 1 : len); + + entityAdvancedData.evt_buf = new BackData[len]; + + for (int i = 0; i < len; i++) { + entityAdvancedData.evt_buf[i] = new BackData(); + } + } + + /** + * 根据暂降事件索引获取波形数据 + * 注:当前只考虑本地的波形文件 + * + * @param rmpEventDetailPO 暂态事件 + * @param flag 抽点方式 3.全部数据 1.抽点数据 + */ + + public WaveData getWavedata(RmpEventDetailPO rmpEventDetailPO, List temCfgList, byte[] array, int flag) { + WaveData waveData = new WaveData(); + + waveData.setEventValue(PubUtils.floatRound(2, rmpEventDetailPO.getFeatureAmplitude().floatValue() * 100)); + waveData.setPersistTime(PubUtils.floatRound(3, rmpEventDetailPO.getDuration().floatValue() / 1000)); + waveData.setTrigeTime(AnalyWave.getTimeWave()); + + + // 判断文件是否存在 + if (StrUtil.isNotBlank(rmpEventDetailPO.getWavePath())) { + log.info(OssPath.WAVE_DIR + rmpEventDetailPO.getWavePath() + "路径下,文件找到了"); + //CFG文件路径 pathTemp + //获取波形的瞬时值、RMS值数据 + AnalyWave analyWave = new AnalyWave(); + AnalyWaveModel.tagDataValue tagDataValue = analyWave.readComtrade(temCfgList, array, flag); + List> shunWave = tagDataValue.getListWaveData();//获取瞬时波形值 + List> rmsWave = analyWave.showValidData(shunWave);//RMS值波形 + waveData.setnOneWaveNum(analyWave.getnOneWaveNum()); + waveData.setSunData(shunWave); + waveData.setTmpWaveTitle(tagDataValue.getTmpWaveTitle()); + waveData.setFirstMs(analyWave.getFirstMs()); + waveData.setFirstTime(analyWave.getFirstTime()); + waveData.setRmsData(rmsWave); + waveData.setRatesCfg(analyWave.getRatesCfg()); + /*********** Modify by yexibao ---Start **************/ + waveData.setiPhasic(tagDataValue.getiPhasic()); + /*********** Modify by yexibao ---End **************/ + List tmpWaveTitle = tagDataValue.getTmpWaveTitle(); + /*********** Modify by yexibao ---Start **************/ + for (int i = 0; i < tagDataValue.getiPhasic(); i++) { + if (tmpWaveTitle.get(i + 1).substring(1).indexOf("A") > -1) { + waveData.setA(tmpWaveTitle.get(i + 1).substring(1)); + } + if (tmpWaveTitle.get(i + 1).substring(1).indexOf("B") > -1) { + waveData.setB(tmpWaveTitle.get(i + 1).substring(1)); + } + if (tmpWaveTitle.get(i + 1).substring(1).indexOf("C") > -1) { + waveData.setC(tmpWaveTitle.get(i + 1).substring(1)); + } + } + /*********** Modify by yexibao ---End **************/ + + } else { + log.error(OssPath.WAVE_DIR + rmpEventDetailPO.getWavePath() + "路径下,文件找不到了"); + } + + return waveData; + } + + + public void translateData(JSONObject jsonObject, LocalDateTime trigeTime, EntityAdvancedData entityAdvancedData) { + int len = Utils.getIntValue(jsonObject.get(EnumEvt.EVT_NUM.getProperty()).toString(), 0); + + entityAdvancedData.backNumber = len; + //初始化EntityAdvancedData的BackData数据 + len = (len == 0 ? 1 : len); + entityAdvancedData.evt_buf = new BackData[len]; + for (int i = 0; i < len; i++) { + entityAdvancedData.evt_buf[i] = new BackData(); + } + + for (int offset = 0; offset < len; offset++) { + BackData backData = new BackData(); + /** + * @波形起始点(3相) + */ + backData.POW_a = Utils.getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).get(EnumEvt.POW_A.getProperty()).toString(), 0.0f); + backData.POW_b = Utils.getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).get(EnumEvt.POW_B.getProperty()).toString(), 0.0f); + backData.POW_c = Utils.getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).get(EnumEvt.POW_C.getProperty()).toString(), 0.0f); + + /** + * @跳变段电压变化 + */ + backData.Voltagechange_Va = Utils.getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).get(EnumEvt.VOLTAGECHANGE_VA.getProperty()).toString(), 0.0f); + backData.Voltagechange_Vb = Utils.getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).get(EnumEvt.VOLTAGECHANGE_VB.getProperty()).toString(), 0.0f); + backData.Voltagechange_Vc = Utils.getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).get(EnumEvt.VOLTAGECHANGE_VC.getProperty()).toString(), 0.0f); + + /** + * @持续时间 + */ + backData.hold_time_rms = Utils.getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).get(EnumEvt.HOLD_TIME_RMS.getProperty()).toString(), 0.0f); + backData.hold_time_dq = Utils.getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).get(EnumEvt.HOLD_TIME_DQ.getProperty()).toString(), 0.0f); + + /** + * @分段信息 + */ + backData.SEG_T_num = Utils.getIntValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).get(EnumEvt.SEG_T_NUM.getProperty()).toString(), 0); + + for (int i = 0; i < backData.SEG_T_num; i++) { + backData.SEG_T_idx[i] = Utils.getIntValue( + jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.SEG_T_IDX.getProperty()).get(Integer.toString(i)).toString(), + -1); + } + + /** + * @特征幅值 + */ + backData.u_min_num = Utils.getIntValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).get(EnumEvt.U_MIN_NUM.getProperty()).toString(), 0); + + for (int j = 0; j < backData.u_min_num; j++) { + backData.ua_min[j] = Utils + .getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.UA_MIN.getProperty()).get(Integer.toString(j)).toString(), 0.0f); + backData.ub_min[j] = Utils + .getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.UB_MIN.getProperty()).get(Integer.toString(j)).toString(), 0.0f); + backData.uc_min[j] = Utils + .getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.UC_MIN.getProperty()).get(Integer.toString(j)).toString(), 0.0f); + backData.u3_min[j] = Utils + .getFloatValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.U3_MIN.getProperty()).get(Integer.toString(j)).toString(), 0.0f); + + /** + * @相位跳变 + */ + backData.angle_diff_an[j] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.ANGLE_DIFF_AN.getProperty()).get(Integer.toString(j)).toString(), + 0.0f); + backData.angle_diff_bn[j] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.ANGLE_DIFF_BN.getProperty()).get(Integer.toString(j)).toString(), + 0.0f); + backData.angle_diff_cn[j] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.ANGLE_DIFF_CN.getProperty()).get(Integer.toString(j)).toString(), + 0.0f); + backData.angle_diff_ap[j] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.ANGLE_DIFF_AP.getProperty()).get(Integer.toString(j)).toString(), + 0.0f); + backData.angle_diff_bp[j] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.ANGLE_DIFF_BP.getProperty()).get(Integer.toString(j)).toString(), + 0.0f); + backData.angle_diff_cp[j] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.ANGLE_DIFF_CP.getProperty()).get(Integer.toString(j)).toString(), + 0.0f); + + /** + * @不平衡度 + */ + backData.bph_max_value[j] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()).getJSONObject(offset) + .getJSONObject(EnumEvt.BPH_MAX_VALUE.getProperty()).get(Integer.toString(j)).toString(), + 0.0f); + + /** + * @暂降原因 + */ + backData.qvvr_cata_cause[j] = Utils.getIntValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).getJSONObject(EnumEvt.QVVR_CATA_CAUSE.getProperty()) + .get(Integer.toString(j)).toString(), -1); + + /** + * @暂降类型 + */ + backData.qvvr_cata_type[j] = Utils.getIntValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).getJSONObject(EnumEvt.QVVR_CATA_TYPE.getProperty()) + .get(Integer.toString(j)).toString(), -1); + + /** + * @暂降相别 + */ + backData.qvvr_phasetype[j] = Utils.getIntValue(jsonObject.getJSONArray(EnumEvt.EVT_BUF.getProperty()) + .getJSONObject(offset).getJSONObject(EnumEvt.QVVR_PHASETYPE.getProperty()) + .get(Integer.toString(j)).toString(), -1); + } + + entityAdvancedData.evt_buf[offset] = backData; + } + + if (jsonObject.containsKey(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty())) { + if (!jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).isEmpty()) { + entityAdvancedData.power_after_buf = new PowerData[1]; + PowerData power = new PowerData(); + float fundP[] = new float[5]; + fundP[0] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_P.getProperty()).get("A").toString(), 0.0f); + fundP[1] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_P.getProperty()).get("B").toString(), 0.0f); + fundP[2] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_P.getProperty()).get("C").toString(), 0.0f); + fundP[3] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_P.getProperty()).get("total").toString(), 0.0f); + fundP[4] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_P.getProperty()).get("zero").toString(), 0.0f); + power.setFundP(fundP); + + float fundQ[] = new float[5]; + fundQ[0] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_Q.getProperty()).get("A").toString(), 0.0f); + fundQ[1] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_Q.getProperty()).get("B").toString(), 0.0f); + fundQ[2] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_Q.getProperty()).get("C").toString(), 0.0f); + fundQ[3] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_Q.getProperty()).get("total").toString(), 0.0f); + fundQ[4] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_Q.getProperty()).get("zero").toString(), 0.0f); + power.setFundQ(fundQ); + + float fundS[] = new float[5]; + fundS[0] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_S.getProperty()).get("A").toString(), 0.0f); + fundS[1] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_S.getProperty()).get("B").toString(), 0.0f); + fundS[2] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_S.getProperty()).get("C").toString(), 0.0f); + fundS[3] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_S.getProperty()).get("total").toString(), 0.0f); + fundS[4] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.POWER_QVVR_AFTER_BUF.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.FUND_S.getProperty()).get("zero").toString(), 0.0f); + power.setFundS(fundS); + entityAdvancedData.power_after_buf[0] = power; + } + } + if (jsonObject.containsKey(EnumEvt.QVVR_DIRECTION_INFO.getProperty())) { + if (!jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).isEmpty()) { + entityAdvancedData.qvvr_direction_info = new DirectionData[1]; + DirectionData direction = new DirectionData(); + int trigTime[] = new int[7]; + trigTime[0] = Utils.getIntValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("year").toString(), 0); + trigTime[1] = Utils.getIntValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("month").toString(), 0); + trigTime[2] = Utils.getIntValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("date").toString(), 0); + trigTime[3] = Utils.getIntValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("hour").toString(), 0); + trigTime[4] = Utils.getIntValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("minute").toString(), 0); + trigTime[5] = Utils.getIntValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("second").toString(), 0); + trigTime[6] = Utils.getIntValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("millisecond").toString(), 0); + direction.setTrigTime(trigTime); + + float qvvrBeforeRms[] = new float[6]; + qvvrBeforeRms[0] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_RMS.getProperty()).get("Fund_Ua").toString(), 0.0f); + qvvrBeforeRms[1] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_RMS.getProperty()).get("Fund_Ub").toString(), 0.0f); + qvvrBeforeRms[2] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_RMS.getProperty()).get("Fund_Uc").toString(), 0.0f); + qvvrBeforeRms[3] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_RMS.getProperty()).get("Fund_Ia").toString(), 0.0f); + qvvrBeforeRms[4] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_RMS.getProperty()).get("Fund_Ib").toString(), 0.0f); + qvvrBeforeRms[5] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_RMS.getProperty()).get("Fund_Ic").toString(), 0.0f); + direction.setQvvrBeforeRms(qvvrBeforeRms); + + float qvvrBeforeZk[] = new float[6]; + qvvrBeforeZk[0] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_ZK.getProperty()).get("Za").toString(), 0.0f); + qvvrBeforeZk[1] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_ZK.getProperty()).get("Zb").toString(), 0.0f); + qvvrBeforeZk[2] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_ZK.getProperty()).get("Zc").toString(), 0.0f); + qvvrBeforeZk[3] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_ZK.getProperty()).get("Zab").toString(), 0.0f); + qvvrBeforeZk[4] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_ZK.getProperty()).get("Zbc").toString(), 0.0f); + qvvrBeforeZk[5] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_BEFORE_ZK.getProperty()).get("Zca").toString(), 0.0f); + direction.setQvvrBeforeZk(qvvrBeforeZk); + + float qvvrOccurRms[] = new float[6]; + qvvrOccurRms[0] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_RMS.getProperty()).get("Fund_Ua").toString(), 0.0f); + qvvrOccurRms[1] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_RMS.getProperty()).get("Fund_Ub").toString(), 0.0f); + qvvrOccurRms[2] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_RMS.getProperty()).get("Fund_Uc").toString(), 0.0f); + qvvrOccurRms[3] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_RMS.getProperty()).get("Fund_Ia").toString(), 0.0f); + qvvrOccurRms[4] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_RMS.getProperty()).get("Fund_Ib").toString(), 0.0f); + qvvrOccurRms[5] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_RMS.getProperty()).get("Fund_Ic").toString(), 0.0f); + direction.setQvvrOccurRms(qvvrOccurRms); + + float qvvrOccurZk[] = new float[6]; + qvvrOccurZk[0] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_ZK.getProperty()).get("Za").toString(), 0.0f); + qvvrOccurZk[1] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_ZK.getProperty()).get("Zb").toString(), 0.0f); + qvvrOccurZk[2] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_ZK.getProperty()).get("Zc").toString(), 0.0f); + qvvrOccurZk[3] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_ZK.getProperty()).get("Zab").toString(), 0.0f); + qvvrOccurZk[4] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_ZK.getProperty()).get("Zbc").toString(), 0.0f); + qvvrOccurZk[5] = Utils.getFloatValue( + jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_OCCUR_ZK.getProperty()).get("Zca").toString(), 0.0f); + direction.setQvvrOccurZk(qvvrOccurZk); + + String qvvrPosInfo[] = new String[1]; + qvvrPosInfo[0] = jsonObject.getJSONArray(EnumEvt.QVVR_DIRECTION_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.QVVR_POS_INFO.getProperty()).get("direction").toString(); + direction.setQvvrPosInfo(qvvrPosInfo); + + entityAdvancedData.qvvr_direction_info[0] = direction; + } + } + if (jsonObject.containsKey(EnumEvt.QVVR_UTBL_INFO.getProperty())) { + if (!jsonObject.getJSONArray(EnumEvt.QVVR_UTBL_INFO.getProperty()).isEmpty()) { + entityAdvancedData.qvvr_utbl_info = new UtblData[1]; + UtblData direction = new UtblData(); + long trigTime[] = new long[1]; + String year = jsonObject.getJSONArray(EnumEvt.QVVR_UTBL_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("year").toString(); + String month = jsonObject.getJSONArray(EnumEvt.QVVR_UTBL_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("month").toString(); + String day = jsonObject.getJSONArray(EnumEvt.QVVR_UTBL_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("date").toString(); + String hour = jsonObject.getJSONArray(EnumEvt.QVVR_UTBL_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("hour").toString(); + String min = jsonObject.getJSONArray(EnumEvt.QVVR_UTBL_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("minute").toString(); + String sec = jsonObject.getJSONArray(EnumEvt.QVVR_UTBL_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("second").toString(); + String mil = jsonObject.getJSONArray(EnumEvt.QVVR_UTBL_INFO.getProperty()).getJSONObject(0) + .getJSONObject(EnumEvt.TRIG_TIME.getProperty()).get("millisecond").toString(); + SimpleDateFormat dfs = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + Date utbl = null; + try { + utbl = dfs.parse(year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec + "." + mil); + } catch (ParseException e) { + e.printStackTrace(); + } + long between = utbl.getTime() - trigeTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); + trigTime[0] = between; + direction.setTrigTime(trigTime); + entityAdvancedData.qvvr_utbl_info[0] = direction; + } + } + + + } + + +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/GetBalanceUtils.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/GetBalanceUtils.java index a5b70a952..0d86349d8 100644 --- a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/GetBalanceUtils.java +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/GetBalanceUtils.java @@ -4,15 +4,11 @@ import cn.hutool.core.date.TimeInterval; import com.njcn.advance.pojo.bo.QtIdxArray; import com.njcn.advance.pojo.bo.QvvrDataStruct; import com.njcn.advance.pojo.dto.BalanceInfo; -import com.njcn.advance.pojo.dto.QtIdx; +import com.njcn.advance.pojo.dto.relevent.QtIdx; import lombok.Data; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; -import java.util.Date; import java.util.List; /** diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/JnaCallBalance.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/JnaCallBalance.java index 55901fe46..9926269c6 100644 --- a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/JnaCallBalance.java +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/JnaCallBalance.java @@ -1,6 +1,8 @@ package com.njcn.advance.utils; import com.njcn.advance.pojo.bo.QvvrDataStruct; +import com.njcn.advance.pojo.dto.waveAnalysis.CauseStruct; +import com.njcn.advance.pojo.dto.waveAnalysis.Rect; import com.sun.jna.Library; import com.sun.jna.Native; @@ -33,5 +35,23 @@ public class JnaCallBalance extends JnaCallDllOrSo{ // 定义方法--->与C方法相对应 void qvvr_fun_cause(QvvrDataStruct data); + + // 定义方法--->与C方法相对应 + void qvvr_fun_cause(CauseStruct data); + + + } + + public interface Eventlibrary extends Library { + // 加载Lib库 + + + Eventlibrary INSTANTCE = (Eventlibrary) Native.loadLibrary(JnaCallBalance.strpath, Eventlibrary.class); + + + // 计算暂降类 + void qvvr_fun(Rect data); + + } } diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/JnaCallDllOrSo.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/JnaCallDllOrSo.java index 2fc59f116..bfef6c22d 100644 --- a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/JnaCallDllOrSo.java +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/JnaCallDllOrSo.java @@ -14,7 +14,6 @@ import java.net.URLDecoder; @Slf4j public class JnaCallDllOrSo { private String path = ""; - private String pathDll = ""; private String nameDll; public static String jarPath = ""; diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/UtilNormalization.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/UtilNormalization.java new file mode 100644 index 000000000..4d68dae8b --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/UtilNormalization.java @@ -0,0 +1,382 @@ +package com.njcn.advance.utils; + + +import com.njcn.advance.pojo.dto.relevent.*; + +public class UtilNormalization { + public static void matrixcata_pro(EntityLogic[] transformer, EntityMtrans entityMtrans, int len) { + int i, j, k, con; + String node1, node2; + int src_node[] = new int[] { 0 }; + + // 连接方式转化为矩阵形式,行、列表示所有节点 + // inf表示两个节点不相连,0表示与自身相连,其他数值表示变压器连接类型 + // 将初始矩阵的元素设为inf,对角线元素设为0 + for (i = 0; i < FinalData.NODE_NUM; i++) { + for (j = 0; j < FinalData.NODE_NUM; j++) { + entityMtrans.getMtrans()[i][j] = FinalData.DATA_INF; + } + entityMtrans.getMtrans()[i][i] = 0; + } + // 根据transformer设置元素 + for (i = 0; i < len; i++) { + node1 = transformer[i].getNode_h(); + node2 = transformer[i].getNode_l(); + con = transformer[i].getType(); + //TODO + //entityMtrans.getMtrans()[node1 - 1][node2 - 1] = con; + //entityMtrans.getMtrans()[node2 - 1][node1 - 1] = con; + } + StringBuilder str = new StringBuilder(); + for (i = 0; i < FinalData.NODE_NUM; i++) { + for (j = 0; j < FinalData.NODE_NUM; j++) { + str.append(entityMtrans.getMtrans()[i][j]).append(" "); + if (j == (FinalData.NODE_NUM - 1)) { + str.append("\r\n"); + } + } + } + + // 类型匹配矩阵Matrixcata + // Matrixcata模式匹配矩阵,列为节点数,行为总类别数,元素为第一个节点分别是1-6类别情况下其他节点类别情况。 + // 元素1,2,3,4,5,6 分别对应 Dc,Cb,Da,Cc,Db,Ca + // 设置矩阵第一行元素 + for (i = 0; i < FinalData.NODE_NUM; i++) { + entityMtrans.getMatrixcata0()[0][i] = 0; + } + for (i = 1; i < FinalData.NODE_NUM; i++) { + // 路径缓存清空 + for (j = 0; j < FinalData.MAX_PATH_NUM; j++) { + for (k = 0; k < (FinalData.NODE_NUM + 1); k++) { + entityMtrans.getPossiable_path()[j][k] = 0; + } + } + entityMtrans.setPath_num(0); + // 寻找路径 + src_node[0] = 0; + findPath(entityMtrans, src_node, i, 0, 1, FinalData.NODE_NUM); + if (entityMtrans.getPath_num() != 0) { + entityMtrans.getMatrixcata0()[0][i] = entityMtrans.getPossiable_path()[0][FinalData.NODE_NUM]; // 采用第一条路径 + } else { + entityMtrans.getMatrixcata0()[0][i] = FinalData.DATA_INF; // 找不到路径填大值表示不通 + } + } + // 构造矩阵其他行元素 + for (i = 1; i < FinalData.EVT_TYPE_NUM; i++) { + for (j = 0; j < FinalData.NODE_NUM; j++) + // EntityGroupData.Matrixcata0[i][j] = + // EntityGroupData.Matrixcata0[0][j] + i; + { + if (entityMtrans.getMatrixcata0()[0][j] == FinalData.DATA_INF) { + entityMtrans.getMatrixcata0()[i][j] = FinalData.DATA_INF; + } else { + entityMtrans.getMatrixcata0()[i][j] = entityMtrans.getMatrixcata0()[0][j] + i; + } + } + } + // 将数据归类到0-5 + for (i = 0; i < FinalData.EVT_TYPE_NUM; i++) { + for (j = 0; j < FinalData.NODE_NUM; j++) { + entityMtrans.getMatrixcata1()[i][j] = entityMtrans.getMatrixcata0()[i][j] % 6; + } + } + // 0换成6,将数据归类到1-6 + for (i = 0; i < FinalData.EVT_TYPE_NUM; i++) { + for (j = 0; j < FinalData.NODE_NUM; j++) { + if (entityMtrans.getMatrixcata1()[i][j] == 0) { + entityMtrans.getMatrixcata1()[i][j] = 6; + } + } + } + str.delete(0, str.length()); + for (i = 0; i < FinalData.EVT_TYPE_NUM; i++) { + for (j = 0; j < FinalData.NODE_NUM; j++) { + str.append(entityMtrans.getMatrixcata1()[i][j]).append(" "); + if (j == (FinalData.NODE_NUM - 1)) { + str.append("\r\n"); + } + } + } + + } + + public static int findPath(EntityMtrans entityMtrans, int[] OriginalNode, int destination, int Weight, int src_num, int node_num) // 深度优先搜索 + { + int i, j; + int last_node; + int nextNodes[] = new int[FinalData.NODE_NUM]; + int nextNode_num = 0; + int nextNodes0[] = new int[FinalData.NODE_NUM]; + int nextNode_num0 = 0; + int tmpPath[] = new int[FinalData.NODE_NUM + 1]; + int tmpPath_num; + if (src_num < 1) // 源节点个数不对 + { + return 1; + } + last_node = OriginalNode[src_num - 1]; + if (last_node > node_num) // 判断最后一个节点号是否在范围内 + { + return 1; + } + for (i = 0; i < node_num; i++) { + // if((Mtrans[last_node][i]>0)&&(Mtrans[last_node][i] 0) // 寻找相同的节点 + { + nextNodes[nextNode_num] = i; + nextNode_num++; + } + } + // 如果一条路的最后一个节点就是目标节点,说明此路径是所有路径中的一条,可以直接return + if (last_node == destination) { + if (entityMtrans.getPath_num() >= FinalData.MAX_PATH_NUM) { + return 1; + } + for (i = 0; i < src_num; i++) { + entityMtrans.getPossiable_path()[entityMtrans.getPath_num()][i] = OriginalNode[i]; + } + entityMtrans.getPossiable_path()[entityMtrans.getPath_num()][FinalData.NODE_NUM] = Weight; // 最后一个节点填入变压器连接 + entityMtrans.setPath_num(entityMtrans.getPath_num() + 1); + } else { + for (i = 0; i < src_num; i++) { + if (destination == OriginalNode[i]) { + return 1; + } + } + } + // 判断下一个节点有没有目的节点 + for (i = 0; i < nextNode_num; i++) { + if (nextNodes[i] == destination) { + // 先清零; + for (j = 0; j < (FinalData.NODE_NUM + 1); j++) { + tmpPath[j] = 0; + } + // 填入源节点 + for (j = 0; j < src_num; j++) { + tmpPath[j] = OriginalNode[j]; + } + tmpPath[src_num] = destination; // 目的节点加在后面 + tmpPath[FinalData.NODE_NUM] = Weight + entityMtrans.getMtrans()[last_node][destination]; // 最后一个点填入变压器累计 + tmpPath_num = src_num + 1; + if (entityMtrans.getPath_num() >= FinalData.MAX_PATH_NUM) { + return 1; + } + for (j = 0; j < (FinalData.NODE_NUM + 1); j++) { + entityMtrans.getPossiable_path()[entityMtrans.getPath_num()][j] = tmpPath[j]; // tmpPath为路径的路阻 + } + entityMtrans.setPath_num(entityMtrans.getPath_num() + 1); + nextNodes[i] = 0; + if (nextNode_num != 0) // if(nextNode_num) + { + nextNode_num--; + } + } else { + // 判断如果源节点中有下一个节点,不再寻找处理 + for (j = 0; j < src_num; j++) { + if (nextNodes[i] == OriginalNode[j]) { + nextNodes[i] = 0; + } + } + } + } + // 不是目的节点的下一节点继续寻找 + for (i = 0; i < nextNode_num; i++) { + if (nextNodes[i] != 0) { + nextNodes0[nextNode_num0] = nextNodes[i]; + nextNode_num0++; + } + } + for (i = 0; i < nextNode_num0; i++) { + // 填入源节点 + for (j = 0; j < src_num; j++) { + tmpPath[j] = OriginalNode[j]; + } + tmpPath[src_num] = nextNodes0[i]; // 下一个节点加在后面 + tmpPath_num = src_num + 1; + findPath(entityMtrans, tmpPath, destination, (Weight + entityMtrans.getMtrans()[last_node][nextNodes0[i]]), tmpPath_num, + node_num); + } + return 0; + } + + public static int sort_Tstart(EntityGroupData buf) { + int res_num, out_num; + int idx = 0; + if ((buf == null) || (buf.getEvt_in_num() == 0)) { + return 0; + } + res_num = buf.getEvt_in_num(); + while (res_num > 0) { // while(res_num) + out_num = sort_Tstart_single(buf); + // 输出缓冲填入归集缓冲 + // buf.getGrp_buf()[idx] = buf.getOut_buf(); + System.arraycopy(buf.getOut_buf(), 0, buf.getGrp_buf()[idx], 0, buf.getOut_buf().length); + buf.getGrp_num()[idx] = out_num; + // 未归集填入输入缓冲 + // buf.setIn_buf(buf.getRes_buf()); + System.arraycopy(buf.getRes_buf(), 0, buf.getIn_buf(), 0, buf.getRes_buf().length); + buf.setEvt_in_num(buf.getEvt_res_num()); + idx++; + if (idx >= FinalData.MAX_GROUP_NUM) // 分组超限 + { + break; + } + if (out_num <= res_num) { + res_num = res_num - out_num; + } else { + break; // 分组数目超限 + } + } + buf.setGrp_all_num(idx); + return 1; + } + + public static int sort_Tstart_single(EntityGroupData buf) { + int i; + int start_time; + int thd_time1, thd_time2; + if ((buf == null) || (buf.getEvt_in_num() == 0)) { + return 0; + } + buf.setEvt_out_num(0); + buf.setEvt_res_num(0); + // 如果只有一个事件直接赋值返回 + if (buf.getEvt_in_num() == 1) { + buf.setEvt_out_num(1); + // buf.getOut_buf()[0] = buf.getIn_buf()[0]; + // System.arraycopy(buf.getIn_buf()[0], 0, buf.getOut_buf()[0], 0, + // 1); + buf.getOut_buf()[0] = (EntityGroupEvtData) buf.getIn_buf()[0].objClone(); + return buf.getEvt_out_num(); + } + start_time = buf.getIn_buf()[0].getStart_time(); + thd_time1 = start_time - FinalData.TIME_THRESHOLD; + thd_time2 = start_time + FinalData.TIME_THRESHOLD; + // 判断时标阀值门槛归集 + for (i = 0; i < buf.getEvt_in_num(); i++) { + start_time = buf.getIn_buf()[i].getStart_time(); + // 在阈值范围内 + if ((start_time >= thd_time1) && (start_time <= thd_time2)) { + // buf.getOut_buf()[buf.getEvt_out_num()] = buf.getIn_buf()[i]; + // System.arraycopy(buf.getIn_buf()[i], 0, + // buf.getOut_buf()[buf.getEvt_out_num()], 0, 1); + buf.getOut_buf()[buf.getEvt_out_num()] = (EntityGroupEvtData) buf.getIn_buf()[i].objClone(); + buf.setEvt_out_num(buf.getEvt_out_num() + 1); + } else { + // buf.getRes_buf()[buf.getEvt_res_num()] = buf.getIn_buf()[i]; + // System.arraycopy(buf.getIn_buf()[i], 0, + // buf.getRes_buf()[buf.getEvt_res_num()], 0, 1); + buf.getRes_buf()[buf.getEvt_res_num()] = (EntityGroupEvtData) buf.getIn_buf()[i].objClone(); + buf.setEvt_res_num(buf.getEvt_res_num() + 1); + } + } + return buf.getEvt_out_num(); + } + + public static int sort_cata(EntityGroupData buf, int idx) { + int i, j; + int cata, node; + int odrer[] = new int[FinalData.MAX_CATA_NUM + 2]; + // 针对类别是1-6的数据进行模式匹配,并标注属于哪一个模式 + + for (i = 0; i < (FinalData.MAX_CATA_NUM + 2); i++) { + odrer[i] = 0; + } + // 暂降类型转换 + // 将类型7,8,9转换为6,2,4 + // 其中7,8,9分别对应BC两相接地,AC两相接地,AB两相接地,1,2,3,4,5,6分别对应Dc,Cb,Da,Cc,Db,Ca + /* + * for (i = 0; i < buf.getGrp_num()[idx]; i++) { if + * (buf.getGrp_buf()[idx][i].getCata() == 7) + * buf.getGrp_buf()[idx][i].setCata(6); if + * (buf.getGrp_buf()[idx][i].getCata() == 8) + * buf.getGrp_buf()[idx][i].setCata(2); if + * (buf.getGrp_buf()[idx][i].getCata() == 9) + * buf.getGrp_buf()[idx][i].setCata(4); } + */ + for (i = 0; i < buf.getGrp_num()[idx]; i++) { + /* + * if (buf.getGrp_buf()[idx][i].getCata() == 10) //事件类型未知 + * buf.getGrp_buf()[idx][i].setCata(11); if + * (buf.getGrp_buf()[idx][i].getCata() == 9) //三相 + * buf.getGrp_buf()[idx][i].setCata(10); + */ + + if (buf.getGrp_buf()[idx][i].getCata() == 0) { + buf.getGrp_buf()[idx][i].setCata(6); + } + + if (buf.getGrp_buf()[idx][i].getCata() == 6) { + buf.getGrp_buf()[idx][i].setCata(6); + } + if (buf.getGrp_buf()[idx][i].getCata() == 7) { + buf.getGrp_buf()[idx][i].setCata(2); + } + if (buf.getGrp_buf()[idx][i].getCata() == 8) { + buf.getGrp_buf()[idx][i].setCata(4); + } + } + + // 将数据进行模式匹配,并标注属于哪一个模式 + for (i = 0; i < buf.getGrp_num()[idx]; i++) { + cata = buf.getGrp_buf()[idx][i].getCata(); + node = buf.getGrp_buf()[idx][i].getNode(); + + if ((node > FinalData.NODE_NUM) || (buf.getMatrixcata()[0][node - 1] == FinalData.DATA_INF)) { + buf.getGrp_buf()[idx][i].setCata2(FinalData.QVVR_TYPE_OUTOFRANGE); + // buf.getGrp_cata_buf()[idx][FinalData.MAX_CATA_NUM + + // 1][odrer[FinalData.MAX_CATA_NUM + 1]] = + // buf.getGrp_buf()[idx][i]; + // System.arraycopy(buf.getGrp_buf()[idx][i], 0, + // buf.getGrp_cata_buf()[idx][FinalData.MAX_CATA_NUM + + // 1][odrer[FinalData.MAX_CATA_NUM + 1]], 0, 1); + buf.getGrp_cata_buf()[idx][FinalData.MAX_CATA_NUM + 1][odrer[FinalData.MAX_CATA_NUM + + 1]] = (EntityGroupEvtData) buf.getGrp_buf()[idx][i].objClone(); + odrer[FinalData.MAX_CATA_NUM + 1]++; + } else if (cata == FinalData.QVVR_TYPE_UNKNOWN) { + buf.getGrp_buf()[idx][i].setCata2(FinalData.QVVR_TYPE_UNKNOWN); + // buf.getGrp_cata_buf()[idx][FinalData.MAX_CATA_NUM][odrer[FinalData.MAX_CATA_NUM]] + // = buf.getGrp_buf()[idx][i]; + // System.arraycopy(buf.getGrp_buf()[idx][i], 0, + // buf.getGrp_cata_buf()[idx][FinalData.MAX_CATA_NUM][odrer[FinalData.MAX_CATA_NUM]], + // 0, 1); + buf.getGrp_cata_buf()[idx][FinalData.MAX_CATA_NUM][odrer[FinalData.MAX_CATA_NUM]] = (EntityGroupEvtData) buf + .getGrp_buf()[idx][i].objClone(); + odrer[FinalData.MAX_CATA_NUM]++; + } else if (cata == FinalData.QVVR_TYPE_THREE) // ÈıÏàÔݽµ¹éÀà + { + buf.getGrp_buf()[idx][i].setCata2(FinalData.QVVR_TYPE_THREE); + // buf.getGrp_cata_buf()[idx][FinalData.MAX_CATA_NUM - + // 1][odrer[FinalData.MAX_CATA_NUM - 1]] = + // buf.getGrp_buf()[idx][i]; + // System.arraycopy(buf.getGrp_buf()[idx][i], 0, + // buf.getGrp_cata_buf()[idx][FinalData.MAX_CATA_NUM - + // 1][odrer[FinalData.MAX_CATA_NUM - 1]], 0, 1); + buf.getGrp_cata_buf()[idx][FinalData.MAX_CATA_NUM - 1][odrer[FinalData.MAX_CATA_NUM + - 1]] = (EntityGroupEvtData) buf.getGrp_buf()[idx][i].objClone(); + odrer[FinalData.MAX_CATA_NUM - 1]++; + } else // 1-6类暂降归类 + { + for (j = 0; j < FinalData.MAX_CATA_NUM; j++) { + if (cata == buf.getMatrixcata()[j][node - 1])// 判断数据类别属于第几行 + { + buf.getGrp_buf()[idx][i].setCata2(j + 1); + // 进行归类 + // buf.getGrp_cata_buf()[idx][j][odrer[j]] = + // buf.getGrp_buf()[idx][i]; + // System.arraycopy(buf.getGrp_buf()[idx][i], 0, + // buf.getGrp_cata_buf()[idx][j][odrer[j]], 0, 1); + buf.getGrp_cata_buf()[idx][j][odrer[j]] = (EntityGroupEvtData) buf.getGrp_buf()[idx][i] + .objClone(); + odrer[j]++; + } + } + } + } + for (i = 0; i < FinalData.MAX_CATA_NUM + 2; i++) { + buf.getGrp_cata_num()[idx][i] = odrer[i]; + } + return 0; + } +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/Utils.java b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/Utils.java new file mode 100644 index 000000000..6a4359b65 --- /dev/null +++ b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/Utils.java @@ -0,0 +1,102 @@ +package com.njcn.advance.utils; + +/** + * @Author: Sunwei 【sunW2016@163.com】 + * @Description: + * @Date: Create in 22:28 2018/3/5 + * @Modified By: + * @author njcn + */ + +import cn.hutool.core.collection.CollectionUtil; + +import java.util.ArrayList; +import java.util.List; + +/***************************************************************** + * 字符串转基础类型,可能转换不成功,封装该方法 + * 第一个参数为需要转换的字符串 + * 第二个参数为null时,直接抛出异常,为数值则传入一个默认值 +*****************************************************************/ +public class Utils { + public static int getIntValue(String s,Integer integer) { + try { + integer = Integer.parseInt(s); + } catch (Exception e) { + if (null == integer) { + throw e; + } + } + + return integer.intValue(); + } + + /** + * String对象转float + * + * @param f + * @return + */ + public static float getFloatValue(String s,Float f) { + try { + f = Float.parseFloat(s); + } catch (Exception e) { + if (null == f) { + throw e; + } + } + + return f.floatValue(); + } + + /** + * String对象转double + * + * @param d + * @return + */ + public static double getDoubleValue(String s,Double d) { + try { + d = Double.parseDouble(s); + } catch (Exception e) { + if (null == d) { + throw e; + } + } + + return d.doubleValue(); + } + + /** + * int转String对象 + */ + public static String int2String(int iValue) { + return Integer.toString(iValue); + } + + /** + * float转String + */ + public static String float2String(float fValue) { + return Float.toString(fValue); + } + + /** + * 按指定大小,分隔集合,将集合按规定个数分为n个部分 + * @author cdf + * @date 2021/10/26 + */ + public static List> splitList(List list, int len){ + if(CollectionUtil.isEmpty(list) || len<1){ + return null; + } + List> result = new ArrayList<>(); + int size = list.size(); + int count = (size+len-1)/1000; + for(int i=0;i subList= list.subList(i*len,((i+1)*len>size?size:len*(i+1))); + result.add(subList); + } + return result; + } +} diff --git a/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/qvvr_balance.dll b/pqs-advance/advance-boot/src/main/java/com/njcn/advance/utils/qvvr_balance.dll deleted file mode 100644 index 4a1ebabb3fb06219e36fb6dd64b0b48671207a99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 335479 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 z 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 TngPv#W checkLocalDateTime(String startTime,String endTime) { + List resultList = new ArrayList<>(); + if(StrUtil.isBlank(startTime) || StrUtil.isBlank(endTime)){ + throw new BusinessException(CommonResponseEnum.TIME_ERROR); + } + try { + startTime = startTime+StrUtil.SPACE+"00:00:00"; + endTime = endTime+StrUtil.SPACE+"23:59:59"; + LocalDateTime start = LocalDateTime.parse(startTime,DateTimeFormatter.ofPattern(DATE_TIME)); + LocalDateTime end = LocalDateTime.parse(endTime,DateTimeFormatter.ofPattern(DATE_TIME)); + resultList.add(start); + resultList.add(end); + } catch (Exception e) { + throw new BusinessException(CommonResponseEnum.TIME_ERROR); + } + return resultList; + } + + /** diff --git a/pqs-device/common-device-biz/src/main/java/com/njcn/device/biz/commApi/CommLedgerDeptClient.java b/pqs-device/common-device-biz/src/main/java/com/njcn/device/biz/commApi/CommLedgerDeptClient.java index 920716157..00f230f24 100644 --- a/pqs-device/common-device-biz/src/main/java/com/njcn/device/biz/commApi/CommLedgerDeptClient.java +++ b/pqs-device/common-device-biz/src/main/java/com/njcn/device/biz/commApi/CommLedgerDeptClient.java @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import java.util.List; /** - * + * 仅供pms系统修改单位部门时候调用,同步修改pms台账表里的单位部门 * @author cdf * @date 2023/4/24 */ diff --git a/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/GeneralDeviceInfoClient.java b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/GeneralDeviceInfoClient.java index a9f8be44b..13f69aa63 100644 --- a/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/GeneralDeviceInfoClient.java +++ b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/GeneralDeviceInfoClient.java @@ -117,7 +117,7 @@ public interface GeneralDeviceInfoClient { HttpResult> getOnlineRateByDevIds(@RequestBody OnlineRateParam param); /** - *根据单位获取投运监测点 + *根据单位获取投运监测点(双系统) * @author cdf * @date 2023/6/7 */ @@ -126,7 +126,7 @@ public interface GeneralDeviceInfoClient { /** - *根据单位获取投运监测点 + *根据单位获取暂态系统投运监测点 * @author cdf * @date 2023/6/7 */ diff --git a/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/TransformerClient.java b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/TransformerClient.java new file mode 100644 index 000000000..3b2887b3d --- /dev/null +++ b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/TransformerClient.java @@ -0,0 +1,28 @@ +package com.njcn.device.pq.api; + +import com.njcn.common.pojo.constant.ServerInfo; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.device.pq.api.fallback.TerminalBaseClientFallbackFactory; +import com.njcn.device.pq.pojo.dto.transformer.EntityLogicDTO; +import com.njcn.device.pq.pojo.po.Line; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.List; + +/** + * @author hongawen + * @version 1.0.0 + * @date 2022年02月14日 14:02 + */ +@FeignClient(value = ServerInfo.DEVICE, path = "/pqsTransformer", fallbackFactory = TerminalBaseClientFallbackFactory.class, contextId = "pqsTransformer") +public interface TransformerClient { + + + HttpResult> getLogic(); + + + + +} diff --git a/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/fallback/TransformerClientFallbackFactory.java b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/fallback/TransformerClientFallbackFactory.java new file mode 100644 index 000000000..cdc0e3ede --- /dev/null +++ b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/api/fallback/TransformerClientFallbackFactory.java @@ -0,0 +1,45 @@ +package com.njcn.device.pq.api.fallback; + +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.device.biz.utils.DeviceEnumUtil; +import com.njcn.device.pq.api.TerminalBaseClient; +import com.njcn.device.pq.api.TransformerClient; +import com.njcn.device.pq.pojo.dto.transformer.EntityLogicDTO; +import com.njcn.device.pq.pojo.po.Line; +import feign.hystrix.FallbackFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author hongawen + * @version 1.0.0 + * @date 2022年02月14日 14:03 + */ +@Slf4j +@Component +public class TransformerClientFallbackFactory implements FallbackFactory { + @Override + public TransformerClient create(Throwable throwable) { + //判断抛出异常是否为解码器抛出的业务异常 + Enum exceptionEnum = CommonResponseEnum.SERVICE_FALLBACK; + if (throwable.getCause() instanceof BusinessException) { + BusinessException businessException = (BusinessException) throwable.getCause(); + exceptionEnum = DeviceEnumUtil.getExceptionEnum(businessException.getResult()); + } + Enum finalExceptionEnum = exceptionEnum; + return new TransformerClient() + { + + @Override + public HttpResult> getLogic() { + return null; + } + }; + + + } +} diff --git a/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/pojo/dto/transformer/EntityLogicDTO.java b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/pojo/dto/transformer/EntityLogicDTO.java new file mode 100644 index 000000000..7908ba3ed --- /dev/null +++ b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/pojo/dto/transformer/EntityLogicDTO.java @@ -0,0 +1,26 @@ +package com.njcn.device.pq.pojo.dto.transformer; + +import lombok.Data; + +/** + * pqs + * + * @author cdf + * @date 2023/8/8 + */ +@Data +public class EntityLogicDTO { + + // 物理隔绝GUID + private String tPIndex; + /* 变压器逻辑上节点 */ + private String node_h; + //变压器逻辑下节点 + private String node_l; + // 变压器连接方式 + private Integer type; + //变压器物理上节点 + private String nodeBefore; + //变压器物理下节点 + private String nodeNext; +} diff --git a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/controller/PqsTransformerController.java b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/controller/PqsTransformerController.java index 146981475..eac69f4ae 100644 --- a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/controller/PqsTransformerController.java +++ b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/controller/PqsTransformerController.java @@ -8,6 +8,7 @@ import com.njcn.common.pojo.enums.common.LogEnum; import com.njcn.common.pojo.enums.response.CommonResponseEnum; import com.njcn.common.pojo.response.HttpResult; import com.njcn.common.utils.HttpResultUtil; +import com.njcn.device.pq.pojo.dto.transformer.EntityLogicDTO; import com.njcn.device.pq.pojo.param.PqsTransformerParam; import com.njcn.device.pq.pojo.vo.PqsTflgassVO; import com.njcn.device.pq.pojo.vo.PqsTransformerVO; @@ -112,5 +113,15 @@ public class PqsTransformerController extends BaseController { List terminalTree = iPqsTransformerService.getTransformerTree(); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, terminalTree, methodDescribe); } + + @GetMapping("/getLogic") + @ApiOperation(value = "获取变压器策略详情") + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + public HttpResult> getLogic() { + String methodDescribe = getMethodDescribe("getLogic"); + List entityLogicDTOList = iPqsTransformerService.getLogic(); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, entityLogicDTOList, methodDescribe); + } + } diff --git a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/mapper/PqsTflgassMapper.java b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/mapper/PqsTflgassMapper.java index bf38ba931..f47d69587 100644 --- a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/mapper/PqsTflgassMapper.java +++ b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/mapper/PqsTflgassMapper.java @@ -1,6 +1,7 @@ package com.njcn.device.pq.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.njcn.device.pq.pojo.dto.transformer.EntityLogicDTO; import com.njcn.device.pq.pojo.po.PqsTflgass; import org.apache.ibatis.annotations.Param; @@ -25,4 +26,9 @@ public interface PqsTflgassMapper extends BaseMapper { */ List selectFlgass(@Param("id") String id,@Param("ids") List ids); + /** + * 获取变压器策略物理节点 + */ + List getLogic(); + } diff --git a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/mapper/mapping/PqsTflgassMapper.xml b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/mapper/mapping/PqsTflgassMapper.xml index d39adacdb..8e968ca1b 100644 --- a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/mapper/mapping/PqsTflgassMapper.xml +++ b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/mapper/mapping/PqsTflgassMapper.xml @@ -23,4 +23,18 @@ + + diff --git a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/IPqsTransformerService.java b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/IPqsTransformerService.java index e84f29754..701b90656 100644 --- a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/IPqsTransformerService.java +++ b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/IPqsTransformerService.java @@ -2,6 +2,7 @@ package com.njcn.device.pq.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; +import com.njcn.device.pq.pojo.dto.transformer.EntityLogicDTO; import com.njcn.device.pq.pojo.param.PqsTransformerParam; import com.njcn.device.pq.pojo.po.PqsTransformer; import com.njcn.device.pq.pojo.vo.PqsTflgassVO; @@ -84,4 +85,11 @@ public interface IPqsTransformerService extends IService { * @date 2023/7/26 */ List getTransformerTree(); + + /** + * 获取所有策略的详情 + * @author cdf + * @date 2023/8/8 + */ + List getLogic(); } diff --git a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/PqsTransformerServiceImpl.java b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/PqsTransformerServiceImpl.java index d8cc9ec4d..725db8de2 100644 --- a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/PqsTransformerServiceImpl.java +++ b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/PqsTransformerServiceImpl.java @@ -14,6 +14,7 @@ import com.njcn.device.pq.enums.PvDeviceResponseEnum; import com.njcn.device.pq.mapper.LineMapper; import com.njcn.device.pq.mapper.PqsTflgassMapper; import com.njcn.device.pq.mapper.PqsTransformerMapper; +import com.njcn.device.pq.pojo.dto.transformer.EntityLogicDTO; import com.njcn.device.pq.pojo.param.PqsTransformerParam; import com.njcn.device.pq.pojo.po.Line; import com.njcn.device.pq.pojo.po.PqsTflgass; @@ -377,6 +378,11 @@ public class PqsTransformerServiceImpl extends ServiceImpl getLogic() { + return pqsTflgassMapper.getLogic(); + } + /** * 获取全部子节点 * @@ -576,4 +582,6 @@ public class PqsTransformerServiceImpl extends ServiceImpl queryEventDetailByEventId(@RequestParam("eventId")String eventId); +} diff --git a/pqs-event/event-api/src/main/java/com/njcn/event/api/fallback/RmpEventDetailFeignClientFallbackFactory.java b/pqs-event/event-api/src/main/java/com/njcn/event/api/fallback/RmpEventDetailFeignClientFallbackFactory.java new file mode 100644 index 000000000..ddb40fd6d --- /dev/null +++ b/pqs-event/event-api/src/main/java/com/njcn/event/api/fallback/RmpEventDetailFeignClientFallbackFactory.java @@ -0,0 +1,46 @@ +package com.njcn.event.api.fallback; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.event.api.EventDetailFeignClient; +import com.njcn.event.api.RmpEventDetailFeignClient; +import com.njcn.event.pojo.po.EventDetail; +import com.njcn.event.pojo.po.RmpEventDetailPO; +import com.njcn.event.pojo.vo.AdvanceEventDetailVO; +import com.njcn.event.pojo.vo.GeneralVO; +import com.njcn.event.utils.EventlEnumUtil; +import com.njcn.web.pojo.param.BaseParam; +import feign.hystrix.FallbackFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +/** + * @date 2023/07/21 + */ +@Slf4j +@Component +public class RmpEventDetailFeignClientFallbackFactory implements FallbackFactory { + @Override + public RmpEventDetailFeignClient create(Throwable throwable) { + //判断抛出异常是否为解码器抛出的业务异常 + Enum exceptionEnum = CommonResponseEnum.SERVICE_FALLBACK; + if (throwable.getCause() instanceof BusinessException) { + BusinessException businessException = (BusinessException) throwable.getCause(); + exceptionEnum = EventlEnumUtil.getExceptionEnum(businessException.getResult()); + } + Enum finalExceptionEnum = exceptionEnum; + return new RmpEventDetailFeignClient() { + + @Override + public HttpResult queryEventDetailByEventId(String eventId) { + log.error("{}异常,降级处理,异常为:{}", "查询暂降明细", throwable.toString()); + throw new BusinessException(finalExceptionEnum); + } + }; + } +} diff --git a/pqs-event/event-api/src/main/java/com/njcn/event/pojo/po/RmpEventDetailAssPO.java b/pqs-event/event-api/src/main/java/com/njcn/event/pojo/po/RmpEventDetailAssPO.java new file mode 100644 index 000000000..f80d90518 --- /dev/null +++ b/pqs-event/event-api/src/main/java/com/njcn/event/pojo/po/RmpEventDetailAssPO.java @@ -0,0 +1,41 @@ +package com.njcn.event.pojo.po; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.njcn.db.bo.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * pqs + * + * @author cdf + * @date 2023/8/9 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@TableName("r_mp_event_detail_ass") +public class RmpEventDetailAssPO extends BaseEntity { + + /** + *事件关联分析表uuid + */ + private String eventAssId; + + /** + *发生时间(归一化中第一个时间) + */ + private LocalDateTime timeId; + + /** + *关联事件描述 + */ + private String describe; + + /** + *是否进行范围分析(0:分析;1:未分析) + */ + private Integer analyseFlag; + +} diff --git a/pqs-event/event-api/src/main/java/com/njcn/event/pojo/po/RmpEventDetailPO.java b/pqs-event/event-api/src/main/java/com/njcn/event/pojo/po/RmpEventDetailPO.java index 89502d3cc..55b22de10 100644 --- a/pqs-event/event-api/src/main/java/com/njcn/event/pojo/po/RmpEventDetailPO.java +++ b/pqs-event/event-api/src/main/java/com/njcn/event/pojo/po/RmpEventDetailPO.java @@ -85,6 +85,7 @@ public class RmpEventDetailPO implements Serializable { private String sagsource; @ApiModelProperty(value = "开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") private LocalDateTime startTime; @ApiModelProperty(value = "格式化开始时间") diff --git a/pqs-event/event-api/src/main/java/com/njcn/event/pojo/vo/AdvanceEventDetailVO.java b/pqs-event/event-api/src/main/java/com/njcn/event/pojo/vo/AdvanceEventDetailVO.java new file mode 100644 index 000000000..46650f30d --- /dev/null +++ b/pqs-event/event-api/src/main/java/com/njcn/event/pojo/vo/AdvanceEventDetailVO.java @@ -0,0 +1,110 @@ +package com.njcn.event.pojo.vo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * pqs + * + * @author cdf + * @date 2023/7/20 + */ +@Data +public class AdvanceEventDetailVO { + + + @ApiModelProperty(value = "暂时事件ID") + private String eventId; + + @ApiModelProperty(value = "监测点ID") + private String measurementPointId; + + @ApiModelProperty(value = "监测点ID(复制)") + private String lineId; + + @ApiModelProperty(value = "统计类型") + private String eventType; + + @ApiModelProperty(value = "暂降原因(Event_Reason)") + private String advanceReason; + + @ApiModelProperty(value = "暂降类型(Event_Type)") + private String advanceType; + + @ApiModelProperty(value = "事件关联分析表Guid") + private String eventassIndex; + + @ApiModelProperty(value = "dq计算持续时间 ") + private Double dqTime; + + @ApiModelProperty(value = "特征值计算更新时间(外键PQS_Relevance的Time字段)") + @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss") + private LocalDateTime dealTime; + + @ApiModelProperty(value = "默认事件个数为0") + private Integer num; + + @ApiModelProperty(value = "波形文件是否从装置招到本地(0:未招,1:已招)默认值为0") + private Integer fileFlag; + + @ApiModelProperty(value = "特征值计算标志(0,未处理;1,已处理; 2,已处理,无结果;3,计算失败)默认值为0") + private Integer dealFlag; + + @ApiModelProperty(value = "处理结果第一条事件发生时间(读comtra文件获取)") + @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss") + private LocalDateTime firstTime; + + @ApiModelProperty(value = "处理结果第一条事件暂降类型(字典表PQS_Dicdata)") + private String firstType; + + @ApiModelProperty(value = "处理结果第一条事件发生时间毫秒(读comtra文件获取)") + private Double firstMs; + + @ApiModelProperty(value = "暂降能量") + private Double energy; + + @ApiModelProperty(value = "暂降严重度") + private Double severity; + + @ApiModelProperty(value = "暂降源与监测位置关系 Upper:上游;Lower :下游;Unknown :未知;为空则是未计算") + private String sagsource; + + @ApiModelProperty(value = "开始时间") + @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss.SSS") + private LocalDateTime startTime; + + @ApiModelProperty(value = "持续时间,单位秒") + private Double duration; + + @ApiModelProperty(value = "特征幅值") + private Double featureAmplitude; + + @ApiModelProperty(value = "相别") + private String phase; + + @ApiModelProperty(value = "事件描述") + private String eventDescribe; + + @ApiModelProperty(value = "波形路径") + private String wavePath; + + private Double transientValue; + + private String gdName; + + private String subName; + + private String voltageId; + + @ApiModelProperty(value = "特征值是否计算") + private String featureAmplitudeFlag; + + @ApiModelProperty(value = "录波文件是否存在") + private String boFileFlag; +} diff --git a/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/AdvancedAnalysisController.java b/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/AdvancedAnalysisController.java deleted file mode 100644 index 07141d478..000000000 --- a/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/AdvancedAnalysisController.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.njcn.event.controller.majornetwork; - -import io.swagger.annotations.Api; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * pqs-event - * - * @author cdf - * @date 2022/6/23 - */ -@Slf4j -@RestController -@RequestMapping("/advance") -@Api(tags = "高级分析") -@AllArgsConstructor -public class AdvancedAnalysisController { -} diff --git a/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/RmpEventDetailController.java b/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/RmpEventDetailController.java index b311e2332..a7462e778 100644 --- a/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/RmpEventDetailController.java +++ b/pqs-event/event-boot/src/main/java/com/njcn/event/controller/majornetwork/RmpEventDetailController.java @@ -9,11 +9,13 @@ import com.njcn.common.pojo.response.HttpResult; import com.njcn.common.utils.HttpResultUtil; import com.njcn.event.pojo.param.UniversalFrontEndParam; import com.njcn.event.pojo.po.RmpEventDetailPO; +import com.njcn.event.pojo.vo.AdvanceEventDetailVO; import com.njcn.event.pojo.vo.RmpEventDetailVO; import com.njcn.event.pojo.vo.TransientVO; import com.njcn.event.service.majornetwork.RmpEventDetailService; import com.njcn.system.pojo.po.DictData; import com.njcn.web.controller.BaseController; +import com.njcn.web.pojo.param.BaseParam; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -22,6 +24,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.Objects; /** * 主网-暂态事件明细 @@ -92,4 +95,38 @@ public class RmpEventDetailController extends BaseController { return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, rmpEventDetailVO, methodDescribe); } + + /** + * 高级算法-暂降事件关联分析主列表 + * @author cdf + * @date 2023/7/20 + */ + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/querySagEvents") + @ApiOperation("高级算法-暂降事件关联分析主列表") + public HttpResult> querySagEvents(@RequestBody BaseParam baseParam){ + String methodDescribe = getMethodDescribe("querySagEvents"); + Page page = rmpEventDetailService.querySagEvents(baseParam); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, page, methodDescribe); + } + + + + + /** + * 获取暂态事件明细 + * @author cdf + * @date 2023/7/28 + */ + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @GetMapping("/queryEventDetailByEventId") + @ApiOperation("获取暂态事件明细") + public HttpResult queryEventDetailByEventId(@RequestParam("eventId")String eventId){ + String methodDescribe = getMethodDescribe("queryEventDetailByEventId"); + RmpEventDetailPO objResult = rmpEventDetailService.queryEventDetailByEventId(eventId); + if(Objects.nonNull(objResult)){ + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, objResult, methodDescribe); + } + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, null, methodDescribe); + } } diff --git a/pqs-event/event-boot/src/main/java/com/njcn/event/service/majornetwork/Impl/RmpEventDetailServiceImpl.java b/pqs-event/event-boot/src/main/java/com/njcn/event/service/majornetwork/Impl/RmpEventDetailServiceImpl.java index 1f8a1dc60..03a8769d8 100644 --- a/pqs-event/event-boot/src/main/java/com/njcn/event/service/majornetwork/Impl/RmpEventDetailServiceImpl.java +++ b/pqs-event/event-boot/src/main/java/com/njcn/event/service/majornetwork/Impl/RmpEventDetailServiceImpl.java @@ -1,7 +1,10 @@ package com.njcn.event.service.majornetwork.Impl; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.njcn.common.pojo.dto.SimpleDTO; import com.njcn.common.pojo.exception.BusinessException; @@ -14,11 +17,14 @@ import com.njcn.device.pms.pojo.dto.PwPmsMonitorDTO; import com.njcn.device.pms.pojo.param.PmsDeviceInfoParam; import com.njcn.device.pms.pojo.param.PmsMonitorParam; import com.njcn.device.pms.pojo.po.Monitor; +import com.njcn.device.pq.api.GeneralDeviceInfoClient; import com.njcn.device.pq.api.LineFeignClient; import com.njcn.device.pq.pojo.vo.AreaLineInfoVO; import com.njcn.event.mapper.majornetwork.RmpEventDetailMapper; import com.njcn.event.pojo.param.UniversalFrontEndParam; import com.njcn.event.pojo.po.RmpEventDetailPO; +import com.njcn.event.pojo.vo.AdvanceEventDetailVO; +import com.njcn.event.pojo.vo.AreaLineVO; import com.njcn.event.pojo.vo.RmpEventDetailVO; import com.njcn.event.pojo.vo.TransientVO; import com.njcn.event.service.majornetwork.RmpEventDetailService; @@ -27,16 +33,17 @@ import com.njcn.system.enums.DicDataTypeEnum; import com.njcn.event.enums.EventResponseEnum; import com.njcn.system.pojo.po.DictData; import com.njcn.user.api.DeptFeignClient; +import com.njcn.web.factory.PageFactory; +import com.njcn.web.pojo.param.BaseParam; +import com.njcn.web.utils.RequestUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -65,6 +72,8 @@ public class RmpEventDetailServiceImpl extends ServiceImpl querySagEvents(BaseParam baseParam) { + Page pageResult = new Page<>(PageFactory.getPageNum(baseParam),PageFactory.getPageSize(baseParam)); + List lineIds = generalDeviceInfoClient.deptGetRunLineEvent(RequestUtil.getDeptIndex()).getData(); + if(CollUtil.isNotEmpty(lineIds)){ + LambdaQueryWrapper lambdaQueryWrapper =new LambdaQueryWrapper<>(); + lambdaQueryWrapper.isNull(RmpEventDetailPO::getEventassIndex); + Page poPage = this.page(new Page<>(PageFactory.getPageNum(baseParam),PageFactory.getPageSize(baseParam)),lambdaQueryWrapper); + + List tempLineIds = poPage.getRecords().stream().map(RmpEventDetailPO::getLineId).distinct().collect(Collectors.toList()); + + List temLine = lineFeignClient.getBaseLineAreaInfo(tempLineIds).getData(); + Map map = temLine.stream().collect(Collectors.toMap(AreaLineInfoVO::getLineId, Function.identity())); + + List advanceEventDetailVOList = BeanUtil.copyToList(poPage.getRecords(),AdvanceEventDetailVO.class); + advanceEventDetailVOList = advanceEventDetailVOList.stream().peek(item->{ + if(map.containsKey(item.getLineId())){ + item.setGdName(map.get(item.getLineId()).getGdName()); + item.setSubName(map.get(item.getLineId()).getSubName()); + switch (item.getDealFlag()) { + case 0: + item.setFeatureAmplitudeFlag(EnumFlag.UNTREATED.getDescription()); + break; + case 1: + item.setFeatureAmplitudeFlag(EnumFlag.PROCESSED.getDescription()); + break; + case 2: + item.setFeatureAmplitudeFlag(EnumFlag.NODATA.getDescription()); + break; + case 3: + item.setFeatureAmplitudeFlag(EnumFlag.PROCESSFAIL.getDescription()); + break; + default: + throw new IllegalStateException("未发现的类型: " + item.getDealFlag()); + } + //录波文件 + if(Objects.nonNull(item.getFileFlag()) && item.getFileFlag() == 1){ + item.setBoFileFlag(EnumFlag.EXIST.description); + }else { + item.setBoFileFlag(EnumFlag.ABSENCE.description); + } + + } + }).collect(Collectors.toList()); + + pageResult.setRecords(advanceEventDetailVOList); + pageResult.setTotal(poPage.getTotal()); + pageResult.setPages(poPage.getPages()); + pageResult.setSize(poPage.getSize()); + pageResult.setCurrent(poPage.getCurrent()); + return pageResult; + } + return pageResult; + } + + + + @Override + public RmpEventDetailPO queryEventDetailByEventId(String eventId) { + return this.getById(eventId); + } + + /** + * 内部枚举类:高级算法处理事件的标识描述 + */ + enum EnumFlag { + PROCESSED(1, "计算成功"), UNTREATED(0, "未计算"), EXIST(1, "存在"), ABSENCE(0, "不存在"), NODATA(2, "无结果"), PROCESSFAIL(3, "计算失败"); + + private final Integer code; + private final String description; + + EnumFlag(Integer code, String description) { + this.code = code; + this.description = description; + } + + public Integer getCode() { + return code; + } + + public String getDescription() { + return description; + } + } } diff --git a/pqs-event/event-boot/src/main/java/com/njcn/event/service/majornetwork/RmpEventDetailService.java b/pqs-event/event-boot/src/main/java/com/njcn/event/service/majornetwork/RmpEventDetailService.java index 0b31d267e..fe16422c5 100644 --- a/pqs-event/event-boot/src/main/java/com/njcn/event/service/majornetwork/RmpEventDetailService.java +++ b/pqs-event/event-boot/src/main/java/com/njcn/event/service/majornetwork/RmpEventDetailService.java @@ -1,11 +1,14 @@ package com.njcn.event.service.majornetwork; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.njcn.event.pojo.param.UniversalFrontEndParam; import com.njcn.event.pojo.po.RmpEventDetailPO; +import com.njcn.event.pojo.vo.AdvanceEventDetailVO; import com.njcn.event.pojo.vo.RmpEventDetailVO; import com.njcn.event.pojo.vo.TransientVO; import com.njcn.system.pojo.po.DictData; +import com.njcn.web.pojo.param.BaseParam; import org.springframework.web.bind.annotation.RequestParam; import java.util.List; @@ -43,4 +46,14 @@ public interface RmpEventDetailService extends IService { RmpEventDetailVO getTransientDetailById(String eventId,String sysType,Integer smallType); + Page querySagEvents(BaseParam baseParam); + + + + /** + * + * @author cdf + * @date 2023/7/28 + */ + RmpEventDetailPO queryEventDetailByEventId(String eventId); } diff --git a/pqs-system/system-api/src/main/java/com/njcn/system/enums/SystemResponseEnum.java b/pqs-system/system-api/src/main/java/com/njcn/system/enums/SystemResponseEnum.java index c006a9912..1e509cf12 100644 --- a/pqs-system/system-api/src/main/java/com/njcn/system/enums/SystemResponseEnum.java +++ b/pqs-system/system-api/src/main/java/com/njcn/system/enums/SystemResponseEnum.java @@ -39,7 +39,7 @@ public enum SystemResponseEnum { TERMINAL_WIRING_EMPTY("A00367","查询字典监测终端接线方式为空"), MONITOR_TYPE_EMPTY("A00368","查询字典监测点类别为空"), ACTIVATED_STATE("A00369","必须存在一个已激活的系统类型"), - + ADVANCE_REASON("A00370","查询字典暂降原因为空"),