feiyu02
2023-11-07 7f580342dce92cb321e2566ef9a02827435a2de2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package com.flightfeather.monitor.analysis.dust.exception
 
import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
import com.flightfeather.monitor.enumration.dust.ExceptionType
import kotlin.math.abs
 
/**
 * 滑动平均值突变异常
 */
class ExceptionSlideAverage(config: DustExceptionSetting) : BaseDustExceptionAnalysis(config) {
 
    private val historyDataList = mutableListOf<DustSiteData>()
    private val tempDataList = mutableListOf<DustSiteData>()
    private val avgListReverse = mutableListOf<Double>()
    private var startData: DustSiteData? = null
    private var lastData: DustSiteData? = null
    private var sIndex = 0
    private var eIndex = -1
    private var existException = false
 
    override fun init() {
        super.init()
        historyDataList.clear()
        tempDataList.clear()
        avgListReverse.clear()
        startData = null
        lastData = null
        sIndex = 0
        eIndex = -1
        existException = false
    }
 
    override fun getExceptionType(): ExceptionType = ExceptionType.TYPE7
 
    override fun onNextData(data: DustSiteData) {
        eIndex++
        if (startData == null) {
            startData = data
        }
        historyDataList.add(data)
 
        // 数据加入临时数组
        tempDataList.add(data)
        // 数据量超出设置数量时,去除当前数据组首个数据
        if (tempDataList.size > config.changeTrendGroup) {
            tempDataList.removeAt(0)
        }
        // 数据量等于设置数量时,计算当前数据组均值
        if (tempDataList.size == config.changeTrendGroup) {
            calAvg(tempDataList)
            if (checkSlideAvg()) {
                existException = true
            } else {
                checkResult()
            }
        }
        lastData = data
    }
 
    override fun onDone() {
        checkResult()
    }
 
    /**
     * 计算一组数据的均值
     */
    private fun calAvg(list: List<DustSiteData>) {
        var total = .0
        val count = list.size
        if (count == 0) return
        list.forEach { total += it.dustValue }
        val avg = total / count
        avgListReverse.add(0, avg)
    }
 
    /**
     * 计算数据组之间的均值差异是否连续超过限定比率
     */
    private fun checkSlideAvg(): Boolean {
        // 计算滑动均值最低要求个数
        val minSize = config.changeTrendTimes + config.changeTrendInterval
        if (avgListReverse.size < minSize) {
            return false
        } else {
            // 滑动均值满足数量时,计算均值之间是否连续超过限定比率
            val rateList = mutableListOf<Double>()
            for (i in avgListReverse.indices) {
                if (i >= config.changeTrendTimes) break
                val r = calAvgChangeRate(avgListReverse[i], avgListReverse[i + config.changeTrendInterval])
                rateList.add(r)
            }
            for (y in rateList) {
                if (y < config.changeTrendRate) {
                    return false
                }
            }
            return true
        }
    }
 
    /**
     * 计算滑动均值变化率
     */
    private fun calAvgChangeRate(a1: Double, a2: Double): Double {
        return if (a2 == .0) {
            1.0
        } else {
            abs(a1 - a2) / a2
        }
    }
 
    /**
     * 当前数据未出现异常时,或数据循环结束时,判断后续步骤
     */
    private fun checkResult() {
        if (existException) {
            resultList.add(newResult(startData!!, lastData))
            existException = false
        }
        // 判断并更新起始点位置
        val len = config.changeTrendGroup - 1 + config.changeTrendTimes + config.changeTrendInterval
        if ((eIndex - sIndex + 1) > len) {
            sIndex = eIndex + 1 - len
            startData = historyDataList[sIndex]
        }
    }
}