From 538ba7a3bbc682f4537f1dd34f93feb2cf56b08e Mon Sep 17 00:00:00 2001 From: feiyu02 <risaku@163.com> Date: 星期二, 14 十月 2025 17:32:04 +0800 Subject: [PATCH] 2025.10.14 1. 新增数据统计颗粒度选项,可选秒级数据、分钟数据进行数据统计 2. 典型隐患区域统计新增按照污染溯源区域进行分类统计的功能 --- src/main/kotlin/com/flightfeather/uav/domain/entity/BaseRealTimeData.kt | 142 ++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 120 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/com/flightfeather/uav/domain/entity/BaseRealTimeData.kt b/src/main/kotlin/com/flightfeather/uav/domain/entity/BaseRealTimeData.kt index 8c9f9df..1066c78 100644 --- a/src/main/kotlin/com/flightfeather/uav/domain/entity/BaseRealTimeData.kt +++ b/src/main/kotlin/com/flightfeather/uav/domain/entity/BaseRealTimeData.kt @@ -1,23 +1,32 @@ package com.flightfeather.uav.domain.entity -import com.flightfeather.uav.common.utils.DateUtil import com.flightfeather.uav.biz.dataprocess.AvgPair +import com.flightfeather.uav.common.utils.DateUtil import com.flightfeather.uav.lightshare.bean.DataVo +import com.flightfeather.uav.lightshare.bean.FactorStatistics import com.flightfeather.uav.socket.bean.AirData import com.flightfeather.uav.socket.eunm.FactorType +import java.io.Serializable import java.math.BigDecimal import java.time.LocalDateTime import java.time.ZoneId +import java.time.temporal.ChronoUnit import java.util.* import javax.persistence.Column +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType import javax.persistence.Id -import kotlin.math.* +import kotlin.math.atan +import kotlin.math.cos +import kotlin.math.round +import kotlin.math.sin /** * 瀹炴椂鐩戞祴鏁版嵁鍩虹被 */ -open class BaseRealTimeData { +open class BaseRealTimeData : Serializable { @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Int? = null @Column(name = "device_code") @@ -66,6 +75,9 @@ @Column(name = "NOI") var noi: Float? = null + @Column(name = "NO") + var no: Float? = null + var velocity: Float? = null @Column(name = "wind_speed") @@ -105,20 +117,7 @@ add(AirData().apply { setData(FactorType.WIND_SPEED, windSpeed) }) add(AirData().apply { setData(FactorType.WIND_DIRECTION, windDirection) }) add(AirData().apply { setData(FactorType.HEIGHT, height) }) - } - } - - fun getByFactorIndex(i: Int): Float? { - return when (i) { - 0 -> no2 - 1 -> co - 2 -> h2s - 3 -> so2 - 4 -> o3 - 5 -> pm25 - 6 -> pm10 - 7 -> voc - else -> null + add(AirData().apply { setData(FactorType.NO, no) }) } } @@ -138,17 +137,21 @@ FactorType.LNG -> longitude?.toFloat() FactorType.LAT -> latitude?.toFloat() FactorType.VELOCITY -> velocity -// FactorType.TIME -> noi +// FactorType.TIME -> dataTime?.time?.toFloat() FactorType.WIND_SPEED -> windSpeed FactorType.WIND_DIRECTION -> windDirection FactorType.HEIGHT -> height + FactorType.NO -> no else -> null } } } -fun List<BaseRealTimeData>.avg(): RealTimeDataGridMin { +fun List<BaseRealTimeData>.avg(onEach: (BaseRealTimeData) -> Unit = { }): BaseRealTimeData { + if (isEmpty()) { + return BaseRealTimeData() + } //椋庡悜閲囩敤鍗曚綅鐭㈤噺娉曟眰鍙栧潎鍊� var u = .0//涓滆タ鏂逛綅鍒嗛噺鎬诲拰 var v = .0//鍗楀寳鏂逛綅鍒嗛噺鎬诲拰 @@ -156,13 +159,14 @@ //闄ら鍚戝鐨勫叾浠栧洜瀛愰噰鐢ㄧ畻鏈钩鍧囨硶姹傚彇鍧囧�� val tmpList = mutableListOf<AvgPair>() - repeat(17) { + repeat(18) { tmpList.add(AvgPair(0f, 0)) } forEach { + onEach(it) //椋庡悜 - it.windDirection?.let {w -> + it.windDirection?.let { w -> val r = Math.toRadians(w.toDouble()) u += sin(r) v += cos(r) @@ -271,10 +275,18 @@ this.c++ } } + tmpList[17].apply { + it.no?.let { + t += it + this.c++ + } + } } return RealTimeDataGridMin().apply { - val time = LocalDateTime.ofInstant(get(0).dataTime?.toInstant(), ZoneId.systemDefault()).withSecond(0) + val time = LocalDateTime + .ofInstant(get(0).dataTime?.toInstant() ?: Date().toInstant(), ZoneId.systemDefault()) + .withSecond(0) deviceCode = get(0).deviceCode dataTime = Date.from(time.atZone(ZoneId.systemDefault()).toInstant()) createTime = dataTime @@ -295,6 +307,7 @@ velocity = tmpList[14].avg() windSpeed = tmpList[15].avg() height = tmpList[16].avg() + no = tmpList[17].avg() if (c != 0) { val avgU = u / c @@ -315,4 +328,89 @@ windDirection = round(a.toFloat()) } } +} + +/** + * 璁$畻瀹炴椂鐩戞祴鏁版嵁鍒楄〃鐨勭粺璁′俊鎭� + * 涓烘瘡绉嶇幆澧冨洜瀛愯绠楁渶灏忓�笺�佹渶澶у�煎拰骞冲潎鍊� + * @param granularity 鏁版嵁棰楃矑搴︼紝鍙�夊�间负SECOND, MINUTE, HOUR, 榛樿MINUTE + * @return 鍖呭惈鍚勭幆澧冨洜瀛愮粺璁′俊鎭殑FactorStatistics鍒楄〃 + * 姣忎釜FactorStatistics瀵硅薄鍖呭惈鍥犲瓙绫诲瀷銆佹渶灏忓�笺�佹渶澶у�煎拰骞冲潎鍊� + */ +fun List<BaseRealTimeData>.calDataStatistics(granularity: String): List<FactorStatistics> { + + // 妫�鏌ラ绮掑害鏄惁鏈夋晥 + if (granularity !in listOf("SECOND", "MINUTE", "HOUR")) { + throw IllegalArgumentException("鏃犳晥鐨勯绮掑害鍙傛暟锛屽彲閫夊�间负SECOND, MINUTE, HOUR") + } + + val groupedData = when (granularity) { + "SECOND" -> this + "MINUTE" -> groupBy { it.dataTime?.toInstant()?.truncatedTo(ChronoUnit.MINUTES) }.mapValues { + it.value.avg().apply { + dataTime = Date.from(it.key) + createTime = dataTime + } + }.values.toList() + "HOUR" -> groupBy { it.dataTime?.toInstant()?.truncatedTo(ChronoUnit.HOURS) }.mapValues { + it.value.avg().apply { + dataTime = Date.from(it.key) + createTime = dataTime + } + }.values.toList() + else -> throw IllegalArgumentException("鏃犳晥鐨勯绮掑害鍙傛暟锛屽彲閫夊�间负SECOND, MINUTE, HOUR") + } + + // 鍒濆鍖栧悇鐜鍥犲瓙鐨勭粺璁″璞″垪琛� + val statistics = mutableListOf<FactorStatistics>() + listOf( + FactorType.NO2, + FactorType.CO, + FactorType.H2S, + FactorType.SO2, + FactorType.O3, + FactorType.PM25, + FactorType.PM10, + FactorType.VOC, + FactorType.NOI, + FactorType.VELOCITY, + FactorType.WIND_SPEED, + FactorType.HEIGHT, + FactorType.NO + ).forEach { statistics.add(FactorStatistics(it)) } + + // 璁$畻骞冲潎鍊煎苟鍚屾椂鏇存柊鍚勫洜瀛愮殑鏈�灏忓�煎拰鏈�澶у�� + val avgData = groupedData.avg { item -> + // 鏇存柊姣忎釜鍥犲瓙鐨勬渶灏忓拰鏈�澶у�� + statistics[0].updateMinAndMaxValue(item.no2) + statistics[1].updateMinAndMaxValue(item.co) + statistics[2].updateMinAndMaxValue(item.h2s) + statistics[3].updateMinAndMaxValue(item.so2) + statistics[4].updateMinAndMaxValue(item.o3) + statistics[5].updateMinAndMaxValue(item.pm25) + statistics[6].updateMinAndMaxValue(item.pm10) + statistics[7].updateMinAndMaxValue(item.voc) + statistics[8].updateMinAndMaxValue(item.noi) + statistics[9].updateMinAndMaxValue(item.velocity) + statistics[10].updateMinAndMaxValue(item.windSpeed) + statistics[11].updateMinAndMaxValue(item.height) + statistics[12].updateMinAndMaxValue(item.no) + } + + // 灏嗚绠楀緱鍒扮殑骞冲潎鍊艰缃埌瀵瑰簲鐨勭粺璁″璞′腑 + statistics[0].avgValue = avgData.no2 ?: 0f + statistics[1].avgValue = avgData.co ?: 0f + statistics[2].avgValue = avgData.h2s ?: 0f + statistics[3].avgValue = avgData.so2 ?: 0f + statistics[4].avgValue = avgData.o3 ?: 0f + statistics[5].avgValue = avgData.pm25 ?: 0f + statistics[6].avgValue = avgData.pm10 ?: 0f + statistics[7].avgValue = avgData.voc ?: 0f + statistics[8].avgValue = avgData.noi ?: 0f + statistics[9].avgValue = avgData.velocity ?: 0f + statistics[10].avgValue = avgData.windSpeed ?: 0f + statistics[11].avgValue = avgData.height ?: 0f + statistics[12].avgValue = avgData.no ?: 0f + + return statistics } \ No newline at end of file -- Gitblit v1.9.3