| | |
| | | package com.flightfeather.uav.domain.entity |
| | | |
| | | import com.flightfeather.uav.biz.dataprocess.AvgPair |
| | | import com.flightfeather.uav.common.utils.DateUtil |
| | | import com.flightfeather.uav.dataprocess.AvgPair |
| | | import com.flightfeather.uav.lightshare.bean.DataVo |
| | | 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.ZoneOffset |
| | | import java.util.* |
| | | import javax.persistence.Column |
| | | import javax.persistence.GeneratedValue |
| | | import javax.persistence.GenerationType |
| | | import javax.persistence.Id |
| | | 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") |
| | |
| | | @Column(name = "NOI") |
| | | var noi: Float? = null |
| | | |
| | | @Column(name = "NO") |
| | | var no: Float? = null |
| | | |
| | | var velocity: Float? = null |
| | | |
| | | @Column(name = "wind_speed") |
| | |
| | | add(AirData().apply { setData(FactorType.WIND_SPEED, windSpeed) }) |
| | | add(AirData().apply { setData(FactorType.WIND_DIRECTION, windDirection) }) |
| | | add(AirData().apply { setData(FactorType.HEIGHT, height) }) |
| | | add(AirData().apply { setData(FactorType.NO, no) }) |
| | | } |
| | | } |
| | | |
| | | fun getByFactorType(type: FactorType?): Float? { |
| | | return when (type) { |
| | | FactorType.NO2 -> no2 |
| | | FactorType.CO -> co |
| | | FactorType.H2S -> h2s |
| | | FactorType.SO2 -> so2 |
| | | FactorType.O3 -> o3 |
| | | FactorType.PM25 -> pm25 |
| | | FactorType.PM10 -> pm10 |
| | | FactorType.TEMPERATURE -> temperature |
| | | FactorType.HUMIDITY -> humidity |
| | | FactorType.VOC -> voc |
| | | FactorType.NOI -> noi |
| | | FactorType.LNG -> longitude?.toFloat() |
| | | FactorType.LAT -> latitude?.toFloat() |
| | | FactorType.VELOCITY -> velocity |
| | | // FactorType.TIME -> dataTime?.time?.toFloat() |
| | | FactorType.WIND_SPEED -> windSpeed |
| | | FactorType.WIND_DIRECTION -> windDirection |
| | | FactorType.HEIGHT -> height |
| | | FactorType.NO -> no |
| | | else -> null |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | fun List<RealTimeDataGrid>.avg(): RealTimeDataGrid { |
| | | fun List<BaseRealTimeData>.avg(): BaseRealTimeData { |
| | | if (isEmpty()) { |
| | | return BaseRealTimeData() |
| | | } |
| | | //风向采用单位矢量法求取均值 |
| | | var u = 0f//东西方位分量总和 |
| | | var v = 0f//南北方位分量总和 |
| | | var u = .0//东西方位分量总和 |
| | | var v = .0//南北方位分量总和 |
| | | var c = 0//风向数据计数 |
| | | |
| | | //除风向外的其他因子采用算术平均法求取均值 |
| | | val tmpList = mutableListOf<AvgPair>() |
| | | repeat(17) { |
| | | repeat(18) { |
| | | tmpList.add(AvgPair(0f, 0)) |
| | | } |
| | | |
| | | forEach { |
| | | //风向 |
| | | it.windDirection?.let {w -> |
| | | u += sin(w) |
| | | v += cos(w) |
| | | val r = Math.toRadians(w.toDouble()) |
| | | u += sin(r) |
| | | v += cos(r) |
| | | c++ |
| | | } |
| | | //其余因子 |
| | |
| | | this.c++ |
| | | } |
| | | } |
| | | tmpList[17].apply { |
| | | it.no?.let { |
| | | t += it |
| | | this.c++ |
| | | } |
| | | } |
| | | } |
| | | |
| | | return RealTimeDataGrid().apply { |
| | | val time = LocalDateTime.ofInstant(get(0).dataTime?.toInstant(), ZoneId.systemDefault()).withSecond(0) |
| | | return RealTimeDataGridMin().apply { |
| | | 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 |
| | |
| | | velocity = tmpList[14].avg() |
| | | windSpeed = tmpList[15].avg() |
| | | height = tmpList[16].avg() |
| | | no = tmpList[17].avg() |
| | | |
| | | if (c != 0) { |
| | | val avgU = u / c |
| | | val avgV = v / c |
| | | var a = atan(avgU / avgV) |
| | | a = Math.toDegrees(a) |
| | | /** |
| | | * avgU>0;avgV>0: 真实角度处于第一象限,修正值为+0° |
| | | * avgU>0;avgV<0: 真实角度处于第二象限,修正值为+180° |
| | | * avgU<0;avgV<0: 真实角度处于第三象限,修正值为+180° |
| | | * avgU<0;avgV>0: 真实角度处于第四象限,修正值为+360° |
| | | */ |
| | | a += if (avgV > 0) { |
| | | if (avgU > 0) 0 else 360 |
| | | } else { |
| | | 180 |
| | | } |
| | | windDirection = round(a.toFloat()) |
| | | } |
| | | } |
| | | } |