Refactor WebSocketMessageBroadcaster to enhance position filtering logic and introduce adaptive speed thresholds for improved accuracy。优化平滑速度策略

This commit is contained in:
sladro 2026-02-08 17:56:21 +08:00
parent bbc3a6f5d6
commit aae4877622

View File

@ -44,6 +44,7 @@ public class WebSocketMessageBroadcaster {
private static final int REACQUIRE_AFTER_REJECTS = 3;
private static final double EARTH_RADIUS_METERS = 6371000.0;
private static final double MIN_DT_SECONDS = 0.05;
private final MessageCacheService messageCacheService;
private final CollisionWebSocketHandler collisionWebSocketHandler;
@ -53,13 +54,13 @@ public class WebSocketMessageBroadcaster {
private final Map<String, PositionTrackState> positionTrackStates = new ConcurrentHashMap<>();
private final AtomicBoolean positionFlushInProgress = new AtomicBoolean(false);
@Value("${websocket.position.filter.ema-alpha:0.45}")
@Value("${websocket.position.filter.ema-alpha:0.6}")
private double positionEmaAlpha;
@Value("${websocket.position.filter.jitter-meter:2.5}")
@Value("${websocket.position.filter.jitter-meter:1.0}")
private double jitterMeterThreshold;
@Value("${websocket.position.filter.max-speed-mps-aircraft:150.0}")
@Value("${websocket.position.filter.max-speed-mps-aircraft:120.0}")
private double maxSpeedMpsAircraft;
@Value("${websocket.position.filter.max-speed-mps-vehicle:35.0}")
@ -68,9 +69,51 @@ public class WebSocketMessageBroadcaster {
@Value("${websocket.position.filter.max-speed-mps-unmanned:15.0}")
private double maxSpeedMpsUnmanned;
@Value("${websocket.position.filter.max-jump-margin-meter:20.0}")
@Value("${websocket.position.filter.max-jump-margin-meter:15.0}")
private double maxJumpMarginMeter;
@Value("${websocket.position.filter.speed-slow-threshold-mps:8.0}")
private double speedSlowThresholdMps;
@Value("${websocket.position.filter.speed-fast-threshold-mps:35.0}")
private double speedFastThresholdMps;
@Value("${websocket.position.filter.slow.jitter-meter:0.8}")
private double slowJitterMeter;
@Value("${websocket.position.filter.slow.ema-alpha:0.75}")
private double slowEmaAlpha;
@Value("${websocket.position.filter.slow.max-speed-mps:25.0}")
private double slowMaxSpeedMps;
@Value("${websocket.position.filter.slow.jump-margin-meter:8.0}")
private double slowJumpMarginMeter;
@Value("${websocket.position.filter.fast.jitter-meter:2.0}")
private double fastJitterMeter;
@Value("${websocket.position.filter.fast.ema-alpha:0.5}")
private double fastEmaAlpha;
@Value("${websocket.position.filter.fast.max-speed-mps:70.0}")
private double fastMaxSpeedMps;
@Value("${websocket.position.filter.fast.jump-margin-meter:15.0}")
private double fastJumpMarginMeter;
@Value("${websocket.position.filter.airborne.jitter-meter:5.0}")
private double airborneJitterMeter;
@Value("${websocket.position.filter.airborne.ema-alpha:0.35}")
private double airborneEmaAlpha;
@Value("${websocket.position.filter.airborne.max-speed-mps:120.0}")
private double airborneMaxSpeedMps;
@Value("${websocket.position.filter.airborne.jump-margin-meter:25.0}")
private double airborneJumpMarginMeter;
@Value("${websocket.position.filter.state-ttl-ms:120000}")
private long positionTrackStateTtlMs;
@ -87,6 +130,20 @@ public class WebSocketMessageBroadcaster {
private int rejectedCount;
}
private enum MotionProfile {
SLOW_TAXI,
FAST_ROLL,
AIRBORNE
}
private record AdaptiveFilterParams(
double jitterMeter,
double emaAlpha,
double maxSpeedMps,
double jumpMarginMeter,
MotionProfile profile
) {}
public WebSocketMessageBroadcaster(
MessageCacheService messageCacheService,
CollisionWebSocketHandler collisionWebSocketHandler,
@ -356,8 +413,10 @@ public class WebSocketMessageBroadcaster {
latitude,
longitude
);
double rawSpeedMps = rawDistance / Math.max(dtSec, MIN_DT_SECONDS);
AdaptiveFilterParams adaptive = resolveAdaptiveFilterParams(payload.getObjectType(), rawSpeedMps);
double maxAllowedJump = resolveMaxAllowedJumpMeters(payload.getObjectType(), dtSec);
double maxAllowedJump = resolveMaxAllowedJumpMeters(adaptive.maxSpeedMps(), adaptive.jumpMarginMeter(), dtSec);
boolean isOutlierJump = rawDistance > maxAllowedJump;
if (isOutlierJump && state.rejectedCount < REACQUIRE_AFTER_REJECTS - 1) {
state.rejectedCount++;
@ -372,11 +431,11 @@ public class WebSocketMessageBroadcaster {
filteredLongitude = longitude;
} else {
state.rejectedCount = 0;
if (rawDistance <= jitterMeterThreshold) {
if (rawDistance <= adaptive.jitterMeter()) {
filteredLatitude = state.lastFilteredLatitude;
filteredLongitude = state.lastFilteredLongitude;
} else {
double alpha = clamp(positionEmaAlpha, 0.05, 1.0);
double alpha = clamp(adaptive.emaAlpha(), 0.05, 1.0);
filteredLatitude = state.lastFilteredLatitude + alpha * (latitude - state.lastFilteredLatitude);
filteredLongitude = state.lastFilteredLongitude + alpha * (longitude - state.lastFilteredLongitude);
}
@ -421,10 +480,49 @@ public class WebSocketMessageBroadcaster {
return latitude >= -90.0 && latitude <= 90.0 && longitude >= -180.0 && longitude <= 180.0;
}
private double resolveMaxAllowedJumpMeters(String objectType, double dtSec) {
double safeDtSec = Math.max(dtSec, 0.05);
double speedMps = resolveMaxSpeedMps(objectType);
return speedMps * safeDtSec + Math.max(maxJumpMarginMeter, 0.0);
private double resolveMaxAllowedJumpMeters(double speedMps, double jumpMarginMeter, double dtSec) {
double safeDtSec = Math.max(dtSec, MIN_DT_SECONDS);
return speedMps * safeDtSec + Math.max(jumpMarginMeter, 0.0);
}
private AdaptiveFilterParams resolveAdaptiveFilterParams(String objectType, double rawSpeedMps) {
if (!"AIRCRAFT".equals(objectType)) {
return new AdaptiveFilterParams(
jitterMeterThreshold,
positionEmaAlpha,
resolveMaxSpeedMps(objectType),
maxJumpMarginMeter,
MotionProfile.FAST_ROLL
);
}
if (rawSpeedMps < speedSlowThresholdMps) {
return new AdaptiveFilterParams(
slowJitterMeter,
slowEmaAlpha,
slowMaxSpeedMps,
slowJumpMarginMeter,
MotionProfile.SLOW_TAXI
);
}
if (rawSpeedMps < speedFastThresholdMps) {
return new AdaptiveFilterParams(
fastJitterMeter,
fastEmaAlpha,
fastMaxSpeedMps,
fastJumpMarginMeter,
MotionProfile.FAST_ROLL
);
}
return new AdaptiveFilterParams(
airborneJitterMeter,
airborneEmaAlpha,
airborneMaxSpeedMps,
airborneJumpMarginMeter,
MotionProfile.AIRBORNE
);
}
private double resolveMaxSpeedMps(String objectType) {