package com.flightfeather.uav.biz.sourcetrace.exceptiontype
|
|
import com.flightfeather.uav.biz.FactorFilter
|
import com.flightfeather.uav.biz.dataanalysis.BaseExceptionContinuous
|
import com.flightfeather.uav.biz.dataanalysis.model.ExceptionTag
|
import com.flightfeather.uav.biz.dataanalysis.model.ExceptionType
|
import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig
|
import com.flightfeather.uav.biz.sourcetrace.model.PollutedClue
|
import com.flightfeather.uav.common.utils.MapUtil
|
import com.flightfeather.uav.domain.entity.BaseRealTimeData
|
import com.flightfeather.uav.lightshare.eunm.ExceptionStatusType
|
import com.flightfeather.uav.socket.eunm.FactorType
|
import java.time.Duration
|
import java.time.LocalDateTime
|
import java.time.ZoneId
|
|
|
// 异常数据生成回调类
|
typealias NewPolluteClueCallback = (ex: PollutedClue) -> Unit
|
/**
|
* 不同风速下,数据突变异常基类
|
* @date 2025/5/29
|
* @author feiyu02
|
*/
|
abstract class BaseRTExcWindLevel(config: RTExcWindLevelConfig) :
|
BaseExceptionContinuous<ExceptionTag, RTExcWindLevelConfig, PollutedClue>(config, ExceptionTag::class.java) {
|
|
constructor(config: RTExcWindLevelConfig, callback: NewPolluteClueCallback) : this(config){
|
this.callback = callback
|
}
|
|
override var excludedFactor: List<FactorType> = listOf(FactorType.NO2)
|
|
private var callback: NewPolluteClueCallback? = null
|
|
abstract var windLevelCondition: RTExcWindLevelConfig.WindLevelCondition
|
|
override var judgeMethod: JudgeMethod = JudgeMethod.M1
|
|
override fun getExceptionType(): ExceptionType {
|
return ExceptionType.TYPE4
|
}
|
|
override fun judgeDataScale(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean> {
|
val res = mutableMapOf<FactorType, Boolean>()
|
config.factorFilter.mainList().forEach { f ->
|
if (p?.getByFactorType(f) == null || n.getByFactorType(f) == null || n.windSpeed == null) {
|
res[f] = (false)
|
return@forEach
|
}
|
val nValue = n.getByFactorType(f)!!
|
val minValue = FactorType.getVMin(f)
|
res[f] = nValue >= minValue
|
}
|
return res
|
}
|
|
override fun judgeException(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean> {
|
val res = mutableMapOf<FactorType, Boolean>()
|
config.factorFilter.mainList().forEach { f ->
|
if (p?.getByFactorType(f) == null || n.getByFactorType(f) == null || n.windSpeed == null) {
|
res[f] = (false)
|
return@forEach
|
}
|
|
val con = windLevelCondition
|
|
if (n.windSpeed!! in con.windSpeed.first..con.windSpeed.second) {
|
println("风速:${n.windSpeed},[${con.windSpeed.first} - ${con.windSpeed.second}]")
|
val pValue = p.getByFactorType(f)!!
|
val nValue = n.getByFactorType(f)!!
|
// 计算后一个数据相比于前一个数据的变化率
|
val r = (nValue - pValue) / pValue
|
val b1 = r >= con.mutationRate.first && r < con.mutationRate.second
|
println("因子:${f.des},幅度:${r},限定:${con.mutationRate.first},${b1}")
|
res[f] = b1
|
} else {
|
res[f] = false
|
}
|
}
|
|
|
return res
|
}
|
|
override fun judgeExceptionCount(tag: ExceptionTag, factorType: FactorType?): Boolean {
|
return tag.exceptionData.size >= windLevelCondition.countLimit
|
}
|
|
override fun needCut(tag: ExceptionTag, hasException: Boolean?, data: BaseRealTimeData): Boolean {
|
// 按照时长和距离限制将异常截取
|
if (tag.exceptionData.isEmpty()) return false
|
|
val se = tag.exceptionData.first()
|
val ee = data
|
|
val sTime = LocalDateTime.ofInstant(se.dataTime?.toInstant(), ZoneId.systemDefault())
|
val eTime = LocalDateTime.ofInstant(ee.dataTime?.toInstant(), ZoneId.systemDefault())
|
val duration = Duration.between(sTime, eTime).toMinutes()
|
// 数据采样的时长超过限制时,需要截取
|
val b1 = duration > config.timeLimit
|
|
// 走航数据的距离超过限制时,需要截取
|
val b2 = if (se.longitude == null || se.latitude == null || ee.longitude == null || ee.latitude == null) {
|
false
|
} else {
|
val distance = MapUtil.getDistance(
|
se.longitude!!.toDouble(), se.latitude!!.toDouble(), ee.longitude!!
|
.toDouble(), ee.latitude!!.toDouble()
|
)
|
distance > config.distanceLimit
|
}
|
|
return b1 || b2
|
}
|
|
override fun immeExcCheck(tag: ExceptionTag, factorType: FactorType): Boolean {
|
// 异常出现等于限定次数时,就需要形成污染线索
|
return tag.exceptionData.size == windLevelCondition.countLimit
|
}
|
|
override fun newResult(tag: ExceptionTag, factor: FactorFilter.SelectedFactor): PollutedClue {
|
return PollutedClue()
|
}
|
|
override fun newResult(exceptions: List<Pair<FactorFilter.SelectedFactor, ExceptionTag>>): PollutedClue {
|
return if (exceptions.isEmpty())
|
PollutedClue()
|
else
|
PollutedClue(exceptions, getExceptionType(), config, windLevelCondition)
|
}
|
|
// override fun newResult(
|
// start: BaseRealTimeData,
|
// end: BaseRealTimeData?,
|
// factor: FactorFilter.SelectedFactor,
|
// exceptionData: List<BaseRealTimeData>,
|
// ): PollutedClue {
|
// return PollutedClue(start, end, factor, exceptionData, getExceptionType(), config, windLevelCondition)
|
// }
|
|
|
// override fun mergeExceptionResult() {
|
// super.mergeExceptionResult()
|
// callback?.let { func ->
|
// result.forEach {
|
// func.invoke(it)
|
// }
|
// }
|
// }
|
|
override fun onNewResult(result: List<PollutedClue>) {
|
callback?.let { func ->
|
result.forEach {
|
func.invoke(it)
|
}
|
}
|
}
|
}
|