feiyu02
2025-01-03 0ddfab15b32dc054464d75c695999fa76c3b9b78
1. 卫星遥测数据的融合
已修改6个文件
已添加3个文件
247 ■■■■■ 文件已修改
src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteDataMix.kt 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridAnalysisRep.kt 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridRep.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/eunm/SatelliteDataType.kt 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteTelemetryService.kt 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteTelemetryServiceImpl.kt 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/web/SatelliteTelemetryController.kt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/UAVApplicationTests.kt 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteTelemetryServiceImplTest.kt 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteDataMix.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,127 @@
package com.flightfeather.uav.biz.satellite
import com.flightfeather.uav.domain.entity.GridData
import com.flightfeather.uav.domain.entity.GridDataDetail
import com.flightfeather.uav.domain.mapper.GridDataDetailMapper
import com.flightfeather.uav.domain.mapper.GridDataMapper
import com.flightfeather.uav.lightshare.eunm.SatelliteDataType
import org.springframework.beans.BeanUtils
import org.springframework.stereotype.Component
import tk.mybatis.mapper.entity.Example
import java.util.Date
/**
 * å«æ˜Ÿé¥æµ‹æ•°æ®èžåˆ
 * @date 2024/12/31
 * @author feiyu02
 */
@Component
class SatelliteDataMix(
    private val gridDataMapper: GridDataMapper,
    private val gridDataDetailMapper: GridDataDetailMapper,
) {
    /**
     * èžåˆå«æ˜Ÿé¥æµ‹æ•°æ®
     * @param dataIdList æ¯æœŸå«æ˜Ÿé¥æµ‹æ•°æ®çš„主键id数组,表示需要将这几组数据进行数据融合
     */
    fun mixData(dataIdList: List<Int>): Pair<GridData?, List<GridDataDetail>> {
        if (dataIdList.isEmpty()) return null to emptyList()
        // èŽ·å–åŽŸå§‹æ•°æ®
        val originalDataList = gridDataMapper.selectByExample(Example(GridData::class.java).apply {
            createCriteria().andIn("id", dataIdList).andEqualTo("type", SatelliteDataType.Original.value)
        })
        if (originalDataList.isEmpty()) return null to emptyList()
        // èŽ·å–å…·ä½“åŽŸå§‹ç½‘æ ¼æ•°æ®
        val dataDetailList = mutableListOf<List<GridDataDetail?>>()
        originalDataList.forEach {
            val res = gridDataDetailMapper.selectByExample(Example(GridDataDetail::class.java).apply {
                createCriteria().andEqualTo("dataId", it?.id)
                orderBy("cellId")
            })
            dataDetailList.add(res)
        }
        // åˆ›å»ºèžåˆæ•°æ®ç´¢å¼•信息
        val firstGridData = originalDataList.first()
        val avgGridData = GridData().apply {
            groupId = firstGridData?.groupId
            dataTime = Date()
            type = SatelliteDataType.Mix.value.toByte()
            mixDataId = dataIdList.joinToString(",")
        }
        gridDataMapper.insert(avgGridData)
        // è®¡ç®—均值
        val avgResult = calculateAvg(avgGridData.id, dataDetailList)
        gridDataDetailMapper.insertList(avgResult)
        return avgGridData to avgResult
    }
    /**
     * å°†å¤šç»„原始卫星遥测网格PM2.5数据进行融合,计算每个网格的均值
     * @param dataId èžåˆæ•°æ®ä¸»é”®id
     * @param dataDetailList åŽŸå§‹å«æ˜Ÿé¥æµ‹æ•°æ®æ•°ç»„
     */
    fun calculateAvg(dataId: Int, dataDetailList: List<List<GridDataDetail?>>): List<GridDataDetail> {
        if (dataDetailList.isEmpty()) return emptyList()
        // èŽ·å–é¦–ç»„ç½‘æ ¼æ•°æ®ï¼Œä½œä¸ºåŽç»­ç”Ÿæˆèžåˆæ•°æ®çš„ä¾æ®
        val first = dataDetailList.first()
        // æ¯ä¸ªå•元格数据监测值总量
        val totalList = mutableListOf<Float>()
        // æ¯ä¸ªå•元格数据总数
        val countList = mutableListOf<Int>()
        // ç»Ÿè®¡å„网格的数据监测值总量和数据总数
        dataDetailList.forEach {
            it.forEachIndexed { i, d ->
                if (i < totalList.size) {
                    if (d?.pm25 != null) {
                        totalList[i] += d.pm25
                        countList[i]++
                    }
                } else {
                    if (d?.pm25 != null) {
                        totalList.add(d.pm25)
                        countList.add(1)
                    } else {
                        totalList.add(0f)
                        countList.add(0)
                    }
                }
            }
        }
        // è®¡ç®—每个网格的均值
        val avgResult = mutableListOf<GridDataDetail>()
        first.forEachIndexed { i, d ->
            val total = totalList[i]
            val count = countList[i]
            val avg = if (count == 0) {
                null
            } else {
                total / count
            }
            val avgData = GridDataDetail().apply {
                this.dataId = dataId
                groupId = d?.groupId
                cellId = d?.cellId
                pm25 = avg
            }
            avgResult.add(avgData)
        }
        // åˆ·æ–°æŽ’名属性
        avgResult.sortByDescending { it.pm25 }
        avgResult.forEachIndexed { i, d ->
            d.rank = i + 1
        }
        return avgResult
    }
}
src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridAnalysisRep.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package com.flightfeather.uav.domain.repository
import com.flightfeather.uav.domain.mapper.GridDataDetailMapper
import com.flightfeather.uav.domain.mapper.GridDataMapper
/**
 *
 * @date 2024/12/31
 * @author feiyu02
 */
