feiyu02
2025-07-10 c5f380b69707a9a09fe988a2f4bd98e142bf64ae
2025.7.10
1. 修改动态溯源异常判断逻辑
已修改9个文件
已添加4个文件
已重命名1个文件
288 ■■■■ 文件已修改
src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/model/ExceptionType.kt 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceController.kt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/config/RTExcWindLevelConfig.kt 80 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/BaseRTExcChangeRate.kt 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcChangeRate1.kt 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcChangeRate4.kt 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcChangeRate6.kt 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTWarnChangeRate.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTWarnChangeRate2.kt 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedData.kt 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/utils/DateUtil.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt
@@ -121,12 +121,14 @@
                // å¯¹äºŽå¼‚常的生成分别执行后置判断、和立即判断
                // 1. åŽç½®åˆ¤æ–­ï¼šå½“相邻数据时间不连续时,或者满足自定义条件时,对之前已有的异常进行记录,形成异常结果
                if (afterExcCheck(isContinue, it, hasException[f])) {
                    // æ•°æ®ä¸è¿žç»­æ—¶æˆ–者满足主动截断条件时,记录异常情况
                    recordException(s, it, data)
                }
//                if (afterExcCheck(isContinue, it, hasException[f])) {
//                    // æ•°æ®ä¸è¿žç»­æ—¶æˆ–者满足主动截断条件时,记录异常情况
//                    recordException(s, it, data)
//                }
                // 2. ç«‹å³åˆ¤æ–­ï¼šå½“出现异常时,缓存异常数据的同时,立即对已有异常进行判断是否满足异常结果要求
                else if (hasException[f] == true) {
                if (hasException[f] == true) {
//                    afterExcCheck(isContinue, it, hasException[f])
                    needCut(it, hasException[f])
                    // æœ‰å¼‚常出现时,记录异常数据
                    it.addExceptionData(data)
                    // å½“立即判断通过时,形成异常结果
@@ -136,9 +138,9 @@
                }
                // 3. æ•°æ®æ­£å¸¸ï¼Œæ— ä»»ä½•异常时d
                // TODO("2025.6.3:其他子类的此处刷新逻辑待完成“)
                else {
                    it.refreshWithNextException(data)
                }
//                else {
//                    it.refreshWithNextException(data)
//                }
            }
        }
        lastData = data
