1. 监测数据根据设备类型不同分别存储不同数据表
2. 车载数据部分监测因子进行量级调整
3. 无人机监测数据部分监测因子由于偏差较大采用车载数据填充
4. 监测数据存储之前先进行平滑预处理,矫正异常值
已修改17个文件
已添加6个文件
680 ■■■■ 文件已修改
src/main/kotlin/com/flightfeather/uav/common/utils/DateUtil.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/entity/BaseRealTimeData.kt 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/entity/DeviceInfo.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/entity/ExpandFun.kt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/mapper/DeviceInfoMapper.kt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/mapper/RealTimeDataGridMapper.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/mapper/RealTimeDataUavMapper.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/mapper/RealTimeDataVehicleMapper.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/DeviceService.kt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/RealTimeDataService.kt 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/DeviceServiceImpl.kt 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/RealTimeDataServiceImpl.kt 124 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/web/DeviceInfoController.kt 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/model/epw/EPWDataPrep.kt 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/repository/AirDataRepository.kt 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/repository/impl/AirDataRepositoryImpl.kt 184 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/bean/AirData.kt 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/bean/AirDataPackage.kt 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generator/generatorConfig.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/DeviceInfoMapper.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/RealTimeDataServiceImplTest.kt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/utils/DateUtil.kt
@@ -230,7 +230,7 @@
     * @param date æ—¥æœŸå­—符串
     * @return æ—¥æœŸ
     */
    fun StringToDate(date: String): Date? {
    fun StringToDate(date: String?): Date? {
        val dateStyle = getDateStyle(date)
        return StringToDate(date, dateStyle)
    }
src/main/kotlin/com/flightfeather/uav/domain/entity/BaseRealTimeData.kt
@@ -1,5 +1,9 @@
package com.flightfeather.uav.domain.entity
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.socket.bean.AirData
import com.flightfeather.uav.socket.eunm.FactorType
import java.math.BigDecimal
import java.util.*
import javax.persistence.Column
@@ -67,4 +71,36 @@
    var windDirection: Float? = null
    var height: Float? = null
    fun toDataVo() = DataVo().apply {
        this.time = DateUtil.instance.dateToString(dataTime, DateUtil.DateStyle.YYYY_MM_DD_HH_MM_SS)
        this.deviceCode = this@BaseRealTimeData.deviceCode
        this.lng = longitude?.toDouble()
        this.lat = latitude?.toDouble()
        this.values = mutableListOf<AirData>().apply {
            add(AirData().apply { setData(FactorType.NO2, no2) })
            add(AirData().apply { setData(FactorType.CO, co) })
            add(AirData().apply { setData(FactorType.H2S, h2s) })
            add(AirData().apply { setData(FactorType.SO2, so2) })
            add(AirData().apply { setData(FactorType.O3, o3) })
            add(AirData().apply { setData(FactorType.PM25, pm25) })
            add(AirData().apply { setData(FactorType.PM10, pm10) })
            add(AirData().apply { setData(FactorType.TEMPERATURE, temperature) })
            add(AirData().apply { setData(FactorType.HUMIDITY, humidity) })
            add(AirData().apply { setData(FactorType.VOC, voc) })
            add(AirData().apply { setData(FactorType.NOI, noi) })
            add(AirData().apply { setData(FactorType.LNG, lng) })
            add(AirData().apply { setData(FactorType.LAT, lat) })
            add(AirData().apply { setData(FactorType.VELOCITY, velocity) })
            add(AirData().apply {
                setData(FactorType.TIME, dataTime?.time?.toDouble())
                statusList = listOf(time ?: "")
            })
            add(AirData().apply { setData(FactorType.WIND_SPEED, windSpeed) })
            add(AirData().apply { setData(FactorType.WIND_DIRECTION, windDirection) })
            add(AirData().apply { setData(FactorType.HEIGHT, height) })
        }
    }
}
src/main/kotlin/com/flightfeather/uav/domain/entity/DeviceInfo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
package com.flightfeather.uav.domain.entity;
import javax.persistence.*;
@Table(name = "device_info")
public class DeviceInfo {
    @Id
    @Column(name = "device_code")
    private String deviceCode;
    @Column(name = "device_type")
    private String deviceType;
    @Column(name = "type_name")
    private String typeName;
    /**
     * @return device_code
     */
    public String getDeviceCode() {
        return deviceCode;
    }
    /**
     * @param deviceCode
     */
    public void setDeviceCode(String deviceCode) {
        this.deviceCode = deviceCode == null ? null : deviceCode.trim();
    }
    /**
     * @return device_type
     */
    public String getDeviceType() {
        return deviceType;
    }
    /**
     * @param deviceType
     */
    public void setDeviceType(String deviceType) {
        this.deviceType = deviceType == null ? null : deviceType.trim();
    }
    /**
     * @return type_name
     */
    public String getTypeName() {
        return typeName;
    }
    /**
     * @param typeName
     */
    public void setTypeName(String typeName) {
        this.typeName = typeName == null ? null : typeName.trim();
    }
}
src/main/kotlin/com/flightfeather/uav/domain/entity/ExpandFun.kt
@@ -2,6 +2,7 @@
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.common.utils.GsonUtils
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.socket.bean.AirData
import com.flightfeather.uav.socket.eunm.FactorType
@@ -49,6 +50,13 @@
    return row.toTypedArray()
}
fun RealTimeData.toDataVo() = DataVo(
    DateUtil.instance.dateToString(dataTime, DateUtil.DateStyle.YYYY_MM_DD_HH_MM_SS),
    deviceCode,
    GsonUtils.parserJsonToArrayBeans(factors, AirData::class.java),
    longitude?.toDouble(), latitude?.toDouble()
)
fun ElectricMinuteValue.toAirData(): List<AirData> {
    return listOf(
        AirData().apply {
src/main/kotlin/com/flightfeather/uav/domain/mapper/DeviceInfoMapper.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.flightfeather.uav.domain.mapper
import com.flightfeather.uav.domain.MyMapper
import com.flightfeather.uav.domain.entity.DeviceInfo
import org.apache.ibatis.annotations.Mapper
@Mapper
interface DeviceInfoMapper : MyMapper<DeviceInfo>
src/main/kotlin/com/flightfeather/uav/domain/mapper/RealTimeDataGridMapper.kt
@@ -5,4 +5,4 @@
import org.apache.ibatis.annotations.Mapper
@Mapper
interface RealTimeDataGridMapper : MyMapper<RealTimeDataGrid?>
interface RealTimeDataGridMapper : MyMapper<RealTimeDataGrid>
src/main/kotlin/com/flightfeather/uav/domain/mapper/RealTimeDataUavMapper.kt
@@ -5,4 +5,4 @@
import org.apache.ibatis.annotations.Mapper
@Mapper
interface RealTimeDataUavMapper : MyMapper<RealTimeDataUav?>
interface RealTimeDataUavMapper : MyMapper<RealTimeDataUav>
src/main/kotlin/com/flightfeather/uav/domain/mapper/RealTimeDataVehicleMapper.kt
@@ -5,4 +5,4 @@
import org.apache.ibatis.annotations.Mapper
@Mapper
interface RealTimeDataVehicleMapper : MyMapper<RealTimeDataVehicle?>
interface RealTimeDataVehicleMapper : MyMapper<RealTimeDataVehicle>
src/main/kotlin/com/flightfeather/uav/lightshare/service/DeviceService.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
package com.flightfeather.uav.lightshare.service
import com.flightfeather.uav.domain.entity.DeviceInfo
import com.flightfeather.uav.lightshare.bean.BaseResponse
interface DeviceService {
    fun getDeviceInfo(): BaseResponse<List<DeviceInfo>>
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/RealTimeDataService.kt
@@ -19,4 +19,10 @@
    fun outToWorkbook(deviceCode: String, startTime: String, endTime: String): SXSSFWorkbook
    fun outToExcel(deviceCode: String, startTime: String, endTime: String, response: HttpServletResponse): HttpServletResponse
    /**
     * æ•°æ®å¤„理
     * åŽ»é™¤åŽŸå§‹æ•°æ®ä¸­çš„å¼‚å¸¸æ³¢åŠ¨å€¼
     */
    fun dataPreprocessing(): BaseResponse<String>
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/DeviceServiceImpl.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.flightfeather.uav.lightshare.service.impl
import com.flightfeather.uav.domain.entity.DeviceInfo
import com.flightfeather.uav.domain.mapper.DeviceInfoMapper
import com.flightfeather.uav.lightshare.bean.BaseResponse
import com.flightfeather.uav.lightshare.service.DeviceService
import org.springframework.stereotype.Service
@Service
class DeviceServiceImpl(
    private val deviceInfoMapper: DeviceInfoMapper
) : DeviceService {
    override fun getDeviceInfo(): BaseResponse<List<DeviceInfo>> {
        val r = deviceInfoMapper.selectAll()
        return BaseResponse(true, data = r)
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/RealTimeDataServiceImpl.kt
@@ -4,13 +4,17 @@
import com.flightfeather.uav.common.utils.ExcelUtil
import com.flightfeather.uav.common.utils.FileExchange
import com.flightfeather.uav.common.utils.GsonUtils
import com.flightfeather.uav.domain.entity.RealTimeData
import com.flightfeather.uav.domain.entity.toRowContent
import com.flightfeather.uav.domain.entity.toRowTitle
import com.flightfeather.uav.domain.entity.*
import com.flightfeather.uav.domain.mapper.RealTimeDataGridMapper
import com.flightfeather.uav.domain.mapper.RealTimeDataMapper
import com.flightfeather.uav.domain.mapper.RealTimeDataUavMapper
import com.flightfeather.uav.domain.mapper.RealTimeDataVehicleMapper
import com.flightfeather.uav.lightshare.bean.*
import com.flightfeather.uav.lightshare.service.RealTimeDataService
import com.flightfeather.uav.model.epw.EPWDataPrep
import com.flightfeather.uav.repository.AirDataRepository
import com.flightfeather.uav.socket.bean.AirData
import com.flightfeather.uav.socket.eunm.UWDeviceType
import com.github.pagehelper.PageHelper
import org.apache.poi.xssf.streaming.SXSSFWorkbook
import org.springframework.stereotype.Service
@@ -22,7 +26,13 @@
import javax.servlet.http.HttpServletResponse
@Service
class RealTimeDataServiceImpl(val realTimeDataMapper: RealTimeDataMapper) : RealTimeDataService {
class RealTimeDataServiceImpl(
    private val realTimeDataMapper: RealTimeDataMapper,
    private val airDataRepository: AirDataRepository,
    private val realTimeDataVehicleMapper: RealTimeDataVehicleMapper,
    private val realTimeDataUavMapper: RealTimeDataUavMapper,
    private val realTimeDataGridMapper: RealTimeDataGridMapper
) : RealTimeDataService {
    private var dateFormatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    private val fileExchange = FileExchange()
@@ -34,33 +44,54 @@
        val eTime = endTime?.let { dateFormatter.parse(it) }
        val pageInfo = PageHelper.startPage<RealTimeData>(_page, _perPage)
        val result = mutableListOf<DataVo>()
        when (UWDeviceType.getType(deviceCode)) {
            UWDeviceType.VEHICLE -> {
                realTimeDataVehicleMapper.selectByExample(Example(RealTimeDataVehicle::class.java).apply {
                    getSecondDataExample(this, deviceCode, sTime, eTime)
                }).forEach { result.add(it.toDataVo()) }
            }
            UWDeviceType.UAV -> {
                realTimeDataUavMapper.selectByExample(Example(RealTimeDataUav::class.java).apply {
                    getSecondDataExample(this, deviceCode, sTime, eTime)
                }).forEach { result.add(it.toDataVo()) }
            }
            UWDeviceType.GRID -> {
                realTimeDataGridMapper.selectByExample(Example(RealTimeDataGrid::class.java).apply {
                    getSecondDataExample(this, deviceCode, sTime, eTime)
                }).forEach { result.add(it.toDataVo()) }
            }
            else -> {
                // ä»ŽåŽŸå§‹æ•°æ®è¡¨ä¸­èŽ·å–æ•°æ®
        realTimeDataMapper.selectByExample(Example(RealTimeData::class.java).apply {
            createCriteria().apply {
                deviceCode?.let { andEqualTo("deviceCode", it) }
                sTime?.let { andGreaterThanOrEqualTo("dataTime", it) }
                eTime?.let { andLessThanOrEqualTo("dataTime", it) }
            }
            orderBy("dataTime").apply {
                // å½“请求接口不传递起始时间,默认获取最新的数据
                if (startTime == null && endTime == null) {
                    desc()
                }
            }
                    getSecondDataExample(this, deviceCode, sTime, eTime)
        }).forEach {
            if (it.longitude == null || it.latitude == null) {
                return@forEach
            }
            result.add(DataVo(
                    dateFormatter.format(it.dataTime),
                    it.deviceCode,
                    GsonUtils.parserJsonToArrayBeans(it.factors, AirData::class.java),
                    it.longitude?.toDouble(), it.latitude?.toDouble()
            ))
                    result.add(it.toDataVo())
        }
            }
        }
        if (startTime == null && endTime == null) {
            result.reverse()
        }
        return BaseResponse(true, head = DataHead(pageInfo.pageNum, pageInfo.pages), data = result)
    }
    private fun getSecondDataExample(example: Example, deviceCode: String?, sTime: Date?, eTime: Date?) {
        example.createCriteria().apply {
            deviceCode?.let { andEqualTo("deviceCode", it) }
            sTime?.let { andGreaterThanOrEqualTo("dataTime", it) }
            eTime?.let { andLessThanOrEqualTo("dataTime", it) }
        }
        example.orderBy("dataTime").apply {
            // å½“请求接口不传递起始时间,默认获取最新的数据
            if (sTime == null && eTime == null) {
                desc()
            }
        }
    }
    override fun getNextData(deviceCode: String, updateTime: String, page: Int?, perPage: Int?): BaseResponse<List<DataVo>> {
@@ -68,19 +99,36 @@
        val _page = page ?: 1
        val pageInfo = PageHelper.startPage<RealTimeData>(_page, _perPage)
        val result = mutableListOf<DataVo>()
        when (UWDeviceType.getType(deviceCode)) {
            UWDeviceType.VEHICLE -> {
                realTimeDataVehicleMapper.selectByExample(Example(RealTimeDataVehicle::class.java).apply {
                    getNextDataExample(this, deviceCode, updateTime)
                }).forEach { result.add(it.toDataVo()) }
            }
            UWDeviceType.UAV -> {
                realTimeDataUavMapper.selectByExample(Example(RealTimeDataUav::class.java).apply {
                    getNextDataExample(this, deviceCode, updateTime)
                }).forEach { result.add(it.toDataVo()) }
            }
            UWDeviceType.GRID -> {
                realTimeDataGridMapper.selectByExample(Example(RealTimeDataGrid::class.java).apply {
                    getNextDataExample(this, deviceCode, updateTime)
                }).forEach { result.add(it.toDataVo()) }
            }
            else -> {
        realTimeDataMapper.selectByExample(Example(RealTimeData::class.java).apply {
            createCriteria().andEqualTo("deviceCode", deviceCode)
                .andGreaterThan("dataTime", updateTime)
            orderBy("dataTime")
        }).forEach {
            result.add(DataVo(
                dateFormatter.format(it.dataTime),
                it.deviceCode,
                GsonUtils.parserJsonToArrayBeans(it.factors, AirData::class.java),
                it.longitude.toDouble(), it.latitude.toDouble()
            ))
                    getNextDataExample(this, deviceCode, updateTime)
                }).forEach { result.add(it.toDataVo()) }
            }
        }
        return BaseResponse(true, head = DataHead(pageInfo.pageNum, pageInfo.pages), data = result)
    }
    private fun getNextDataExample(example: Example, deviceCode: String, updateTime: String) {
        example.createCriteria().andEqualTo("deviceCode", deviceCode)
            .andGreaterThan("dataTime", updateTime)
        example.orderBy("dataTime")
    }
    override fun importData(file: MultipartFile): BaseResponse<DataImportResult> {
@@ -149,4 +197,18 @@
        }
        return contents
    }
    override fun dataPreprocessing(): BaseResponse<String> {
        val epwDataPrep = EPWDataPrep()
        val res = getSecondData("0b0000000002", "2021-10-23 19:00:00", "2021-10-23 20:00:00", 1, 5000)
        val dataList = res.data ?: emptyList()
        var count = 0
        dataList.forEach {
            val result = epwDataPrep.mDataPrep2(listOf(it))
            count += airDataRepository.savePrepData2(result)
            println("[${it.deviceCode}]: [${it.time}]")
            Thread.sleep(4000)
        }
        return BaseResponse(count > 0, data = "插入数据: ${count}条")
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/web/DeviceInfoController.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package com.flightfeather.uav.lightshare.web
import com.flightfeather.uav.lightshare.service.DeviceService
import io.swagger.annotations.Api
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@Api(tags = ["走航监测设备API接口"])
@RestController
@RequestMapping("air/device")
class DeviceInfoController(private val deviceService: DeviceService) {
    fun getDeviceInfo() = deviceService.getDeviceInfo()
}
src/main/kotlin/com/flightfeather/uav/model/epw/EPWDataPrep.kt
@@ -1,11 +1,16 @@
package com.flightfeather.uav.model.epw
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.common.utils.GsonUtils
import com.flightfeather.uav.lightshare.bean.CompanySOP
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.model.BaseDataPrep
import com.flightfeather.uav.socket.bean.AirData
import com.flightfeather.uav.socket.bean.AirDataPackage
import com.flightfeather.uav.socket.eunm.FactorType
import kotlin.math.max
import kotlin.math.min
import kotlin.math.round
import kotlin.math.sqrt
class EPWDataPrep : BaseDataPrep<DataVo, CompanySOP>() {
@@ -63,7 +68,7 @@
                    list.addAll(mDataList.subList(thisIndex, i))
                    // åŽ»é™¤æ— æ•ˆå€¼çš„å¹³å‡
                    val avg = average(list, it.factorName)
                    val avg = average(list, it.factorName) ?: continue
                    // åŽ»é™¤æ— æ•ˆå€¼çš„æ ‡å‡†å·®
                    val std = standardDeviation(avg.first, list, it.factorName)
                    // åˆç†æœ€å¤§å€¼
@@ -98,20 +103,96 @@
        return sopList
    }
    fun mDataPrep2(dataPackage: AirDataPackage): List<DataVo> {
        val vo = dataPackage.toDataVo()
        return mDataPrep2(listOf(vo))
    }
    fun mDataPrep2(mDataList: List<DataVo>): List<DataVo> {
        var i = ncal
        if (lastData.isNotEmpty()) {
            i = 0
        }
        while (i < mDataList.size) {
            for (y in mDataList[i].values?.indices ?: 0..0) {
                val it = mDataList[i].values?.get(y) ?: continue
                if (!calTypes.contains(it.factorName)) continue
                val vMax = FactorType.getVMax(it.factorName) ?: continue
//                it.factorData ?: continue
                if (it.factorData!! > vMax) {
                    val lastDataIndex = i
                    val thisIndex = if (i-ncal<0) 0 else i - ncal
                    val list = mutableListOf<DataVo>()
                    if (lastDataIndex < lastData.size) {
                        list.addAll(lastData.subList(lastDataIndex, lastData.lastIndex + 1))
                    }
                    list.addAll(mDataList.subList(thisIndex, i))
                    // åŽ»é™¤æ— æ•ˆå€¼çš„å¹³å‡ï¼Œå½“æ‰€æœ‰æ•°æ®éƒ½æ˜¯æ— æ•ˆå€¼æ—¶ï¼Œæš‚ä¸åšå¤„ç†
                    average(list, it.factorName)?.let { avg ->
                        // åŽ»é™¤æ— æ•ˆå€¼çš„æ ‡å‡†å·®
                        val std = standardDeviation(avg.first, list, it.factorName)
                        // åˆç†æœ€å¤§å€¼
                        val max = max(avg.first + std * nstd, avg.first + avg.first * xratio)
                        // åˆç†æœ€å°å€¼
                        val min = min(avg.first - std * nstd, avg.first / (1 + xratio))
                        // æ•°æ®ä¸å¤„于合理范围并且有效个数达标时,采用计算所得均值代替原始值
                        if (avg.second > max(ncal / 5, 2)
                            && (it.factorData!! < min || it.factorData!! > max)
                        ) {
                            // åŽŸå§‹æ•°æ®
//                        it.factorData = null
                            it.factorData = avg.first
                        }
                    }
                }
            }
            i++
        }
        // å°†æ–°æ•°æ®çš„至多最后15个保存下来(已经过预处理),用于下一次的判断
        val newList = mutableListOf<DataVo>()
        val s = if ((mDataList.lastIndex - ncal + 1) < 0) 0 else mDataList.lastIndex - ncal + 1
        mDataList.subList(s, mDataList.lastIndex + 1).forEach {
            newList.add(it.copy())
        }
        // å½“新数据与旧数据采样时间差超过1分钟时,认为两组数据已无关联性,清空旧数据
        if (lastData.isNotEmpty() && newList.isNotEmpty()) {
            val lastTime = DateUtil.instance.StringToDate(lastData.last().time)
            val thisTime = DateUtil.instance.StringToDate(newList.first().time)
            if (thisTime?.time?.minus(lastTime?.time ?: 0) ?: 0 >= (60 * 1000)) {
                lastData.clear()
            }
        }
        lastData.addAll(newList)
        // ç¡®ä¿ä¿å­˜çš„æ•°æ®æœ€å¤šåªæœ‰æœ€æ–°çš„15个
        while (lastData.size > ncal) {
            lastData.removeAt(0)
        }
        return mDataList
    }
    /**
     * åŽ»é™¤æ— æ•ˆå€¼çš„å¹³å‡
     * @param list ç›‘测数据
     * @return å‡å€¼å’Œæœ‰æ•ˆæ•°æ®ä¸ªæ•°
     */
    private fun average(list: List<DataVo>, factorName:String?): Pair<Double, Int> {
    private fun average(list: List<DataVo>, factorName:String?): Pair<Double, Int>? {
        var t = 0.0
        var c = 0
        list.forEach {
            for (i in it.values?.indices ?: 0..0) {
                val f = it.values?.get(i)
                if (f?.factorName == factorName) {
                    if (f?.factorData != null) {
                        t += f.factorData!!
                    val range = FactorType.getRange(f?.factorName) ?: continue
                    //判断数据是否在合理范围内
                    if (f?.factorData ?: 0.0 in range.first..range.second) {
                        t += f?.factorData!!
                        c++
                    }
                    break
@@ -122,10 +203,14 @@
        val avg = if (c == 0) {
            0.0
        } else {
            t / c
            round(t / c * 1000) / 1000
        }
        return Pair(avg, c)
        return if (c == 0) {
            null
        } else {
            Pair(avg, c)
        }
    }
    /**
@@ -138,8 +223,9 @@
            for (i in it.values?.indices ?: 0..0) {
                val f = it.values?.get(i)
                if (f?.factorName == factorName) {
                    if (f?.factorData != null) {
                        t += (f.factorData!! - avg) * (f.factorData!! - avg)
                    val range = FactorType.getRange(f?.factorName) ?: continue
                    if (f?.factorData ?: 0.0 in range.first..range.second) {
                        t += (f?.factorData!! - avg) * (f.factorData!! - avg)
                        c++
                    }
                    break
src/main/kotlin/com/flightfeather/uav/repository/AirDataRepository.kt
@@ -1,6 +1,7 @@
package com.flightfeather.uav.repository
import com.flightfeather.uav.domain.entity.RealTimeData
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.socket.bean.AirDataPackage
/**
@@ -19,6 +20,11 @@
     */
    fun savePrepData(dataPackage: AirDataPackage): Int
    /**
     * å­˜å‚¨é¢„处理后的数据
     */
    fun savePrepData(dataList: List<RealTimeData>): Int
    fun savePrepData2(dataList: List<DataVo>): Int
}
src/main/kotlin/com/flightfeather/uav/repository/impl/AirDataRepositoryImpl.kt
@@ -13,9 +13,13 @@
import com.flightfeather.uav.socket.bean.AirDataPackage
import com.flightfeather.uav.socket.eunm.FactorType
import com.flightfeather.uav.socket.eunm.UWDeviceType
import com.github.pagehelper.PageHelper
import com.google.gson.Gson
import org.springframework.stereotype.Repository
import tk.mybatis.mapper.entity.Example
import java.math.BigDecimal
import java.text.SimpleDateFormat
import java.util.*
/**
 * @author riku
@@ -29,11 +33,14 @@
    private val realTimeDataGridMapper: RealTimeDataGridMapper
): AirDataRepository {
    // FIXME: 2021/10/25 ä¸´æ—¶è½¦è½½æ•°æ®ï¼Œç”±äºŽæ— äººæœºéƒ¨åˆ†ç›‘测因子数据无效,因此暂时采用车载数据作为填充
    private val tmpVehicleDataList = mutableListOf<BaseRealTimeData>()
    override fun saveAirData(dataPackage: AirDataPackage): Int {
        val data = RealTimeData().apply {
            deviceCode = dataPackage.deviceCode
            latitude
            longitude
            latitude = BigDecimal.ZERO
            longitude = BigDecimal.ZERO
            altitude
            height
            factors = Gson().toJson(dataPackage.dataUnit)
@@ -62,55 +69,28 @@
    }
    override fun savePrepData(dataPackage: AirDataPackage): Int {
        var mapper: MyMapper<out BaseRealTimeData?>? = null
        var count = 0
        when (UWDeviceType.getType(dataPackage.deviceCode)) {
            UWDeviceType.VEHICLE -> {
                mapper = realTimeDataVehicleMapper
                RealTimeDataVehicle()
                val d = RealTimeDataVehicle()
                dataTransform(dataPackage, d)
                realTimeDataVehicleMapper.insert(d)
                count++
            }
            UWDeviceType.UAV -> {
                mapper = realTimeDataUavMapper
                RealTimeDataUav()
                val d = RealTimeDataUav()
                dataTransform(dataPackage, d)
                realTimeDataUavMapper.insert(d)
                count++
            }
            UWDeviceType.GRID -> {
                mapper = realTimeDataGridMapper
                RealTimeDataGrid()
            }
            else -> null
        }?.run {
            deviceCode = dataPackage.deviceCode
            dataPackage.dataUnit.forEach {
                if (it is AirData) {
                    when (it.factorId?.toInt()) {
                        FactorType.NO2.value -> no2 = it.factorData?.toFloat()
                        FactorType.CO.value -> co = it.factorData?.toFloat()
                        FactorType.H2S.value -> h2s = it.factorData?.toFloat()
                        FactorType.SO2.value -> so2 = it.factorData?.toFloat()
                        FactorType.O3.value -> o3 = it.factorData?.toFloat()
                        FactorType.PM25.value -> pm25 = it.factorData?.toFloat()
                        FactorType.PM10.value -> pm10 = it.factorData?.toFloat()
                        FactorType.TEMPERATURE.value -> temperature = it.factorData?.toFloat()
                        FactorType.HUMIDITY.value -> humidity = it.factorData?.toFloat()
                        FactorType.VOC.value -> voc = it.factorData?.toFloat()
                        FactorType.NOI.value -> noi = it.factorData?.toFloat()
                        FactorType.VELOCITY.value -> velocity = it.factorData?.toFloat()
                        FactorType.WIND_SPEED.value -> windSpeed = it.factorData?.toFloat()
                        FactorType.WIND_DIRECTION.value -> windDirection = it.factorData?.toFloat()
                        FactorType.HEIGHT.value -> height = it.factorData?.toFloat()
                        FactorType.LAT.value -> latitude = it.factorData?.toBigDecimal()
                        FactorType.LNG.value -> longitude = it.factorData?.toBigDecimal()
                        FactorType.TIME.value -> it.statusList?.takeIf { l -> l.isNotEmpty() }?.get(0)?.let { d ->
                            dataTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(d)
                val d = RealTimeDataGrid()
                dataTransform(dataPackage, d)
                realTimeDataGridMapper.insert(d)
                count++
                        }
                    }
                }
            }
//            mapper?.insert(this)
            return 1
        }
        return 0
        return count
    }
    override fun savePrepData(dataList: List<RealTimeData>): Int {
@@ -126,6 +106,59 @@
                UWDeviceType.UAV -> {
                    val d = RealTimeDataUav()
                    dataTransform(vo, d)
                    realTimeDataUavMapper.insert(d)
                    count++
                }
                UWDeviceType.GRID -> {
                    val d = RealTimeDataGrid()
                    dataTransform(vo, d)
                    realTimeDataGridMapper.insert(d)
                    count++
                }
            }
        }
        return count
    }
    override fun savePrepData2(dataList: List<DataVo>): Int {
        var count = 0
        dataList.forEach {vo ->
            when (UWDeviceType.getType(vo.deviceCode)) {
                UWDeviceType.VEHICLE -> {
                    val d = RealTimeDataVehicle()
                    dataTransform(vo, d)
                    /***************************************************************************************************/
                    // FIXME: 2021/10/27 è½¦è½½ç›‘测部分因子量级调整:NO2*0.6,H2S*0.3, SO2*0.2, O3*0.5,其他要素不变
                    d.no2 = d.no2?.times(0.6f)
                    d.h2s = d.h2s?.times(0.3f)
                    d.so2 = d.so2?.times(0.2f)
                    d.o3 = d.o3?.times(0.5f)
                    /***************************************************************************************************/
                    realTimeDataVehicleMapper.insert(d)
                    count++
                }
                UWDeviceType.UAV -> {
                    val d = RealTimeDataUav()
                    dataTransform(vo, d)
                    /***************************************************************************************************/
                    // FIXME: 2021/10/25 æ— äººæœºéƒ¨åˆ†å› å­é‡‡ç”¨è½¦è½½æ•°æ®å¡«å……,取最新的15分钟的数据
                    if (tmpVehicleDataList.isEmpty()) {
                        val p = PageHelper.startPage<RealTimeDataVehicle>(1, 225)
                        realTimeDataVehicleMapper.selectByExample(Example(RealTimeDataVehicle::class.java).apply {
                            orderBy("dataTime").desc()
                        }).let { tmpVehicleDataList.addAll(it) }
                    }
                    if (tmpVehicleDataList.isNotEmpty()) {
                        tmpVehicleDataList[0].let {
                            d.no2 = it.no2
                            d.co = it.co
                            d.h2s = it.h2s
                            d.so2 = it.so2
                            d.o3 = it.o3
                        }
                        tmpVehicleDataList.removeFirst()
                    }
                    /***************************************************************************************************/
                    realTimeDataUavMapper.insert(d)
                    count++
                }
@@ -169,4 +202,69 @@
        }
    }
    private fun dataTransform(dataPackage: AirDataPackage, bean: BaseRealTimeData) {
        bean.apply {
            deviceCode = dataPackage.deviceCode
            dataPackage.dataUnit.forEach {
                if (it is AirData) {
                    when (it.factorId?.toInt()) {
                        FactorType.NO2.value -> no2 = it.factorData?.toFloat()
                        FactorType.CO.value -> co = it.factorData?.toFloat()
                        FactorType.H2S.value -> h2s = it.factorData?.toFloat()
                        FactorType.SO2.value -> so2 = it.factorData?.toFloat()
                        FactorType.O3.value -> o3 = it.factorData?.toFloat()
                        FactorType.PM25.value -> pm25 = it.factorData?.toFloat()
                        FactorType.PM10.value -> pm10 = it.factorData?.toFloat()
                        FactorType.TEMPERATURE.value -> temperature = it.factorData?.toFloat()
                        FactorType.HUMIDITY.value -> humidity = it.factorData?.toFloat()
                        FactorType.VOC.value -> voc = it.factorData?.toFloat()
                        FactorType.NOI.value -> noi = it.factorData?.toFloat()
                        FactorType.VELOCITY.value -> velocity = it.factorData?.toFloat()
                        FactorType.WIND_SPEED.value -> windSpeed = it.factorData?.toFloat()
                        FactorType.WIND_DIRECTION.value -> windDirection = it.factorData?.toFloat()
                        FactorType.HEIGHT.value -> height = it.factorData?.toFloat()
                        FactorType.LAT.value -> latitude = it.factorData?.toBigDecimal()
                        FactorType.LNG.value -> longitude = it.factorData?.toBigDecimal()
                        FactorType.TIME.value -> it.statusList?.takeIf { l -> l.isNotEmpty() }?.get(0)?.let { d ->
                            dataTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(d)
                        }
                    }
                }
            }
        }
    }
    private fun dataTransform(vo: DataVo, bean: BaseRealTimeData) {
        bean.apply {
            deviceCode = vo.deviceCode
            latitude = vo.lat?.toBigDecimal()
            longitude = vo.lng?.toBigDecimal()
            dataTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(vo.time)
            createTime = Date()
            vo.values?.forEach {
                when (it.factorId?.toInt()) {
                    FactorType.NO2.value -> no2 = it.factorData?.toFloat()
                    FactorType.CO.value -> co = it.factorData?.toFloat()
                    FactorType.H2S.value -> h2s = it.factorData?.toFloat()
                    FactorType.SO2.value -> so2 = it.factorData?.toFloat()
                    FactorType.O3.value -> o3 = it.factorData?.toFloat()
                    FactorType.PM25.value -> pm25 = it.factorData?.toFloat()
                    FactorType.PM10.value -> pm10 = it.factorData?.toFloat()
                    FactorType.TEMPERATURE.value -> temperature = it.factorData?.toFloat()
                    FactorType.HUMIDITY.value -> humidity = it.factorData?.toFloat()
                    FactorType.VOC.value -> voc = it.factorData?.toFloat()
                    FactorType.NOI.value -> noi = it.factorData?.toFloat()
                    FactorType.VELOCITY.value -> velocity = it.factorData?.toFloat()
                    FactorType.WIND_SPEED.value -> windSpeed = it.factorData?.toFloat()
                    FactorType.WIND_DIRECTION.value -> windDirection = it.factorData?.toFloat()
                    FactorType.HEIGHT.value -> height = it.factorData?.toFloat()
                }
            }
        }
    }
}
src/main/kotlin/com/flightfeather/uav/socket/bean/AirData.kt
@@ -1,6 +1,8 @@
package com.flightfeather.uav.socket.bean
import com.fasterxml.jackson.annotation.JsonInclude
import com.flightfeather.uav.socket.eunm.FactorType
import kotlin.math.round
/**
 * @author riku
@@ -20,4 +22,14 @@
    //状态位
    var statusList: List<String>? = null
    fun setData(factorType: FactorType, value: Float?) {
        setData(factorType, round(value?.toDouble()?.times(1000) ?: .0) / 1000)
    }
    fun setData(factorType: FactorType, value: Double?) {
        factorId = factorType.value.toString()
        factorName = factorType.des
        factorData = value
    }
}
src/main/kotlin/com/flightfeather/uav/socket/bean/AirDataPackage.kt
@@ -1,6 +1,10 @@
package com.flightfeather.uav.socket.bean
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.socket.eunm.AirCommandUnit
import com.flightfeather.uav.socket.eunm.FactorType
import java.text.SimpleDateFormat
import java.util.*
/**
@@ -38,4 +42,29 @@
        const val FACTOR_BIT_LENGTH_2 = 3
        const val FACTOR_BIT_LENGTH_3 = 2
    }
    fun toDataVo()= DataVo().apply {
        this.time = DateUtil.instance.dateToString(dataTime, DateUtil.DateStyle.YYYY_MM_DD_HH_MM_SS)
        this.deviceCode = this@AirDataPackage.deviceCode
        val tempList = mutableListOf<AirData>()
        this@AirDataPackage.dataUnit.forEach {
            if (it is AirData) {
                when (it.factorId?.toInt()) {
                    FactorType.LAT.value -> {
                        this.lat = it.factorData
                    }
                    FactorType.LNG.value -> {
                        this.lng = it.factorData
                    }
                    FactorType.TIME.value -> {
                        it.statusList?.takeIf {l-> l.isNotEmpty() }?.get(0)?.let {d ->
                            this.time = d
                        }
                    }
                }
                tempList.add(it)
            }
        }
        this.values = tempList
    }
}
src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt
@@ -1,5 +1,6 @@
package com.flightfeather.uav.socket.processor
import com.flightfeather.uav.model.epw.EPWDataPrep
import com.flightfeather.uav.repository.AirDataRepository
import com.flightfeather.uav.socket.bean.AirDataPackage
import com.flightfeather.uav.socket.decoder.AirDataDecoder
@@ -31,8 +32,11 @@
    @Autowired
    lateinit var airDataRepository: AirDataRepository
    val airDataDecoder = AirDataDecoder.instance
    val dataPackageDecoder = DataPackageDecoder()
    private val airDataDecoder = AirDataDecoder.instance
    private val dataPackageDecoder = DataPackageDecoder()
    // æ•°æ®é¢„处理函数
    private val dataProcessMap = mutableMapOf<String?, EPWDataPrep>()
    @PostConstruct
    fun init() {
@@ -63,6 +67,14 @@
            AirCommandUnit.AirData.value -> {
                // ä»¥json格式存储原始数据
                instance.airDataRepository.saveAirData(dataPackage)
                // è¿›è¡Œé¢„处理后,存储至对应数据表
                if (!dataProcessMap.containsKey(dataPackage.deviceCode)) {
                    dataProcessMap[dataPackage.deviceCode] = EPWDataPrep()// æ¯å°è®¾å¤‡æœ‰å•独的数据预处理对象
                }
                dataProcessMap[dataPackage.deviceCode]?.run {
                    val list = this.mDataPrep2(dataPackage)// æ•°æ®å¹³æ»‘处理
                    instance.airDataRepository.savePrepData2(list)// æŒ‰ç…§è®¾å¤‡ç±»åž‹å­˜å‚¨è‡³å¯¹åº”数据表
                }
            }
        }
    }
src/main/resources/application.yml
@@ -7,9 +7,9 @@
#    password: cn.FLIGHTFEATHER
#    çº¿ä¸ŠæœåС噍
#    url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
#    username: dronemonitor
#    password: dronemonitor_hackxrnomxm
    url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
    username: dronemonitor
    password: dronemonitor_hackxrnomxm
#    å¼€å‘本地服务器
#    url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
@@ -17,9 +17,9 @@
#    password: 123456
#   å¼€å‘远程服务器
    url: jdbc:mysql://47.100.191.150:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
    username: remoteU1
    password: eSoF8DnzfGTlhAjE
#    url: jdbc:mysql://47.100.191.150:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
#    username: remoteU1
#    password: eSoF8DnzfGTlhAjE
    hikari:
      maximum-pool-size: 500
      minimum-idle: 20
src/main/resources/generator/generatorConfig.xml
@@ -51,8 +51,9 @@
<!--        <table tableName="el_company_device" domainObjectName="CompanyDevice" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
<!--        <table tableName="co_complaint" domainObjectName="Complaint" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
<!--        <table tableName="co_assessment" domainObjectName="Assessment" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
        <table tableName="real_time_data_grid" domainObjectName="RealTimeDataGrid" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
        <table tableName="real_time_data_uav" domainObjectName="RealTimeDataUav" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
        <table tableName="real_time_data_vehicle" domainObjectName="RealTimeDataVehicle" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
<!--        <table tableName="real_time_data_grid" domainObjectName="RealTimeDataGrid" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
<!--        <table tableName="real_time_data_uav" domainObjectName="RealTimeDataUav" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
<!--        <table tableName="real_time_data_vehicle" domainObjectName="RealTimeDataVehicle" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
        <table tableName="device_info" domainObjectName="DeviceInfo" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
    </context>
</generatorConfiguration>
src/main/resources/mapper/DeviceInfoMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.flightfeather.uav.domain.mapper.DeviceInfoMapper">
  <resultMap id="BaseResultMap" type="com.flightfeather.uav.domain.entity.DeviceInfo">
    <!--
      WARNING - @mbg.generated
    -->
    <id column="device_code" jdbcType="VARCHAR" property="deviceCode" />
    <result column="device_type" jdbcType="VARCHAR" property="deviceType" />
    <result column="type_name" jdbcType="VARCHAR" property="typeName" />
  </resultMap>
  <sql id="Base_Column_List">
    <!--
      WARNING - @mbg.generated
    -->
    device_code, device_type, type_name
  </sql>
</mapper>
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/RealTimeDataServiceImplTest.kt
@@ -116,4 +116,9 @@
            }
        }
    }
    @Test
    fun dataPreprocessing() {
        realTimeDataService.dataPreprocessing()
    }
}