From dac47617b37ccfb834cd73ce0ee725e1101de214 Mon Sep 17 00:00:00 2001 From: feiyu02 <risaku@163.com> Date: 星期四, 14 八月 2025 17:25:51 +0800 Subject: [PATCH] 2025.8.14 1. 动态溯源模块添加滑动平均异常计算(调试中) --- src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcSlideAverage.kt | 194 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 194 insertions(+), 0 deletions(-) diff --git a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcSlideAverage.kt b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcSlideAverage.kt new file mode 100644 index 0000000..fb74b06 --- /dev/null +++ b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcSlideAverage.kt @@ -0,0 +1,194 @@ +package com.flightfeather.uav.biz.sourcetrace.exceptiontype + +import com.flightfeather.uav.biz.FactorFilter +import com.flightfeather.uav.biz.dataanalysis.BaseExceptionAnalysis +import com.flightfeather.uav.biz.dataanalysis.exceptiontype.ExceptionSlideAverage.Tag +import com.flightfeather.uav.biz.dataanalysis.model.ExceptionResult +import com.flightfeather.uav.biz.dataanalysis.model.ExceptionSlideAverageTag +import com.flightfeather.uav.biz.dataanalysis.model.ExceptionTag +import com.flightfeather.uav.biz.dataanalysis.model.ExceptionType +import com.flightfeather.uav.biz.sourcetrace.RealTimeAnalysisConfig +import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig +import com.flightfeather.uav.biz.sourcetrace.model.PollutedClue +import com.flightfeather.uav.biz.sourcetrace.model.RealTimeExceptionResult +import com.flightfeather.uav.domain.entity.BaseRealTimeData +import com.flightfeather.uav.lightshare.eunm.ExceptionStatusType +import com.flightfeather.uav.socket.eunm.FactorType +import kotlin.math.abs + +/** + * 婊戝姩骞冲潎鍊肩獊鍙樺紓甯� + * @date 2025/5/13 + * @author feiyu02 + */ +class RTExcSlideAverage : BaseExceptionAnalysis<RTExcWindLevelConfig, PollutedClue> { + + constructor(config: RTExcWindLevelConfig) : super(config) + + constructor(config: RTExcWindLevelConfig, callback: NewPolluteClueCallback) : super(config){ + this.callback = callback + } + + private var callback: NewPolluteClueCallback? = null + + private val historyDataList = mutableListOf<BaseRealTimeData>() + private val tempDataList = mutableListOf<BaseRealTimeData>() + private var lastData: BaseRealTimeData? = null + + protected val tagMap = mutableMapOf<FactorType, ExceptionSlideAverageTag>() + + override fun init() { + super.init() + historyDataList.clear() + tempDataList.clear() + lastData = null + + tagMap.clear() + config.factorFilter.mainList().forEach { f -> + tagMap[f] = ExceptionSlideAverageTag() + } + } + + override fun getExceptionType(): ExceptionType { + return ExceptionType.TYPE7 + } + + override fun onNextData(data: BaseRealTimeData) { + historyDataList.add(data) + // 鏁版嵁鍔犲叆涓存椂鏁扮粍 + tempDataList.add(data) + // 鏁版嵁閲忚秴鍑鸿缃暟閲忔椂锛屽幓闄ゅ綋鍓嶆暟鎹粍棣栦釜鏁版嵁 + if (tempDataList.size > config.changeTrendGroup) { + tempDataList.removeAt(0) + } + config.factorFilter.selectedList.forEach { s -> + val f = s.main + tagMap[f]?.let { + it.eIndex++ + it.endData = lastData + if (it.startData == null) { + it.startData = data + } + // 鏁版嵁閲忕瓑浜庤缃暟閲忔椂锛岃绠楀綋鍓嶆暟鎹粍鍧囧�� + if (tempDataList.size == config.changeTrendGroup) { + calAvg(f, tempDataList) + if (checkSlideAvg(f)) { + it.addExceptionData(data) + checkResult(s) + } else { + recordException(s, it, data) + } + } + } + } + lastData = data + } + + override fun onDone() { + checkResult(exceptionStatus = ExceptionStatusType.Ended) + } + + /** + * 寮傚父缁撴潫锛岃褰曞紓甯� + */ + fun recordException(factor: FactorFilter.SelectedFactor, tag: ExceptionSlideAverageTag, data: BaseRealTimeData) { + checkResult(factor, ExceptionStatusType.Ended) + tag.refreshAfterCheckResult(historyDataList, config.changeTrendGroup) + } + + /** + * 褰撳墠鏁版嵁鏈嚭鐜板紓甯告椂锛屾垨鏁版嵁寰幆缁撴潫鏃讹紝鍒ゆ柇鍚庣画姝ラ + */ + private fun checkResult( + factor: FactorFilter.SelectedFactor? = null, + exceptionStatus: ExceptionStatusType = ExceptionStatusType.InProgress + ) { + val tag = tagMap[factor?.main] + if (factor != null && tag != null) { + if (tag.exceptionExisted) { + onNewException(tag, factor, exceptionStatus) + } + } else { + config.factorFilter.selectedList.forEach { f -> + val tag1 = tagMap[f.main] ?: return@forEach + if (tag1.exceptionExisted) { + onNewException(tag1, f, exceptionStatus) + } + } + } + + } + + /** + * 鏂板鎴栨洿鏂颁竴鏉″紓甯� + */ + open fun onNewException(tag: ExceptionSlideAverageTag, factor: FactorFilter.SelectedFactor, exceptionStatus: ExceptionStatusType) { + if (tag.startData == null) return + val ex = newResult(listOf(factor to tag)) + + callback?.invoke(ex) + } + + fun newResult(exceptions: List<Pair<FactorFilter.SelectedFactor, ExceptionTag>>): PollutedClue { + return PollutedClue(exceptions, getExceptionType(), config, null) + } + + /** + * 璁$畻涓�缁勬暟鎹殑鍧囧�� + */ + private fun calAvg(type: FactorType, list: List<BaseRealTimeData>) { + var total = .0 + var valid = true + val count = list.size + if (count == 0) return + list.forEach { + val v = it.getByFactorType(type) + if (v == null) { + valid = false + } else { + total += v + } + } + val avg = total / count + tagMap[type]?.avgListReverse?.add(0, Pair(avg, valid)) + } + + /** + * 璁$畻鏁版嵁缁勪箣闂寸殑鍧囧�煎樊寮傛槸鍚﹁繛缁秴杩囬檺瀹氭瘮鐜� + */ + private fun checkSlideAvg(type: FactorType): Boolean { + val tag = tagMap[type] ?: return false + // 璁$畻婊戝姩鍧囧�兼渶浣庤姹備釜鏁� + val minSize = config.changeTrendTimes + config.changeTrendInterval + if (tag.avgListReverse.size < minSize) { + return false + } else { + // 婊戝姩鍧囧�兼弧瓒虫暟閲忔椂锛岃绠楀潎鍊间箣闂存槸鍚﹁繛缁秴杩囬檺瀹氭瘮鐜� + val rateList = mutableListOf<Pair<Double, Boolean>>() + for (i in tag.avgListReverse.indices) { + if (i >= config.changeTrendTimes) break + val r = calAvgChangeRate(tag.avgListReverse[i], tag.avgListReverse[i + config.changeTrendInterval]) + rateList.add(r) + } + for (y in rateList) { + if (!y.second || y.first < config.changeTrendRate) { + return false + } + } + return true + } + } + + /** + * 璁$畻婊戝姩鍧囧�煎彉鍖栫巼 + * 姹俛1鐩稿浜巃2鐨勫彉鍖栫巼 + */ + private fun calAvgChangeRate(a1: Pair<Double, Boolean>, a2: Pair<Double, Boolean>): Pair<Double, Boolean> { + val valid = a1.second && a2.second + return if (a2.first == .0) { + Pair(1.0, valid) + } else { + Pair(abs(a1.first - a2.first) / a2.first, valid) + } + } +} \ No newline at end of file -- Gitblit v1.9.3