src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/model/ExceptionType.kt
@@ -11,5 +11,6 @@
    TYPE7(7, "滑动平均值突变"),
    TYPE8(8, "有效率异常"),
    TYPE9(9, "快速上升"),
    TYPE10(10, "快速下降")
    TYPE10(10, "快速下降"),
    TYPE11(11, "上升趋势")
}
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceController.kt
@@ -2,13 +2,11 @@
import com.flightfeather.uav.biz.FactorFilter
import com.flightfeather.uav.biz.dataanalysis.BaseExceptionAnalysis
import com.flightfeather.uav.biz.sourcetrace.RealTimeAnalysisConfig
import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig
import com.flightfeather.uav.biz.sourcetrace.exceptiontype.*
import com.flightfeather.uav.biz.sourcetrace.model.AnalysisResult
import com.flightfeather.uav.biz.sourcetrace.model.PollutedClue
import com.flightfeather.uav.biz.sourcetrace.model.PollutedSummary
import com.flightfeather.uav.common.utils.GsonUtils
import com.flightfeather.uav.domain.entity.BaseRealTimeData
import com.flightfeather.uav.domain.repository.SceneInfoRep
import com.flightfeather.uav.domain.repository.SourceTraceRep
@@ -74,8 +72,13 @@
            add(RTExcWindLevel1_1(config) { exceptionCallback(it) }.also { it.init() })
            add(RTExcWindLevel4(config) { exceptionCallback(it) }.also { it.init() })
            add(RTExcWindLevel6(config) { exceptionCallback(it) }.also { it.init() })
            add(RTExcChangeRate(config) { exceptionCallback(it) }.also { it.init() })
            add(RTExcChangeRate1(config) { exceptionCallback(it) }.also { it.init() })
            add(RTExcChangeRate4(config) { exceptionCallback(it) }.also { it.init() })
            add(RTExcChangeRate6(config) { exceptionCallback(it) }.also { it.init() })
            add(RTWarnChangeRate(config) { dataChangeCallback(it) }.also { it.init() })
            add(RTWarnChangeRate2(config) { dataChangeCallback(it) }.also { it.init() })
        }
    }
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/config/RTExcWindLevelConfig.kt
@@ -65,37 +65,71 @@
    )
    /****数据快速上升*****************************************************************************/
    var changeRateCondition = WindLevelCondition(
        .0 to Double.MAX_VALUE,
        0.1 to Double.MAX_VALUE,
        DistanceType.TYPE1,
        3
    )
    // ç›‘测因子在一个监测周期(4秒)内正常变化的量级范围
    var changeRateUp = mutableMapOf(
    var changeRateUp1 = mutableMapOf(
        FactorType.PM25 to WindLevelCondition(
            .0 to Double.MAX_VALUE,
            .0 to 1.5,
            4.0 to Double.MAX_VALUE,
            DistanceType.TYPE1,
            3
        ),
        FactorType.PM10 to WindLevelCondition(
            .0 to Double.MAX_VALUE,
            .0 to 1.5,
            4.0 to Double.MAX_VALUE,
            DistanceType.TYPE1,
            3
        ),
        FactorType.VOC to WindLevelCondition(
            .0 to Double.MAX_VALUE,
            .0 to 1.5,
            6.0 to Double.MAX_VALUE,
            DistanceType.TYPE1,
            1
        ),
    )
    var changeRateUp2 = mutableMapOf(
        FactorType.PM25 to WindLevelCondition(
            1.6 to 7.9,
            4.0 to Double.MAX_VALUE,
            DistanceType.TYPE3,
            3
        ),
        FactorType.PM10 to WindLevelCondition(
            1.6 to 7.9,
            4.0 to Double.MAX_VALUE,
            DistanceType.TYPE3,
            3
        ),
        FactorType.VOC to WindLevelCondition(
            1.6 to 7.9,
            6.0 to Double.MAX_VALUE,
            DistanceType.TYPE3,
            1
        ),
    )
    var changeRateUp3 = mutableMapOf(
        FactorType.PM25 to WindLevelCondition(
            8.0 to 13.8,
            4.0 to Double.MAX_VALUE,
            DistanceType.TYPE4,
            3
        ),
        FactorType.PM10 to WindLevelCondition(
            8.0 to 13.8,
            4.0 to Double.MAX_VALUE,
            DistanceType.TYPE4,
            3
        ),
        FactorType.VOC to WindLevelCondition(
            8.0 to 13.8,
            6.0 to Double.MAX_VALUE,
            DistanceType.TYPE4,
            1
        ),
    )
    /****数据快速下降*****************************************************************************/
    /****数据快速下降提醒*****************************************************************************/
    // ç›‘测因子在一个监测周期(4秒)内正常变化的量级范围
    var changeRateDown = mutableMapOf(
    var changeRateWarnDown = mutableMapOf(
        FactorType.PM25 to WindLevelCondition(
            .0 to Double.MAX_VALUE,
            -Double.MAX_VALUE to -2.0,
@@ -115,4 +149,26 @@
            3
        ),
    )
    /****数据有上升趋势提醒*****************************************************************************/
    var changeRateWarnUp = mutableMapOf(
        FactorType.PM25 to WindLevelCondition(
            .0 to Double.MAX_VALUE,
            2.0 to 4.0,
            DistanceType.TYPE1,
            3
        ),
        FactorType.PM10 to WindLevelCondition(
            .0 to Double.MAX_VALUE,
            2.0 to 4.0,
            DistanceType.TYPE1,
            3
        ),
        FactorType.VOC to WindLevelCondition(
            .0 to Double.MAX_VALUE,
            3.0 to 6.0,
            DistanceType.TYPE1,
            1
        ),
    )
}
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/BaseRTExcChangeRate.kt
ÎļþÃû´Ó src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcChangeRate.kt ÐÞ¸Ä
@@ -19,7 +19,7 @@
 * @date 2025/6/10
 * @author feiyu02
 */
open class RTExcChangeRate(config: RTExcWindLevelConfig) :
abstract class BaseRTExcChangeRate(config: RTExcWindLevelConfig) :
    BaseExceptionContinuous<ExceptionTag, RTExcWindLevelConfig, PollutedClue>(config, ExceptionTag::class.java) {
    constructor(config: RTExcWindLevelConfig, callback: NewPolluteClueCallback) : this(config){
@@ -28,7 +28,7 @@
    private var callback: NewPolluteClueCallback? = null
    open var changeRate = this.config.changeRateUp
    abstract var changeRate: MutableMap<FactorType, RTExcWindLevelConfig.WindLevelCondition>
    override fun getExceptionType(): ExceptionType {
        return ExceptionType.TYPE9
@@ -58,20 +58,17 @@
            val rate = changeRate[f]
            val pValue = p.getByFactorType(f)!!
            val nValue = n.getByFactorType(f)!!
            // è®¡ç®—后一个数据相比于前一个数据的变化速率
            val v = (nValue - pValue)
            val b1 = if (rate != null) {
                v in rate.mutationRate.first..rate.mutationRate.second
            if (rate != null && n.windSpeed!! in rate.windSpeed.first..rate.windSpeed.second) {
                val pValue = p.getByFactorType(f)!!
                val nValue = n.getByFactorType(f)!!
                // è®¡ç®—后一个数据相比于前一个数据的变化速率
                val v = (nValue - pValue)
                val b1 = v in rate.mutationRate.first..rate.mutationRate.second
                println("因子:${f.des},速率:${v},${b1}")
                res[f] = b1
            } else {
                false
                res[f] = false
            }
//                val r = (nValue - pValue) / pValue
//                val b1 = r >= con.mutationRate.first && r < con.mutationRate.second
            println("因子:${f.des},速率:${v},${b1}")
            res[f] = b1
        }
        return res
    }
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcChangeRate1.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package com.flightfeather.uav.biz.sourcetrace.exceptiontype
import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig
import com.flightfeather.uav.socket.eunm.FactorType
/**
 * æ•°æ®å˜åŒ–速率异常
 * @date 2025/6/10
 * @author feiyu02
 */
open class RTExcChangeRate1 : BaseRTExcChangeRate {
    constructor(config: RTExcWindLevelConfig):super(config)
    constructor(config: RTExcWindLevelConfig, callback: NewPolluteClueCallback) : super(config, callback)
    override var changeRate: MutableMap<FactorType, RTExcWindLevelConfig.WindLevelCondition> = this.config.changeRateUp1
}
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcChangeRate4.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package com.flightfeather.uav.biz.sourcetrace.exceptiontype
import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig
import com.flightfeather.uav.socket.eunm.FactorType
/**
 * æ•°æ®å˜åŒ–速率异常
 * @date 2025/6/10
 * @author feiyu02
 */
open class RTExcChangeRate4 : BaseRTExcChangeRate {
    constructor(config: RTExcWindLevelConfig):super(config)
    constructor(config: RTExcWindLevelConfig, callback: NewPolluteClueCallback) : super(config, callback)
    override var changeRate: MutableMap<FactorType, RTExcWindLevelConfig.WindLevelCondition> = this.config.changeRateUp2
}
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcChangeRate6.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package com.flightfeather.uav.biz.sourcetrace.exceptiontype
import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig
import com.flightfeather.uav.socket.eunm.FactorType
/**
 * æ•°æ®å˜åŒ–速率异常
 * @date 2025/6/10
 * @author feiyu02
 */
open class RTExcChangeRate6 : BaseRTExcChangeRate {
    constructor(config: RTExcWindLevelConfig):super(config)
    constructor(config: RTExcWindLevelConfig, callback: NewPolluteClueCallback) : super(config, callback)
    override var changeRate: MutableMap<FactorType, RTExcWindLevelConfig.WindLevelCondition> = this.config.changeRateUp3
}
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTWarnChangeRate.kt
@@ -8,7 +8,7 @@
 * @date 2025/7/3
 * @author feiyu02
 */
class RTWarnChangeRate : RTExcChangeRate {
class RTWarnChangeRate : BaseRTExcChangeRate {
    constructor(config: RTExcWindLevelConfig):super(config)
    constructor(config: RTExcWindLevelConfig, callback: NewPolluteClueCallback) : super(config, callback)
@@ -16,5 +16,5 @@
        return ExceptionType.TYPE10
    }
    override var changeRate = config.changeRateDown
    override var changeRate = config.changeRateWarnDown
}
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTWarnChangeRate2.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.flightfeather.uav.biz.sourcetrace.exceptiontype
import com.flightfeather.uav.biz.dataanalysis.model.ExceptionType
import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig
/**
 * æ•°æ®æœ‰ä¸Šå‡è¶‹åŠ¿æé†’
 * @date 2025/7/3
 * @author feiyu02
 */
class RTWarnChangeRate2 : RTExcChangeRate1 {
    constructor(config: RTExcWindLevelConfig):super(config)
    constructor(config: RTExcWindLevelConfig, callback: NewPolluteClueCallback) : super(config, callback)
    override fun getExceptionType(): ExceptionType {
        return ExceptionType.TYPE11
    }
    override var changeRate = config.changeRateWarnUp
}
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedData.kt
@@ -6,7 +6,9 @@
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.domain.entity.BaseRealTimeData
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.socket.eunm.FactorType
import java.util.Date
import kotlin.math.round
/**
 * æ±¡æŸ“数据
@@ -61,6 +63,11 @@
        calPer()
        calRate()
        val s = dataSummary(exceptionData, factor.main)
        avg = s.first
        min = s.second
        max = s.third
    }
    var deviceCode: String? = null
@@ -89,6 +96,10 @@
    var avgPer: Double? = null
    // å› å­é‡çº§å¹³å‡å˜åŒ–速率
    var avgRate: Double? = null
    var avg: Double? = null
    var min: Double? = null
    var max: Double? = null
    // å‘生次数
    var times: Int? = null
@@ -127,4 +138,25 @@
        }
        avgRate = total / (list.size - 1)
    }
    private fun dataSummary(exceptionData: List<BaseRealTimeData?>, factorType: FactorType): Triple<Double, Double,
            Double> {
        var min = -1.0
        var max = -1.0
        var total = .0
        var count = 0
        exceptionData.forEach {
            val value = it?.getByFactorType(factorType)?.toDouble() ?: return@forEach
            if (min == -1.0 || min > value) {
                min = round(value * 1000) / 1000
            }
            if (max == -1.0 || max < value) {
                max = round(value * 1000) / 1000
            }
            total += value
            count++
        }
        val avg = if (count == 0) .0 else round(total / count * 1000) / 1000
        return Triple(avg, min, max)
    }
}
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt
@@ -1,5 +1,6 @@
package com.flightfeather.uav.biz.sourcetrace.model
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.common.utils.MapUtil
import com.flightfeather.uav.domain.entity.SceneInfo
import com.flightfeather.uav.domain.repository.SceneInfoRep
@@ -25,7 +26,7 @@
     */
    // æº¯æºä¼ä¸š
    var sceneList: List<SceneInfoVo?>? = null
    var sceneList: List<SceneInfoVo>? = null
    // æº¯æºæŽ¨ç†ç»“论
    var conclusion: String? = null
@@ -69,7 +70,7 @@
        // æ ¹æ®æ±¡æŸ“因子的量级,计算主要的污染场景类型,筛选结果
        val mainSceneType = calSceneType(pollutedData)
        if (mainSceneType != null) {
            this.conclusion = mainSceneType.first
//            this.conclusion = mainSceneType.first
            result = result.filter {
                val r = mainSceneType.second.find { s->
                    s.value == it.typeId.toInt()
@@ -80,6 +81,8 @@
        this.sceneList = findClosestStation(sceneInfoRep, result)
        val txt = summaryTxt(pollutedData, this.sceneList!!)
        this.conclusion = txt
    }
    /**
@@ -114,7 +117,7 @@
                    it.pm25!! / it.pm10!!
                }.average()
                val str =
                    "PM2.5量级为${pm25Avg}μg/m³,PM10量级为${pm25Avg}μg/m³,PM2.5占PM10的比重为${round(percentageAvg * 100)}%"
                    "PM2.5量级为${pm25Avg}μg/m³,PM10量级为${pm10Avg}μg/m³,PM2.5占PM10的比重为${round(percentageAvg * 100)}%"
                return if (percentageAvg > 0.666) {
                    "${str},比重较大,污染源以餐饮为主,工地次之" to
                            listOf(SceneType.TYPE1, SceneType.TYPE2, SceneType.TYPE3, SceneType.TYPE14, SceneType.TYPE5)
@@ -176,4 +179,35 @@
            return@map vo
        }
    }
    private fun summaryTxt(pollutedData: PollutedData, sceneList: List<SceneInfoVo>): String {
//        pollutedData.exception
//        pollutedData.selectedFactor?.main
        val st = DateUtil.instance.getTime(pollutedData.startTime)
        val et = DateUtil.instance.getTime(pollutedData.endTime)
        var txt =
            "${pollutedData.selectedFactor?.main?.des}在${st}至${et}之间,出现${pollutedData.exception},最低值为${
                pollutedData
                    .min
            },最高值为${pollutedData.max}"
        if (sceneList.isEmpty()) {
            txt += (",可能存在隐藏风险源。")
        } else {
            txt += (",发现${sceneList.size}个风险源,包含")
            val sizeMap = mutableMapOf<String, Int>()
            sceneList.forEach {
                if (!sizeMap.containsKey(it.type)) {
                    sizeMap[it.type] = 0
                }
                sizeMap[it.type] = sizeMap[it.type]!! + 1
            }
            sizeMap.forEach { (t, u) ->
                txt += ("${u}个${t},")
            }
            txt = txt.replaceRange(txt.length - 1, txt.length, "。")
        }
        return txt
    }
}
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt
@@ -158,8 +158,8 @@
            val closetScene = result.sortedSceneList?.first()
            // èµ°èˆªè·¯çº¿è°ƒæ•´å»ºè®®
            result.advice =
                "根据${sT}至${eT}的${clueList.size}条溯源切片,风险源【" +
                        "${closetScene?.first?.name}】被多次溯源,具有较高污染风险,现提供新的走航推荐路线,可经过该污染源。"
                "根据${sT}至${eT}的${clueList.size}个溯源切片,风险源【" +
                        "${closetScene?.first?.name}】被多次溯源,具有较高污染风险,现提供最新直达走航路线。"
            val lastP = realTimeDataList.last()
            // å»ºè®®å¯¹åº”的数据采样时间
src/main/kotlin/com/flightfeather/uav/common/utils/DateUtil.kt
@@ -650,7 +650,7 @@
     * @param date æ—¥æœŸ
     * @return æ—¶é—´
     */
    fun getTime(date: Date): String? {
    fun getTime(date: Date?): String? {
        return dateToString(date, DateStyle.HH_MM_SS)
    }