说明文档及下载链接

一、加速度信号处理优化(MainActivity.kt)

1.1 滑动窗口缩小

windowSize: 10 → 6

缩小滑动窗口至约 120ms(6 帧),最大限度保留不到 1s 的轨道冲击峰值。

1.2 全局增益(baseGain)

InspectorState 中新增 baseGain 参数,默认值 1.5,可持久化到 SharedPreferences。在传感器计算中:

val totalGainV = s.scaleZ * s.baseGain
val totalGainH = s.scaleX * s.baseGain

与 Scale 参数叠加,增益可独立调节。

1.3 filterAlpha 默认值提高

filterAlpha: 0.6 → 0.65

加速指数平滑的响应速度,使 UI 显示值更接近真实峰值。

1.4 UI 峰值保持机制

新增 uiPeakV / uiPeakH 变量,500ms 窗口内保持加速度峰值:

// 500ms 重置一次
if (currentTime - lastPeakResetTime > 500) {
    uiPeakV = abs(filteredZ); uiPeakH = abs(filteredX)
    lastPeakResetTime = currentTime
} else {
    uiPeakV = max(uiPeakV, abs(filteredZ))
    uiPeakH = max(uiPeakH, abs(filteredX))
}

仪表盘显示峰值而非瞬时值。


二、坐标库清理算法修复(MainActivity.kt: autoCleanupLibrary)

2.1 去重 Key 增加方向维度 + 放宽精度

修复前"%.6f,%.6f"(6位小数,无方向)

修复后

val key = String.format(Locale.US, "%s|%s|%.5f,%.5f",
    ref.lineName, ref.lineDirection, ref.latitude, ref.longitude)
  • 增加 lineNamelineDirection → 双向共用车站不误删
  • 6 位小数 → 5 位小数(约 1m) → 隧道航推坐标可正确去重

2.2 锚点优先保留策略

if (ref.isAnchor && !existing.isAnchor) {
    toDelete.add(existing.id)  // 锚点替换非锚点
    seenCoords[key] = ref
} else {
    toDelete.add(ref.id)       // 否则删除当前
}

同坐标点中锚点优先保留,非锚点重复删后到的。

2.3 上行方向单调性修复 + 反转遍历

修复前:不分方向,ORDER BY mileageValue ASC 遍历,上行 K0→K141 递增 → 反向数据全误删

修复后

val isUpbound = (direction == "上行")
var lastValidMileage = if (isUpbound) Double.MAX_VALUE else -1.0
val pointsToProcess = if (isUpbound) refs.reversed() else refs  // 反转遍历

上行反转后按 K141→K0(递减)遍历,检查逻辑变为"里程变大则为污染"。下行/单线逻辑不变(递增检查)。

2.4 增加无效坐标检查

val isInvalid = (point.latitude == 0.0) || ...

2.5 单线处理

单线走下行分支(isUpbound = false),里程递增检查通过即可。正反采集数据都能保留,去重由第一遍坐标去重兜底。


三、GPS 丢失-恢复校正(InspectorService.kt)

3.1 修复 GPS 恢复纠偏算法

修复前:用速度×时间推算里程差(恒速假设,加减速→误差累积)

val estimatedAtRestore = if (s.lineDirection == "上行")
    gpsLostStartMileage - (lastValidSpeed * 3.6f * dtHours)
else
    gpsLostStartMileage + (lastValidSpeed * 3.6f * dtHours)
updateSavedRecordsWithOffset(..., mVal - estimatedAtRestore, ...)

修复后:直接对比 GPS 恢复后的真实里程与最后一个航推值

val totalOffset = mVal - lastValidMileage
updateSavedRecordsWithOffset(..., totalOffset, ...)

3.2 新增加速度积分航推(UI 显示用)

新增 5 个变量:

变量 作用
gpsSpeedAtLoss GPS 丢失时的末次速度(m/s)
estimatedIntegralSpeed 积分推定速度(m/s)
filteredLongitudinalAcc 低通滤波后的纵向加速度(m/s²)
longitudinalAccAlpha 低通系数 0.12
lastAccelTimestamp 上次加速度时间戳

