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.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
|
*/
|
@Deprecated("2025.5.29, 逻辑与业务不匹配,后续删除")
|
class RealTimeExceptionSlideAverage : BaseExceptionAnalysis<RealTimeAnalysisConfig, RealTimeExceptionResult> {
|
|
constructor(config: RealTimeAnalysisConfig) : super(config)
|
|
constructor(config: RealTimeAnalysisConfig, callback: NewExceptionCallback) : super(config){
|
this.callback = callback
|
}
|
|
var callback: NewExceptionCallback? = 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(tag.startData!!, tag.endData, factor, tag.exceptionData)
|
.apply { status = exceptionStatus.value }
|
// 异常已创建时,更新异常信息
|
if (tag.exceptionCreated) {
|
// 将最新的异常的guid赋值给ex
|
val lastEx = tag.exceptionResult.last()
|
ex.guid = lastEx.guid
|
tag.exceptionResult.removeLast()
|
tag.exceptionResult.add(ex)
|
}
|
// 异常未创建时,新建异常信息
|
else {
|
tag.exceptionResult.add(ex)
|
tag.exceptionCreated = true
|
}
|
|
callback?.let { func ->
|
val exc = tag.exceptionResult.last()
|
func.invoke(exc as RealTimeExceptionResult)
|
}
|
}
|
|
|
override fun newResult(
|
start: BaseRealTimeData,
|
end: BaseRealTimeData?,
|
factor: FactorFilter.SelectedFactor,
|
exceptionData: List<BaseRealTimeData>,
|
): RealTimeExceptionResult {
|
val eType = getExceptionType()
|
return RealTimeExceptionResult(start, end, factor, exceptionData, eType)
|
}
|
|
/**
|
* 计算一组数据的均值
|
*/
|
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
|
}
|
}
|
|
/**
|
* 计算滑动均值变化率
|
* 求a1相对于a2的变化率
|
*/
|
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)
|
}
|
}
|
}
|