class SatelliteGridAnalysisRep(
    private val gridDataMapper: GridDataMapper,
    private val gridDataDetailMapper: GridDataDetailMapper,
) {
}
src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridRep.kt
@@ -52,6 +52,10 @@
        })
    }
    fun fetchGridData(gridData: GridData): List<GridData?> {
        return gridDataMapper.select(gridData)
    }
    fun fetchGridDataDetail(dataId: Int, groupId: Int?, cellId: Int?): List<GridDataDetail?> {
        return gridDataDetailMapper.selectByExample(Example(GridDataDetail::class.java).apply {
            createCriteria().andEqualTo("dataId", dataId)
src/main/kotlin/com/flightfeather/uav/lightshare/eunm/SatelliteDataType.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package com.flightfeather.uav.lightshare.eunm
/**
 * å«æ˜Ÿé¥æµ‹æ•°æ®ç±»åž‹
 * @date 2024/12/31
 * @author feiyu02
 */
enum class SatelliteDataType(val value: Int) {
    // åŽŸå§‹æ•°æ®
    Original(0),
    // èžåˆæ•°æ®
    Mix(1)
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteTelemetryService.kt
@@ -14,7 +14,7 @@
import javax.servlet.http.HttpServletResponse
/**
 *
 * å«æ˜Ÿé¥æµ‹ç›¸å…³service服务接口
 * @date 2024/12/5
 * @author feiyu02
 */
@@ -28,6 +28,11 @@
    fun fetchGridDataDetail(dataId: Int, groupId: Int?, cellId: Int?): List<GridDataDetail?>
    /**
     * æ•°æ®èžåˆ
     */
    fun mixGridData(dataIdList: List<Int>): List<GridData?>
    @Throws(BizException::class)
    fun importGridData(groupId: Int, dataTime: LocalDateTime?, update: Boolean, file: MultipartFile): GridDataImportResult?
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteTelemetryServiceImpl.kt
@@ -1,5 +1,6 @@
package com.flightfeather.uav.lightshare.service.impl
import com.flightfeather.uav.biz.satellite.SatelliteDataMix
import com.flightfeather.uav.common.exception.BizException
import com.flightfeather.uav.common.utils.FileExchange
import com.flightfeather.uav.domain.entity.GridAod
@@ -14,6 +15,7 @@
import com.flightfeather.uav.lightshare.service.SatelliteTelemetryService
import com.github.pagehelper.PageHelper
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.multipart.MultipartFile
import java.io.ByteArrayInputStream
import java.io.File
@@ -21,6 +23,7 @@
import java.time.ZoneId
import java.util.*
import javax.servlet.http.HttpServletResponse
import kotlin.math.round
/**
 *
@@ -28,7 +31,10 @@
 * @author feiyu02
 */
@Service
class SatelliteTelemetryServiceImpl(private val satelliteGridRep: SatelliteGridRep) : SatelliteTelemetryService {
class SatelliteTelemetryServiceImpl(
    private val satelliteGridRep: SatelliteGridRep,
    private val satelliteDataMix: SatelliteDataMix,
) : SatelliteTelemetryService {
    private val fileExchange = FileExchange()
    override fun fetchGridGroup(areaVo: AreaVo, page: Int?, perPage: Int?): Pair<DataHead, List<GridGroup?>> {
@@ -50,7 +56,27 @@
    }
    override fun fetchGridDataDetail(dataId: Int, groupId: Int?, cellId: Int?): List<GridDataDetail?> {
        return satelliteGridRep.fetchGridDataDetail(dataId, groupId, cellId)
        val res =  satelliteGridRep.fetchGridDataDetail(dataId, groupId, cellId)
        res.forEach {
            if (it?.pm25 != null) {
                it.pm25 = round(it.pm25 * 100) / 100
            }
        }
        return res
    }
    @Transactional
    override fun mixGridData(dataIdList: List<Int>): List<GridData?> {
        if (dataIdList.isEmpty()) throw BizException("融合所需数据id不能为空")
        // 1. æ ¹æ®æ•°æ®ä¸»é”®id数组,查询该组合下是否已有数据融合记录
        val exist = satelliteGridRep.fetchGridData(GridData().apply {
            type = 1
            mixDataId = dataIdList.joinToString(",")
        })
        // 2. è‹¥èžåˆæ•°æ®å·²å­˜åœ¨ï¼Œç›´æŽ¥è¿”回
        return exist.ifEmpty {
            listOf(satelliteDataMix.mixData(dataIdList).first)
        }
    }
    override fun importGridData(groupId: Int, dataTime: LocalDateTime?, update: Boolean, file: MultipartFile): GridDataImportResult? {
src/main/kotlin/com/flightfeather/uav/lightshare/web/SatelliteTelemetryController.kt
@@ -54,6 +54,11 @@
        @ApiParam("网格单元格id") @RequestParam(required = false) cellId: Int?,
    ) = resPack { satelliteTelemetryService.fetchGridDataDetail(dataId, groupId, cellId) }
    @ApiOperation(value = "多次走航数据进行融合计算")
    @PostMapping("/grid/data/mix")
    fun mixGridData(
        @ApiParam("原始数据id数组") @RequestBody dataIdList: List<Int>
    ) = resPack { satelliteTelemetryService.mixGridData(dataIdList) }
    @ApiOperation(value = "导入卫星遥测PM2.5结果数据")
    @PostMapping("/import/grid/data")
src/test/kotlin/com/flightfeather/uav/UAVApplicationTests.kt
@@ -1,5 +1,7 @@
package com.flightfeather.uav
import com.flightfeather.uav.domain.entity.GridDataDetail
import com.flightfeather.uav.domain.mapper.GridDataDetailMapper
import com.flightfeather.uav.lightshare.service.RealTimeDataService
import org.junit.Test
import org.junit.runner.RunWith
@@ -7,6 +9,7 @@
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit4.SpringRunner
import tk.mybatis.mapper.entity.Example
@RunWith(SpringRunner::class)
@SpringBootTest
@@ -15,6 +18,27 @@
    @Autowired
    lateinit var realTimeDataService: RealTimeDataService
    @Autowired
    lateinit var gridDataDetailMapper: GridDataDetailMapper
    /**
     * åˆ·æ–°æ¯ç»„数据的数据排名
     */
    @Test
    fun refreshDataRank() {
        for (i in 29..39) {
            val dataDetailList = gridDataDetailMapper.selectByExample(Example(GridDataDetail::class.java).apply {
                createCriteria().andEqualTo("dataId", i)
                orderBy("pm25").desc()
            })
            dataDetailList.forEachIndexed { i, d ->
                d?.rank = i + 1
                gridDataDetailMapper.updateByPrimaryKey(d)
            }
            println("finish --${i}")
        }
    }
    @Test
    fun contextLoads() {
    }
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteTelemetryServiceImplTest.kt
@@ -2,6 +2,7 @@
import com.flightfeather.uav.domain.entity.GridDataDetail
import com.flightfeather.uav.domain.mapper.GridDataDetailMapper
import com.flightfeather.uav.lightshare.service.SatelliteTelemetryService
import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith
@@ -15,23 +16,10 @@
class SatelliteTelemetryServiceImplTest {
    @Autowired
    lateinit var gridDataDetailMapper: GridDataDetailMapper
    lateinit var satelliteTelemetryService: SatelliteTelemetryService
    /**
     * åˆ·æ–°æ¯ç»„数据的数据排名
     */
    @Test
    fun refreshDataRank() {
        for (i in 1..25) {
            val dataDetailList = gridDataDetailMapper.selectByExample(Example(GridDataDetail::class.java).apply {
                createCriteria().andEqualTo("dataId", i)
                orderBy("pm25").desc()
            })
            dataDetailList.forEachIndexed { i, d ->
                d?.rank = i + 1
                gridDataDetailMapper.updateByPrimaryKey(d)
            }
            println("finish --${i}")
        }
    fun mixGridData() {
        satelliteTelemetryService.mixGridData(listOf(24, 25))
    }
}