package com.flightfeather.uav.biz.sourcetrace.model
|
|
import com.flightfeather.uav.biz.FactorFilter
|
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.common.utils.DateUtil
|
import com.flightfeather.uav.domain.entity.BaseRealTimeData
|
import com.flightfeather.uav.domain.entity.avg
|
import com.flightfeather.uav.lightshare.bean.DataVo
|
import com.flightfeather.uav.socket.eunm.FactorType
|
import java.util.Date
|
import kotlin.math.round
|
|
/**
|
* 污染数据
|
* @date 2025/5/27
|
* @author feiyu02
|
*/
|
class PollutedData() {
|
|
companion object {
|
// 默认数据采样时间间隔,单位:秒
|
const val DEFAULT_PERIOD = 4
|
}
|
|
/**
|
* 异常数据分组情况统计
|
*/
|
inner class ExcGroup{
|
constructor(dataIndexList: List<Int>, factorType: FactorType){
|
this.dataIndexList = dataIndexList
|
this.factorType = factorType
|
val first = getFirstDataValue()?.toDouble()
|
val last = getLastDataValue()?.toDouble()
|
if (first != null && last != null) {
|
per = round((last - first) / first * 100) / 100
|
rate = round((last - first) / DEFAULT_PERIOD * 100) / 100
|
}
|
}
|
var factorType: FactorType? = null
|
/**
|
* 异常数据对应历史数据[historyDataList]中的索引值
|
*/
|
var dataIndexList: List<Int>? = null
|
// 变化幅度
|
var per: Double? = null
|
// 变化速率
|
var rate: Double? = null
|
|
/**
|
* 获取异常数据的第一个数据
|
* !!!!第一个数据其实是首个异常数据的前一个数据值!!!!
|
*/
|
fun getFirstData(): BaseRealTimeData? {
|
return dataIndexList?.firstOrNull()?.let {
|
val i = if (it > 0) it - 1 else it
|
historyDataList[i].toBaseRealTimeData(BaseRealTimeData::class.java)
|
}
|
}
|
fun getFirstDataValue(): Float? {
|
return getFirstData()?.getByFactorType(factorType)
|
}
|
|
/**
|
* 获取异常数据的最后一个数据
|
*/
|
fun getLastData(): BaseRealTimeData? {
|
return dataIndexList?.lastOrNull()?.let {
|
historyDataList[it].toBaseRealTimeData(BaseRealTimeData::class.java)
|
}
|
}
|
fun getLastDataValue(): Float? {
|
return getLastData()?.getByFactorType(factorType)
|
}
|
}
|
|
|
/**
|
* 各监测因子异常统计信息
|
*/
|
inner class Statistic(){
|
var factorId: Int? = null
|
var factorName: String? = null
|
var subFactorId: List<Int>? = null
|
var subFactorName: List<String>? = null
|
var selectedFactor: FactorFilter.SelectedFactor? = null
|
|
/**
|
* 异常数据对应历史数据[historyDataList]中的索引值
|
*/
|
var dataIndexList: List<Int>? = null
|
|
// 因子量级平均变化幅度
|
var avgPer: Double? = null
|
// 因子量级平均变化速率
|
var avgRate: Double? = null
|
|
var avg: Double? = null
|
var min: Double? = null
|
var max: Double? = null
|
|
var excGroup: List<ExcGroup>? = null
|
|
/**
|
* 获取异常数据
|
*/
|
fun getExceptionData(): List<BaseRealTimeData>? {
|
return dataIndexList?.map { historyDataList[it].toBaseRealTimeData(BaseRealTimeData::class.java) }
|
}
|
|
/**
|
* 获取异常数据分段情况
|
* 将连续的异常数据分为一组
|
*/
|
fun getExceptionDataGroup(): List<List<Int>> {
|
val res = mutableListOf<MutableList<Int>>()
|
var curGroup = mutableListOf<Int>()
|
var lastIndex = -2
|
dataIndexList?.forEach {
|
if (curGroup.isEmpty()) {
|
curGroup.add(it)
|
} else if (it - lastIndex == 1) {
|
curGroup.add(it)
|
} else {
|
res.add(curGroup)
|
curGroup = mutableListOf(it)
|
}
|
lastIndex = it
|
}
|
if (curGroup.isNotEmpty()) {
|
res.add(curGroup)
|
}
|
return res
|
}
|
}
|
|
constructor(exceptions: List<Pair<FactorFilter.SelectedFactor, ExceptionTag>>, eType: ExceptionType,) : this() {
|
// 遍历所有的因子的异常,整合统一的异常结果,具体如下
|
var startData: BaseRealTimeData? = null
|
var endData: BaseRealTimeData? = null
|
var historyData = mutableListOf<BaseRealTimeData>()
|
var _times = 0
|
exceptions.forEach { e ->
|
// 将采样时间最早的数据作为开始数据
|
if (startData == null) {
|
startData = e.second.startData
|
} else {
|
if (e.second.startData?.dataTime!! < startData!!.dataTime) {
|
startData = e.second.startData
|
}
|
}
|
|
// 将采样时间最晚的作为结束数据
|
if (endData == null) {
|
endData = e.second.endData
|
} else {
|
if (e.second.endData?.dataTime!! > endData!!.dataTime) {
|
endData = e.second.endData
|
}
|
}
|
// 将所有历史数据去重合并
|
if (historyData.isEmpty()) {
|
historyData = e.second.historyData
|
} else {
|
e.second.historyData.forEach {
|
if (historyData.find { d -> d.dataTime == it.dataTime } == null) {
|
historyData.add(it)
|
}
|
}
|
}
|
|
_times += e.second.exceptionData.size
|
}
|
// 按照采样时间升序排列
|
historyData.sortBy { it.dataTime }
|
|
exception = eType.des
|
exceptionType = eType.value
|
startTime = startData?.dataTime
|
endTime = endData?.dataTime
|
windSpeed = historyData.avg().windSpeed?.toDouble()
|
times = _times
|
historyDataList.addAll(historyData.map { it.toDataVo() })
|
|
// 再次整合异常数据,分别计算各因子的异常结果统计
|
exceptions.forEach {e ->
|
statisticMap[e.first.main] = Statistic().apply {
|
factorId = e.first.main.value
|
factorName = e.first.main.des
|
subFactorId = e.first.subs.map { it.value }
|
subFactorName = e.first.subs.map { it.des }
|
selectedFactor = e.first
|
dataIndexList = e.second.exceptionData.map {
|
historyDataList.indexOfFirst { d ->
|
d.time == DateUtil.instance.dateToString(it.dataTime, DateUtil.DateStyle.YYYY_MM_DD_HH_MM_SS)
|
}
|
}
|
|
val s = dataSummary(e.second.exceptionData, e.first.main)
|
avg = s.first
|
min = s.second
|
max = s.third
|
|
excGroup = getExceptionDataGroup().map { ExcGroup(it, e.first.main) }
|
avgPer = excGroup?.mapNotNull { it.per }?.average()
|
avgRate = excGroup?.mapNotNull { it.rate }?.average()
|
}
|
}
|
}
|
|
var deviceCode: String? = null
|
var exception: String? = null
|
var exceptionType: Int? = null
|
var startTime: Date? = null
|
var endTime: Date? = null
|
// 风速
|
var windSpeed: Double? = null
|
// 发生次数
|
var times: Int? = null
|
var historyDataList = mutableListOf<DataVo>()
|
// 异常监测数据,包含单次异常中所有发生了异常的数据值(可能不是时间连续的数据)
|
// var dataList: MutableList<BaseRealTimeData> = mutableListOf()
|
// var dataVoList: MutableList<DataVo> = mutableListOf()
|
var statisticMap = mutableMapOf<FactorType, Statistic>()
|
|
/**
|
* 获取所有异常因子名称
|
*/
|
fun toFactorNames(): String {
|
val factors = statisticMap.entries.map { it.key }.sortedBy { it.value }.joinToString(";") { it.des }
|
return factors
|
}
|
|
fun getExceptionAvgData(): BaseRealTimeData {
|
val exceptionDataList = statisticMap.flatMap { it.value.getExceptionData() ?: emptyList() }
|
val avgData = exceptionDataList.avg()
|
return avgData
|
}
|
/**
|
* 获取异常数据中心坐标(异常数据中经度纬度的平均值)
|
*/
|
fun getExceptionCenter(): Pair<Double, Double>? {
|
val avgData = getExceptionAvgData()
|
val wgs84Lng = avgData.longitude?.toDouble()
|
val wgs84Lat = avgData.latitude?.toDouble()
|
return if (wgs84Lng == null || wgs84Lat == null) null else Pair(wgs84Lng, wgs84Lat)
|
}
|
|
private fun calPer(exceptionData: List<BaseRealTimeData?>, factorType: FactorType): Double? {
|
if (exceptionData.size < 2) return null
|
|
var total = .0
|
for (i in 0 until exceptionData.size - 1) {
|
val p = exceptionData[i]?.getByFactorType(factorType) ?: .0f
|
val n = exceptionData[i + 1]?.getByFactorType(factorType) ?: .0f
|
total += (n - p) / p
|
}
|
return total / (exceptionData.size - 1)
|
}
|
|
private fun calRate(exceptionData: List<BaseRealTimeData?>, factorType: FactorType): Double? {
|
if (exceptionData.size < 2) return null
|
|
var total = .0
|
for (i in 0 until exceptionData.size - 1) {
|
val p = exceptionData[i]?.getByFactorType(factorType) ?: .0f
|
val n = exceptionData[i + 1]?.getByFactorType(factorType) ?: .0f
|
total += (n - p) / 4
|
}
|
return total / (exceptionData.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)
|
}
|
}
|