This commit is contained in:
pythagodzilla 2026-03-19 19:41:47 +08:00
parent 07cb1304d2
commit d8ed237d46
15 changed files with 165 additions and 99 deletions

View File

@ -1,4 +1,8 @@
import core.TrajectorySimulator
import core.SimulatorConfig
import core.PhysicsConfig
import core.NoiseConfig
import core.OutputConfig
import resources.data.sampleRoute
/**
@ -22,37 +26,38 @@ fun main() {
// ════════════════════════════════════════════
// 第2步创建模拟器
// ════════════════════════════════════════════
val simulator = TrajectorySimulator(route)
// ════════════════════════════════════════════
// 第3步配置参数可选
// ════════════════════════════════════════════
simulator.setPhysicsParams(
totalDistance = 2000.0, // 5公里
duration = 600.0, //
maxVelocity = 4.0 // 4 m/s (14.4 km/h)
)
simulator.setNoiseParams(
gpsErrorStdDev = 0.00002, // GPS误差标准差
driftWeight = 0.1 // 漂移权重
val config = SimulatorConfig(
physics = PhysicsConfig(
totalDistance = 2000.0,
duration = 600.0,
maxVelocity = 4.0,
minVelocity = 1.8,
sampleStepSeconds = 1.0,
modelMaxAccelerationMps2 = 1.2,
seed = 42L
),
noise = NoiseConfig(
gpsErrorStdDev = 0.00002,
driftWeight = 0.1
),
output = OutputConfig(
duration = 600.0,
timeStep = 3.0
)
)
val simulator = TrajectorySimulator(route, config)
// ════════════════════════════════════════════
// 第4步模拟运动逐个时间步
// ════════════════════════════════════════════
val timeStep = 3.0
val duration = 600.0 // 总模拟时长10分钟
val timeStep = config.output.timeStep
val duration = config.output.duration // 总模拟时长10分钟
println("时间(秒)\t距离(米)\t速度(m/s)\t加速度(m/s²)\t纬度\t\t经度\t\tGPS误差(m)")
println("".repeat(100))
var time = 0.0
while (time <= duration) {
// 调用模拟器的核心方法执行完整的4步数据流
val motionState = simulator.simulate(time)
// 输出结果
val routeStates = simulator.routeOut(duration = duration, timeStep = timeStep)
routeStates.forEach { motionState ->
println(
"%.1f\t%.1f\t%.3f\t%.3f\t%.6f\t%.6f\t%.6f".format(
motionState.time,
@ -64,8 +69,6 @@ fun main() {
motionState.gpsError
)
)
time += timeStep
}
println("\n模拟完成!")

View File

@ -22,19 +22,26 @@ import model.PhysicsState
class RunnerPhysics(
private val totalDistance: Double = 0.0, // 总路线距离(米)
private val duration: Double = 1000.0, // 总运动时间(秒)
private val maxVelocity: Double = 4.0 // 最大速度m/s
private val maxVelocity: Double = 4.0, // 最大速度m/s
private val minVelocity: Double = (maxVelocity * 0.45).coerceAtLeast(0.5), // 最小速度m/s
private val sampleStepSeconds: Double = 1.0, // 速度时间线采样间隔(秒)
private val modelMaxAccelerationMps2: Double = 1.2, // 模型内最大加速度m/s²
private val seed: Long? = null // 随机种子(可选)
) {
private val derivativeStepSeconds = 1.0
private val derivativeStepSeconds = sampleStepSeconds
// 接入人类风格距离引擎(仅用于 time -> distance
private val distanceEngine: HumanLikeDistanceEngine? =
if (totalDistance > 0.0 && duration > 0.0 && maxVelocity > 0.0) {
if (totalDistance > 0.0 && duration > 0.0 && maxVelocity > 0.0 && minVelocity > 0.0) {
HumanLikeDistanceEngine(
HumanLikeDistanceConfig(
totalDistanceMeters = totalDistance,
totalDurationSeconds = duration,
minSpeedMps = (maxVelocity * 0.45).coerceAtLeast(0.5),
maxSpeedMps = maxVelocity
minSpeedMps = minVelocity.coerceAtMost(maxVelocity - 1e-6),
maxSpeedMps = maxVelocity,
sampleStepSeconds = sampleStepSeconds,
maxAccelerationMps2 = modelMaxAccelerationMps2,
seed = seed
)
)
} else {

View File

@ -5,6 +5,32 @@ import model.MetaCoordinate
import model.MotionState
import noise.NoiseProcessor
data class PhysicsConfig(
val totalDistance: Double = 2000.0,
val duration: Double = 600.0,
val maxVelocity: Double = 4.0,
val minVelocity: Double = (maxVelocity * 0.45).coerceAtLeast(0.5),
val sampleStepSeconds: Double = 1.0,
val modelMaxAccelerationMps2: Double = 1.2,
val seed: Long? = null
)
data class NoiseConfig(
val gpsErrorStdDev: Double = 0.00002,
val driftWeight: Double = 0.3
)
data class OutputConfig(
val duration: Double = 600.0,
val timeStep: Double = 3.0
)
data class SimulatorConfig(
val physics: PhysicsConfig = PhysicsConfig(),
val noise: NoiseConfig = NoiseConfig(),
val output: OutputConfig = OutputConfig()
)
/**
* 轨迹模拟器 - 核心协调器管理整个数据流
*
@ -41,12 +67,35 @@ import noise.NoiseProcessor
*
*
*/
class TrajectorySimulator(route: List<MetaCoordinate>) {
class TrajectorySimulator(
route: List<MetaCoordinate>,
initialConfig: SimulatorConfig = SimulatorConfig()
) {
private var simulatorConfig: SimulatorConfig = initialConfig
// 核心引擎(一次性创建,重复使用)
private val pathInterpolator: PathInterpolator = PathInterpolator(route)
private val physicsEngine: RunnerPhysics = RunnerPhysics()
private val noiseProcessor: NoiseProcessor = NoiseProcessor()
private var physicsEngine: RunnerPhysics = createPhysicsEngine()
private var noiseProcessor: NoiseProcessor = createNoiseProcessor()
private fun createPhysicsEngine(): RunnerPhysics {
return RunnerPhysics(
totalDistance = simulatorConfig.physics.totalDistance,
duration = simulatorConfig.physics.duration,
maxVelocity = simulatorConfig.physics.maxVelocity,
minVelocity = simulatorConfig.physics.minVelocity,
sampleStepSeconds = simulatorConfig.physics.sampleStepSeconds,
modelMaxAccelerationMps2 = simulatorConfig.physics.modelMaxAccelerationMps2,
seed = simulatorConfig.physics.seed
)
}
private fun createNoiseProcessor(): NoiseProcessor {
return NoiseProcessor(
gpsErrorStdDev = simulatorConfig.noise.gpsErrorStdDev,
driftWeight = simulatorConfig.noise.driftWeight
)
}
/**
* 模拟特定时刻的运动状态
@ -98,6 +147,25 @@ class TrajectorySimulator(route: List<MetaCoordinate>) {
)
}
fun routeOut(
duration: Double = simulatorConfig.output.duration,
timeStep: Double = simulatorConfig.output.timeStep
): List<MotionState> {
val output = mutableListOf<MotionState>()
var time = 0.0
while (time <= duration) {
output.add(simulate(time))
time += timeStep
}
return output
}
fun setConfig(config: SimulatorConfig) {
simulatorConfig = config
physicsEngine = createPhysicsEngine()
noiseProcessor = createNoiseProcessor()
}
/**
* 设置物理引擎参数
*
@ -112,8 +180,32 @@ class TrajectorySimulator(route: List<MetaCoordinate>) {
duration: Double,
maxVelocity: Double
) {
// TODO: 实现参数设置逻辑
// 可考虑重新初始化物理引擎
simulatorConfig = simulatorConfig.copy(
physics = simulatorConfig.physics.copy(
totalDistance = totalDistance,
duration = duration,
maxVelocity = maxVelocity,
minVelocity = (maxVelocity * 0.45).coerceAtLeast(0.5)
)
)
physicsEngine = createPhysicsEngine()
}
fun setPhysicsModelParams(
minVelocity: Double,
sampleStepSeconds: Double = 1.0,
modelMaxAccelerationMps2: Double = 1.2,
seed: Long? = null
) {
simulatorConfig = simulatorConfig.copy(
physics = simulatorConfig.physics.copy(
minVelocity = minVelocity,
sampleStepSeconds = sampleStepSeconds,
modelMaxAccelerationMps2 = modelMaxAccelerationMps2,
seed = seed
)
)
physicsEngine = createPhysicsEngine()
}
/**
@ -128,7 +220,12 @@ class TrajectorySimulator(route: List<MetaCoordinate>) {
gpsErrorStdDev: Double,
driftWeight: Double
) {
// TODO: 实现参数设置逻辑
// 可考虑动态调整噪声引擎参数
simulatorConfig = simulatorConfig.copy(
noise = simulatorConfig.noise.copy(
gpsErrorStdDev = gpsErrorStdDev,
driftWeight = driftWeight
)
)
noiseProcessor = createNoiseProcessor()
}
}

View File

@ -40,8 +40,14 @@ interface NoiseEngine {
*
* NoisyCoordinate (添加了噪声)
*/
class NoiseProcessor {
private val gpsNoiseEngine = GpsNoiseEngine()
class NoiseProcessor(
gpsErrorStdDev: Double = 0.00002,
driftWeight: Double = 0.3
) {
private val gpsNoiseEngine = GpsNoiseEngine(
gpsErrorStdDev = gpsErrorStdDev,
driftWeight = driftWeight
)
// 预留其他噪声引擎
// private val velocityNoiseEngine = VelocityNoiseEngine()
// private val accelerationNoiseEngine = AccelerationNoiseEngine()

File diff suppressed because one or more lines are too long