| | |
| | | package com.flightfeather.uav.biz.dataanalysis |
| | | |
| | | import com.flightfeather.uav.biz.FactorFilter |
| | | import com.flightfeather.uav.socket.eunm.FactorType |
| | | |
| | | /** |
| | | * 数据分析配置参数基类 |
| | | * @date 2025/5/13 |
| | | * @author feiyu02 |
| | | */ |
| | | abstract class BaseAnalysisConfig( |
| | | abstract class BaseAnalysisConfig{ |
| | | constructor(factorFilter: FactorFilter, combination: List<List<FactorType>>?){ |
| | | this.factorFilter = factorFilter |
| | | this.combination = combination |
| | | } |
| | | // 因子筛选 |
| | | val factorFilter: FactorFilter, |
| | | ) { |
| | | constructor(factorFilter: FactorFilter):this(factorFilter, null) |
| | | |
| | | val factorFilter:FactorFilter |
| | | val combination: List<List<FactorType>>? |
| | | } |
| | |
| | | // 末尾数据对象 |
| | | protected var lastData: BaseRealTimeData? = null |
| | | |
| | | /** |
| | | * 后置判断:当相邻数据时间不连续时,或者满足自定义条件时,对之前已有的异常进行记录 |
| | | */ |
| | | open fun afterExcCheck(isContinue: Boolean, tag: T, hasException: Boolean?): Boolean { |
| | | return !isContinue || needCut(tag, hasException) |
| | | } |
| | | // 最新的一组异常,根据设定参数,将相关联的因子产生的异常合并 |
| | | protected val latestExceptionResult = mutableListOf<BaseExceptionResult>() |
| | | |
| | | // 最新的一组合并异常 |
| | | protected val latestCombinedResult = mutableListOf<List<BaseExceptionResult>>() |
| | | |
| | | /** |
| | | * 立即判断:当出现异常时,缓存异常数据的同时,立即对已有异常进行判断是否满足异常结果要求 |
| | |
| | | * 异常数据的截取判断 |
| | | * @return |
| | | */ |
| | | open fun needCut(tag: T, hasException: Boolean?): Boolean { |
| | | open fun needCut(tag: T, hasException: Boolean?, data: BaseRealTimeData): Boolean { |
| | | // 默认判断条件为 当异常不再重复出现时,形成异常结果 |
| | | return tag.exceptionExisted && hasException == false |
| | | } |
| | |
| | | // } |
| | | // 2. 立即判断:当出现异常时,缓存异常数据的同时,立即对已有异常进行判断是否满足异常结果要求 |
| | | if (hasException[f] == true) { |
| | | |
| | | // afterExcCheck(isContinue, it, hasException[f]) |
| | | needCut(it, hasException[f]) |
| | | if (needCut(it, hasException[f], data)) { |
| | | it.refreshWithNextException(data) |
| | | } |
| | | // 有异常出现时,记录异常数据 |
| | | it.addExceptionData(data) |
| | | // 当立即判断通过时,形成异常结果 |
| | |
| | | } |
| | | } |
| | | lastData = data |
| | | |
| | | mergeExceptionResult() |
| | | } |
| | | |
| | | override fun onDone() { |
| | |
| | | // 异常未创建时,新建异常信息 |
| | | else { |
| | | tag.exceptionResult.add(ex) |
| | | // resultList.add(ex) |
| | | tag.exceptionCreated = true |
| | | } |
| | | |
| | | latestExceptionResult.add(ex) |
| | | } |
| | | |
| | | /** |
| | | * 合并异常 |
| | | */ |
| | | open fun mergeExceptionResult() { |
| | | // 遍历所有的因子组合 |
| | | config.combination?.forEach {c -> |
| | | val res = mutableListOf<BaseExceptionResult>() |
| | | var exist = true |
| | | // 查看组合内的所有因子是否都同时出现异常 |
| | | c.forEach { f-> |
| | | val r = latestExceptionResult.find { e-> |
| | | e.factorId == f.value |
| | | } |
| | | if (r != null) { |
| | | res.add(r) |
| | | } else { |
| | | exist = false |
| | | } |
| | | } |
| | | // 如果组合内的所有因子都存在异常,则存储为合并异常 |
| | | if (exist) { |
| | | // 将合并异常从单个异常集合中去除 |
| | | res.forEach { r-> |
| | | latestExceptionResult.removeIf { e-> e.factorId == r.factorId } |
| | | } |
| | | // 将合并异常存储 |
| | | latestCombinedResult.add(res) |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | // 异常的状态 |
| | | var status: Int = ExceptionStatusType.InProgress.value |
| | | |
| | | var factorId: Int? = null |
| | | var factorName: String? = null |
| | | |
| | | init { |
| | | guid = UUID.randomUUID().toString() |
| | | } |
| | |
| | | this.sceneInfoRep = sceneInfoRep |
| | | this.sourceTraceRep = sourceTraceRep |
| | | this.config = if (factorFilter != null) { |
| | | RTExcWindLevelConfig(factorFilter) |
| | | RTExcWindLevelConfig(factorFilter, emptyList()) |
| | | } else { |
| | | RTExcWindLevelConfig( |
| | | FactorFilter.builder() |
| | | // .withMain(FactorType.NO2) |
| | | // .withMain(FactorType.CO) |
| | | .withMain(FactorType.NO2) |
| | | .withMain(FactorType.CO) |
| | | // .withMain(FactorType.H2S) |
| | | // .withMain(FactorType.SO2) |
| | | // .withMain(FactorType.O3) |
| | | .withMain(FactorType.O3) |
| | | .withMain(FactorType.PM25) |
| | | .withMain(FactorType.PM10) |
| | | .withMain(FactorType.VOC) |
| | | .create() |
| | | .create(), |
| | | listOf( |
| | | listOf(FactorType.PM25, FactorType.PM10), |
| | | listOf(FactorType.VOC, FactorType.CO), |
| | | ) |
| | | ) |
| | | } |
| | | pollutedSummary = PollutedSummary(config) { summaryCallback(it) } |
| | |
| | | * @date 2025/5/29 |
| | | * @author feiyu02 |
| | | */ |
| | | class RTExcWindLevelConfig(factorFilter: FactorFilter): BaseAnalysisConfig(factorFilter) { |
| | | class RTExcWindLevelConfig(factorFilter: FactorFilter, combination: List<List<FactorType>>?): BaseAnalysisConfig |
| | | (factorFilter, combination) { |
| | | |
| | | inner class WindLevelCondition( |
| | | val windSpeed: Pair<Double, Double>, |
| | |
| | | return tag.exceptionData.size >= (changeRate[factorType]?.countLimit ?: 1) |
| | | } |
| | | |
| | | override fun needCut(tag: ExceptionTag, hasException: Boolean?): Boolean { |
| | | override fun needCut(tag: ExceptionTag, hasException: Boolean?, data: BaseRealTimeData): Boolean { |
| | | // 按照时长和距离限制将异常截取 |
| | | if (tag.exceptionData.isEmpty()) return false |
| | | |
| | | val se = tag.exceptionData.first() |
| | | val ee = tag.exceptionData.last() |
| | | val ee = data |
| | | |
| | | val sTime = LocalDateTime.ofInstant(se.dataTime?.toInstant(), ZoneId.systemDefault()) |
| | | val eTime = LocalDateTime.ofInstant(ee.dataTime?.toInstant(), ZoneId.systemDefault()) |
| | |
| | | exceptionStatus: ExceptionStatusType, |
| | | ) { |
| | | super.onNewException(tag, factor, exceptionStatus) |
| | | // callback?.let { func -> |
| | | // val exc = tag.exceptionResult.last() |
| | | // func.invoke(exc as PollutedClue) |
| | | // } |
| | | } |
| | | |
| | | override fun mergeExceptionResult() { |
| | | super.mergeExceptionResult() |
| | | latestExceptionResult |
| | | latestCombinedResult |
| | | callback?.let { func -> |
| | | val exc = tag.exceptionResult.last() |
| | | func.invoke(exc as PollutedClue) |
| | | latestExceptionResult.forEach { |
| | | func.invoke(it as PollutedClue) |
| | | } |
| | | latestCombinedResult.forEach { |
| | | func.invoke(it as PollutedClue) |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | return tag.exceptionData.size >= windLevelCondition.countLimit |
| | | } |
| | | |
| | | override fun needCut(tag: ExceptionTag, hasException: Boolean?): Boolean { |
| | | override fun needCut(tag: ExceptionTag, hasException: Boolean?, data: BaseRealTimeData): Boolean { |
| | | // 按照时长和距离限制将异常截取 |
| | | if (tag.exceptionData.isEmpty()) return false |
| | | |
| | | val se = tag.exceptionData.first() |
| | | val ee = tag.exceptionData.last() |
| | | val ee = data |
| | | |
| | | val sTime = LocalDateTime.ofInstant(se.dataTime?.toInstant(), ZoneId.systemDefault()) |
| | | val eTime = LocalDateTime.ofInstant(ee.dataTime?.toInstant(), ZoneId.systemDefault()) |