逻辑:GPS 丢失时在 onSensorChanged 中,用带符号的横向加速度 finalH × 9.81 经 α=0.12 滤波后积分更新速度:

filteredLongitudinalAcc = (1 - α) × filteredLongitudinalAcc + α × (finalH × 9.81)
estimatedIntegralSpeed += filteredLongitudinalAcc × dt

速度限制在 0120m/s(0432km/h)。

3.3 航推定时器使用积分速度

if (lastValidSpeed > 0.5f || (isGpsLost && estimatedIntegralSpeed > 0.5f)) {
    val currentSpeed = if (isGpsLost) estimatedIntegralSpeed.toDouble() else lastValidSpeed.toDouble()
    val displacementMeters = currentSpeed * (dtMillis / 1000.0)
    ...
}

GPS 丢失期间 UI 显示的里程基于积分速度而非恒速,能反映加减速趋势。

3.4 GPS 丢失时记录速度初值

if (!isGpsLost) {
    isGpsLost = true
    gpsLostStartTime = lastValidTime
    gpsLostStartMileage = lastValidMileage
    gpsSpeedAtLoss = lastValidSpeed          // 新增
    estimatedIntegralSpeed = lastValidSpeed  // 积分初值
    filteredLongitudinalAcc = 0f
    lastAccelTimestamp = System.currentTimeMillis()
}

3.5 匀加速模型重算隧道记录(核心改进)

GPS 恢复后使用匀加速模型替代线性时间分摊:

a = (v恢复 - v丢失) / Δt
m(t) = m_start + v0 × t + ½ × a × t²

两端严格对齐真实里程和速度。

if (dtTotal > 1.0) {
    val accel = (v1 - v0) / dtTotal
    recalculateLostRecords(sessionId, startTime, endTime, startMileage, v0, accel)
}

**极短中断(<1s)**走原线性校正回退路径。

3.6 recalculateLostRecords 函数

private suspend fun recalculateLostRecords(
    sessionId: Long, startTime: Long, endTime: Long,
    startMileage: Double, v0: Double, accel: Double
) {
    val records = database.detectionDao().getLostRecordsInRange(sessionId, startTime, endTime)
    records.forEach { record ->
        val dt = (record.timestamp - startTime) / 1000.0
        val correctedKm = startMileage + (v0 * dt / 1000.0) + (0.5 * accel * dt * dt / 1000.0)
        database.detectionDao().updateRecordMileage(record.id, correctedKm, formatMileage(correctedKm))
    }
}

四、数据库 DAO 新增(InspectorDatabase.kt)

4.1 更新单条记录里程

@Query("UPDATE detection_records SET mileageValue = :mileageVal, mileage = :mileageText WHERE id = :id")
suspend fun updateRecordMileage(id: Long, mileageVal: Double, mileageText: String)

4.2 查询丢失区间记录

@Query("SELECT * FROM detection_records WHERE sessionId = :sessionId " +
       "AND timestamp >= :startTime AND timestamp <= :endTime AND isEstimated = 1 " +
       "ORDER BY timestamp ASC")
suspend fun getLostRecordsInRange(sessionId: Long, startTime: Long, endTime: Long): List<DetectionRecord>

五、编译器警告修复

5.1 冗余限定符

java.util.ArrayDeque<Float>() → ArrayDeque<Float>()

5.2 一元运算符警告

行首的 + 被解析为一元正号而非二元加法,已移至上一行末尾:

filteredLongitudinalAcc = (1 - longitudinalAccAlpha) * filteredLongitudinalAcc +
    longitudinalAccAlpha * (finalH * 9.81f)

六、受影响的文件清单

文件 改动位置 改动量
InspectorService.kt 变量区、onSensorChanged、航推定时器、GPS恢复、新增函数 ~80 行
InspectorDatabase.kt DAO 接口末尾 2 个方法
MainActivity.kt autoCleanupLibrary、窗口/增益参数、峰值保持 ~50 行