继续修复平滑
This commit is contained in:
parent
900ccdbb02
commit
7bb910892a
@ -18,7 +18,7 @@
|
||||
(4)Z31020**&d1231=+33
|
||||
4.测试平台-- 10.100.23.10
|
||||
(1)root
|
||||
(2)Dianxin@222
|
||||
Dianxin@222
|
||||
5.红绿灯测试平台-- 10.98.23.111 windows系统
|
||||
(1)账密
|
||||
①administrator
|
||||
|
||||
@ -26,6 +26,11 @@ public class Aircraft extends MovingObject {
|
||||
*/
|
||||
private String flightNumber;
|
||||
|
||||
/**
|
||||
* Upstream track identifier for source-track partitioning.
|
||||
*/
|
||||
private String trackNumber;
|
||||
|
||||
/**
|
||||
* 进港跑道编号
|
||||
*/
|
||||
|
||||
@ -115,6 +115,7 @@ public class DataCollectorDao {
|
||||
Aircraft aircraft = new Aircraft();
|
||||
aircraft.setObjectId(rawData.getFlightNo());
|
||||
aircraft.setObjectName(rawData.getFlightNo()); // 使用 flightNo 作为 objectName
|
||||
aircraft.setTrackNumber(rawData.getTrackNumber());
|
||||
aircraft.setCurrentPosition(geometryFactory.createPoint(new org.locationtech.jts.geom.Coordinate(rawData.getLongitude(), rawData.getLatitude())));
|
||||
// 外部API中没有直接的速度和方向,如果需要,可以在DataCollectorService中计算或使用默认值
|
||||
// 暂时设置为0.0,DataCollectorService会处理
|
||||
@ -207,6 +208,8 @@ public class DataCollectorDao {
|
||||
private static class ExternalAircraftData {
|
||||
@JsonProperty("flightNo")
|
||||
private String flightNo;
|
||||
@JsonProperty("trackNumber")
|
||||
private String trackNumber;
|
||||
@JsonProperty("longitude")
|
||||
private Double longitude;
|
||||
@JsonProperty("latitude")
|
||||
|
||||
@ -130,6 +130,7 @@ public class DataCollectorService {
|
||||
|
||||
// 用于缓存所有活跃的MovingObject的最新状态
|
||||
private final Map<String, MovingObject> activeMovingObjectsCache = new ConcurrentHashMap<>();
|
||||
private final Map<String, String> selectedTrackByFlightNo = new ConcurrentHashMap<>();
|
||||
|
||||
// 记录每个对象最近一次更新的时间戳,用于淘汰不活跃对象(防止内存长期增长)
|
||||
private final Map<String, Long> activeMovingObjectsLastUpdatedAtMs = new ConcurrentHashMap<>();
|
||||
@ -430,19 +431,30 @@ public class DataCollectorService {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Map<String, Aircraft> latestByFlightNo = new HashMap<>();
|
||||
Map<String, Map<String, Aircraft>> latestByFlightAndTrack = new HashMap<>();
|
||||
for (Aircraft aircraft : aircrafts) {
|
||||
if (aircraft == null || aircraft.getObjectId() == null || aircraft.getObjectId().isBlank()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Aircraft existing = latestByFlightNo.get(aircraft.getObjectId());
|
||||
String flightNo = aircraft.getObjectId();
|
||||
String trackKey = normalizeTrackKey(aircraft.getTrackNumber());
|
||||
Map<String, Aircraft> byTrack = latestByFlightAndTrack.computeIfAbsent(flightNo, k -> new HashMap<>());
|
||||
|
||||
Aircraft existing = byTrack.get(trackKey);
|
||||
if (existing == null || isCandidateNewer(existing, aircraft)) {
|
||||
latestByFlightNo.put(aircraft.getObjectId(), aircraft);
|
||||
byTrack.put(trackKey, aircraft);
|
||||
}
|
||||
}
|
||||
|
||||
return List.copyOf(latestByFlightNo.values());
|
||||
List<Aircraft> selected = new java.util.ArrayList<>(latestByFlightAndTrack.size());
|
||||
for (Map.Entry<String, Map<String, Aircraft>> entry : latestByFlightAndTrack.entrySet()) {
|
||||
Aircraft selectedAircraft = selectAircraftTrackCandidate(entry.getKey(), entry.getValue());
|
||||
if (selectedAircraft != null) {
|
||||
selected.add(selectedAircraft);
|
||||
}
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
private boolean isCandidateNewer(Aircraft existing, Aircraft candidate) {
|
||||
@ -461,6 +473,72 @@ public class DataCollectorService {
|
||||
return candidateTs >= existingTs;
|
||||
}
|
||||
|
||||
private Aircraft selectAircraftTrackCandidate(String flightNo, Map<String, Aircraft> byTrack) {
|
||||
if (byTrack == null || byTrack.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (byTrack.size() == 1) {
|
||||
Aircraft only = byTrack.values().iterator().next();
|
||||
selectedTrackByFlightNo.put(flightNo, normalizeTrackKey(only.getTrackNumber()));
|
||||
return only;
|
||||
}
|
||||
|
||||
String selectedTrack = selectedTrackByFlightNo.get(flightNo);
|
||||
if (selectedTrack != null && byTrack.containsKey(selectedTrack)) {
|
||||
return byTrack.get(selectedTrack);
|
||||
}
|
||||
|
||||
MovingObject previous = activeMovingObjectsCache.get(flightNo);
|
||||
Aircraft best = null;
|
||||
double bestDistance = Double.MAX_VALUE;
|
||||
if (previous != null && previous.getCurrentPosition() != null) {
|
||||
for (Aircraft candidate : byTrack.values()) {
|
||||
if (candidate == null || candidate.getCurrentPosition() == null) {
|
||||
continue;
|
||||
}
|
||||
double d = calculateDistanceMeters(previous.getCurrentPosition(), candidate.getCurrentPosition());
|
||||
if (d < bestDistance) {
|
||||
best = candidate;
|
||||
bestDistance = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best == null) {
|
||||
for (Aircraft candidate : byTrack.values()) {
|
||||
if (best == null || isCandidateNewer(best, candidate)) {
|
||||
best = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best != null) {
|
||||
selectedTrackByFlightNo.put(flightNo, normalizeTrackKey(best.getTrackNumber()));
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
private String normalizeTrackKey(String trackNumber) {
|
||||
if (trackNumber == null || trackNumber.isBlank()) {
|
||||
return "_DEFAULT_TRACK_";
|
||||
}
|
||||
return trackNumber.trim();
|
||||
}
|
||||
|
||||
private double calculateDistanceMeters(Point from, Point to) {
|
||||
double lat1 = Math.toRadians(from.getY());
|
||||
double lon1 = Math.toRadians(from.getX());
|
||||
double lat2 = Math.toRadians(to.getY());
|
||||
double lon2 = Math.toRadians(to.getX());
|
||||
|
||||
double dLat = lat2 - lat1;
|
||||
double dLon = lon2 - lon1;
|
||||
double a = Math.sin(dLat / 2.0) * Math.sin(dLat / 2.0)
|
||||
+ Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2.0) * Math.sin(dLon / 2.0);
|
||||
double c = 2.0 * Math.atan2(Math.sqrt(a), Math.sqrt(1.0 - a));
|
||||
return 6371000.0 * c;
|
||||
}
|
||||
|
||||
@Scheduled(fixedRateString = "${data.collector.interval}")
|
||||
public void collectAircraftData() {
|
||||
if (collectorDisabled) {
|
||||
@ -1274,6 +1352,7 @@ public class DataCollectorService {
|
||||
Long last = entry.getValue();
|
||||
if (last == null || last < cutoff) {
|
||||
activeMovingObjectsCache.remove(entry.getKey());
|
||||
selectedTrackByFlightNo.remove(entry.getKey());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -42,6 +42,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@Component
|
||||
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;
|
||||
|
||||
@ -116,9 +117,6 @@ public class WebSocketMessageBroadcaster {
|
||||
@Value("${websocket.position.filter.state-ttl-ms:120000}")
|
||||
private long positionTrackStateTtlMs;
|
||||
|
||||
@Value("${websocket.position.filter.reacquire-gap-ms:8000}")
|
||||
private long reacquireGapMs;
|
||||
|
||||
private record CoalescedPositionUpdate(PositionUpdatePayload payload, long timestamp) {}
|
||||
|
||||
private static final class PositionTrackState {
|
||||
@ -393,7 +391,7 @@ public class WebSocketMessageBroadcaster {
|
||||
}
|
||||
|
||||
long payloadTimestamp = payload.getTimestamp() != null ? payload.getTimestamp() : System.currentTimeMillis();
|
||||
long filterTimestampMs = System.currentTimeMillis();
|
||||
long filterTimestampMs = payloadTimestamp;
|
||||
PositionTrackState state = positionTrackStates.computeIfAbsent(payload.getObjectId(), k -> new PositionTrackState());
|
||||
|
||||
double filteredLatitude = latitude;
|
||||
@ -404,8 +402,11 @@ public class WebSocketMessageBroadcaster {
|
||||
initializeTrackState(state, latitude, longitude, filterTimestampMs);
|
||||
} else {
|
||||
if (filterTimestampMs <= state.lastPayloadTimestampMs) {
|
||||
state.rejectedCount++;
|
||||
return null;
|
||||
// Use local monotonic time to avoid dropping legitimate points on equal/out-of-order source timestamps.
|
||||
filterTimestampMs = System.currentTimeMillis();
|
||||
if (filterTimestampMs <= state.lastPayloadTimestampMs) {
|
||||
filterTimestampMs = state.lastPayloadTimestampMs + 1;
|
||||
}
|
||||
}
|
||||
|
||||
long dtMs = filterTimestampMs - state.lastPayloadTimestampMs;
|
||||
@ -418,32 +419,33 @@ public class WebSocketMessageBroadcaster {
|
||||
);
|
||||
double rawSpeedMps = rawDistance / Math.max(dtSec, MIN_DT_SECONDS);
|
||||
AdaptiveFilterParams adaptive = resolveAdaptiveFilterParams(payload.getObjectType(), rawSpeedMps);
|
||||
boolean aircraft = isAircraftType(payload.getObjectType());
|
||||
|
||||
double maxAllowedJump = resolveMaxAllowedJumpMeters(adaptive.maxSpeedMps(), adaptive.jumpMarginMeter(), dtSec);
|
||||
boolean isOutlierJump = rawDistance > maxAllowedJump;
|
||||
if (isOutlierJump && !aircraft && state.rejectedCount < REACQUIRE_AFTER_REJECTS - 1) {
|
||||
state.rejectedCount++;
|
||||
log.debug("Drop outlier position update: objectId={}, jumpMeter={}, allowedMeter={}",
|
||||
payload.getObjectId(), rawDistance, maxAllowedJump);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isOutlierJump) {
|
||||
boolean longGapReacquire = dtMs >= Math.max(reacquireGapMs, 0L);
|
||||
if (longGapReacquire) {
|
||||
state.rejectedCount = 0;
|
||||
filteredLatitude = latitude;
|
||||
filteredLongitude = longitude;
|
||||
} else {
|
||||
state.rejectedCount++;
|
||||
double[] clipped = clipPointByMaxDistance(
|
||||
state.lastFilteredLatitude,
|
||||
state.lastFilteredLongitude,
|
||||
latitude,
|
||||
longitude,
|
||||
maxAllowedJump
|
||||
);
|
||||
filteredLatitude = clipped[0];
|
||||
filteredLongitude = clipped[1];
|
||||
log.debug("Clip outlier position update: objectId={}, jumpMeter={}, allowedMeter={}, dtMs={}",
|
||||
payload.getObjectId(), rawDistance, maxAllowedJump, dtMs);
|
||||
state.rejectedCount = 0;
|
||||
if (aircraft) {
|
||||
if (rawDistance <= adaptive.jitterMeter()) {
|
||||
filteredLatitude = state.lastFilteredLatitude;
|
||||
filteredLongitude = state.lastFilteredLongitude;
|
||||
} else {
|
||||
double alpha = resolveAircraftDynamicAlpha(adaptive.emaAlpha(), rawDistance, maxAllowedJump);
|
||||
filteredLatitude = state.lastFilteredLatitude + alpha * (latitude - state.lastFilteredLatitude);
|
||||
filteredLongitude = state.lastFilteredLongitude + alpha * (longitude - state.lastFilteredLongitude);
|
||||
}
|
||||
} else {
|
||||
state.rejectedCount = 0;
|
||||
if (rawDistance <= adaptive.jitterMeter()) {
|
||||
filteredLatitude = state.lastFilteredLatitude;
|
||||
filteredLongitude = state.lastFilteredLongitude;
|
||||
@ -453,6 +455,13 @@ public class WebSocketMessageBroadcaster {
|
||||
filteredLongitude = state.lastFilteredLongitude + alpha * (longitude - state.lastFilteredLongitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isOutlierJump && aircraft) {
|
||||
// Aircraft points should not be dropped to avoid visual path gaps.
|
||||
filteredLatitude = latitude;
|
||||
filteredLongitude = longitude;
|
||||
}
|
||||
|
||||
state.lastRawLatitude = latitude;
|
||||
state.lastRawLongitude = longitude;
|
||||
@ -478,6 +487,18 @@ public class WebSocketMessageBroadcaster {
|
||||
.build();
|
||||
}
|
||||
|
||||
private boolean isAircraftType(String objectType) {
|
||||
return "AIRCRAFT".equals(objectType);
|
||||
}
|
||||
|
||||
private double resolveAircraftDynamicAlpha(double baseAlpha, double rawDistance, double maxAllowedJump) {
|
||||
double normalized = maxAllowedJump <= 0.0 ? 1.0 : clamp(rawDistance / maxAllowedJump, 0.0, 1.0);
|
||||
// Keep smoothness at low speed, but reduce lag quickly when displacement grows.
|
||||
double minAlpha = Math.max(0.35, baseAlpha);
|
||||
double maxAlpha = 0.92;
|
||||
return clamp(minAlpha + (maxAlpha - minAlpha) * normalized, 0.05, 1.0);
|
||||
}
|
||||
|
||||
private void initializeTrackState(PositionTrackState state, double latitude, double longitude, long payloadTimestamp) {
|
||||
state.initialized = true;
|
||||
state.lastPayloadTimestampMs = payloadTimestamp;
|
||||
@ -569,21 +590,4 @@ public class WebSocketMessageBroadcaster {
|
||||
}
|
||||
return Math.min(value, max);
|
||||
}
|
||||
|
||||
private double[] clipPointByMaxDistance(
|
||||
double startLatitude,
|
||||
double startLongitude,
|
||||
double targetLatitude,
|
||||
double targetLongitude,
|
||||
double maxDistanceMeters) {
|
||||
double distanceMeters = calculateDistanceMeters(startLatitude, startLongitude, targetLatitude, targetLongitude);
|
||||
if (distanceMeters <= maxDistanceMeters || distanceMeters <= 0.0 || maxDistanceMeters <= 0.0) {
|
||||
return new double[] {targetLatitude, targetLongitude};
|
||||
}
|
||||
|
||||
double ratio = maxDistanceMeters / distanceMeters;
|
||||
double clippedLatitude = startLatitude + (targetLatitude - startLatitude) * ratio;
|
||||
double clippedLongitude = startLongitude + (targetLongitude - startLongitude) * ratio;
|
||||
return new double[] {clippedLatitude, clippedLongitude};
|
||||
}
|
||||
}
|
||||
|
||||
49
命令.md
49
命令.md
@ -134,8 +134,6 @@ docker exec -it qaup-app sh -lc 'sha256sum /app.jar'
|
||||
docker exec -it qaup-app rm /app.jar
|
||||
docker cp qaup-app.jar qaup-app:/app.jar
|
||||
docker restart qaup-app
|
||||
curl -s http://10.64.58.228:8086/api/adxp/status
|
||||
curl -s http://10.64.58.228:8086/api/adxp/health
|
||||
curl -s -X POST http://10.64.58.228:8086/api/adxp/reconnect
|
||||
docker logs -f qaup-app | grep "路由"
|
||||
```
|
||||
@ -305,3 +303,50 @@ for F in MU9692; do
|
||||
fi
|
||||
echo "$F | biz=$BIZ | flight=[$FR] | biz=[$BR]"
|
||||
done
|
||||
|
||||
|
||||
grep -oE 'TISFLIGHT' ./adxp-adapter/logs/adapter-logs.log | sort | uniq -c | sort -nr
|
||||
|
||||
|
||||
```
|
||||
TOKEN=$(echo "$LOGIN_RESP" | sed -n 's/.*"data":"\([^"]*\)".*/\1/p')
|
||||
# B. 连续观察 QDA9846(无 jq 版本)
|
||||
for i in $(seq 1 20); do
|
||||
TS=$(date '+%H:%M:%S')
|
||||
RESP=$(curl -sS -H "Authorization: $TOKEN" "http://10.32.38.3:8090/openApi/getCurrentFlightPositions")
|
||||
LINE=$(echo "$RESP" | tr '{' '\n' | grep '"flightNo":"FGCX253"' | head -n1)
|
||||
if [ -z "$LINE" ]; then
|
||||
echo "[$TS] NO_HIT"
|
||||
else
|
||||
echo "[$TS] $LINE"
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
root@root:/home/project_20250804/qaup# for i in $(seq 1 20); do TS=$(date '+%H:%M:%S'); RESP=$(curl -sS -H "Authorization: $TOKEN" "http://10.32.38.3:8090/openApi/getCurrentFlightPositions"); LINE=$(echo "$RESP" | tr '{' '\n' | grep '"flightNo":"FGCX253"' | head -n1); if [ -z "$LINE" ]; then echo "[$TS] NO_HIT"; else echo "[$TS] $LINE"; fi; sleep 1; done
|
||||
[05:59:44] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35046,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:45] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35046,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:46] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35046,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:47] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35044,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:48] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35044,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:49] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35044,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:51] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35044,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:52] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35044,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:53] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35044,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:54] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35044,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:55] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35045,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:56] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35045,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:57] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35045,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:58] "flightNo":"FGCX253","longitude":120.09361,"latitude":36.35045,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[05:59:59] "flightNo":"FGCX253","longitude":120.09372,"latitude":36.35048,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[06:00:00] "flightNo":"FGCX253","longitude":120.09372,"latitude":36.35048,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[06:00:01] "flightNo":"FGCX253","longitude":120.09372,"latitude":36.35048,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[06:00:02] "flightNo":"FGCX253","longitude":120.09396,"latitude":36.35043,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[06:00:03] "flightNo":"FGCX253","longitude":120.094,"latitude":36.35036,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
[06:00:04] "flightNo":"FGCX253","longitude":120.09401,"latitude":36.3503,"time":1770760653475,"altitude":0.0,"trackNumber":0},
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user