现如今航迹预测的最优解当然是使用AI来做
但在不需要太准确的并且不考虑使用人工智能来做的情况下该如何实现航迹的预测呢?
-
思路
- 需求是通过已有的多条历史航迹计算一条预测的航迹点
- 预测的航迹起点使用历史航迹的所有起点取中间值,终点同理
- 中间点也采用取中间点的方式来实现
- 对于航迹点数不同的历史航迹需要做插值补全和删点简化
- 对于历史航迹中偏差较大的航迹,该条航迹的点位不加入预测航迹的计算中
这是一种比较简单的能够实现航迹预测功能的思路,代码如下:
package com.jq.coursesimplify;
import java.util.ArrayList;
import java.util.List;
/**
* 航迹预测类
* @作者: YYD
*/
public class TrajectoryPrediction {
/**
* 航迹点信息
*/
public static class TargetPoint{
/** 经度 */
private final double lng;
/** 维度 */
private final double lat;
/** 航迹点时间 */
private final long tim;
public TargetPoint(double lng, double lat, long tim) {
this.lng = lng;
this.lat = lat;
this.tim = tim;
}
public double getLng() {
return lng;
}
public double getLat() {
return lat;
}
public long getTim() {
return tim;
}
}
// 计算两个点之间的欧几里得距离
private static double calculateDistance(TargetPoint p1, TargetPoint p2) {
double dLng = p1.getLng() - p2.getLng();
double dLat = p1.getLat() - p2.getLat();
return Math.sqrt(dLng * dLng + dLat * dLat);
}
// 计算每条航线的总偏差距离
private static double calculateTotalDeviation(List<TargetPoint> trajectory, List<List<TargetPoint>> trajectories) {
double totalDeviation = 0.0;
for (List<TargetPoint> otherTrajectory : trajectories) {
if (trajectory != otherTrajectory) {
totalDeviation += calculateTrajectoryDistance(trajectory, otherTrajectory);
}
}
return totalDeviation;
}
// 计算两条航线之间的距离
private static double calculateTrajectoryDistance(List<TargetPoint> t1, List<TargetPoint> t2) {
double distance = 0.0;
int minLength = Math.min(t1.size(), t2.size());
for (int i = 0; i < minLength; i++) {
distance += calculateDistance(t1.get(i), t2.get(i));
}
return distance;
}
// 过滤掉偏差较大的航线
private static List<List<TargetPoint>> filterOutliers(List<List<TargetPoint>> trajectories, double threshold) {
List<List<TargetPoint>> filteredTrajectories = new ArrayList<>();
List<Double> deviations = new ArrayList<>();
// 计算每条航线的总偏差距离
for (List<TargetPoint> trajectory : trajectories) {
double totalDeviation = calculateTotalDeviation(trajectory, trajectories);
deviations.add(totalDeviation);
}
// 计算偏差距离的平均值
double averageDeviation = deviations.stream().mapToDouble(d -> d).average().orElse(0.0);
// 过滤掉偏差较大的航线
for (int i = 0; i < trajectories.size(); i++) {
if (deviations.get(i) <= averageDeviation * threshold) {
filteredTrajectories.add(trajectories.get(i));
}
}
return filteredTrajectories;
}
// 计算多个点的经度和纬度的平均值
private static TargetPoint calculateMidpoint(List<TargetPoint> points) {
double totalLng = 0.0;
double totalLat = 0.0;
long totalTim = 0; // 时间的平均值可根据需要调整计算方法
for (TargetPoint point : points) {
totalLng += point.getLng();
totalLat += point.getLat();
totalTim += point.getTim();
}
int count = points.size();
double avgLng = totalLng / count;
double avgLat = totalLat / count;
long avgTim = totalTim / count;
return new TargetPoint( avgLng, avgLat, avgTim);
}
// 插值方法,补全缺失的点
private static List<TargetPoint> interpolatePoints(List<TargetPoint> points, int targetSize) {
List<TargetPoint> interpolated = new ArrayList<>(points);
while (interpolated.size() < targetSize) {
List<TargetPoint> temp = new ArrayList<>();
for (int i = 0; i < interpolated.size() - 1; i++) {
temp.add(interpolated.get(i));
double midLng = (interpolated.get(i).getLng() + interpolated.get(i + 1).getLng()) / 2;
double midLat = (interpolated.get(i).getLat() + interpolated.get(i + 1).getLat()) / 2;
long midTim = (interpolated.get(i).getTim() + interpolated.get(i + 1).getTim()) / 2;
temp.add(new TargetPoint(midLng, midLat, midTim));
}
temp.add(interpolated.get(interpolated.size() - 1));
interpolated = temp;
}
return interpolated.subList(0, targetSize);
}
// 删除点方法,简化过多的点
private static List<TargetPoint> reducePoints(List<TargetPoint> points, int targetSize) {
List<TargetPoint> reduced = new ArrayList<>();
double step = (double) points.size() / targetSize;
for (int i = 0; i < targetSize; i++) {
reduced.add(points.get((int) (i * step)));
}
return reduced;
}
// 统一所有轨迹的点数
private static List<List<TargetPoint>> normalizeTrajectories(List<List<TargetPoint>> trajectories, int targetSize) {
List<List<TargetPoint>> normalized = new ArrayList<>();
for (List<TargetPoint> trajectory : trajectories) {
if (trajectory.size() < targetSize) {
normalized.add(interpolatePoints(trajectory, targetSize));
} else if (trajectory.size() > targetSize) {
normalized.add(reducePoints(trajectory, targetSize));
} else {
normalized.add(trajectory);
}
}
return normalized;
}
// 预测下一次可能的完整航迹
public static List<TargetPoint> predictTrajectory(List<List<TargetPoint>> trajectories, double threshold) {
// 过滤掉偏差较大的航线
List<List<TargetPoint>> filteredTrajectories = filterOutliers(trajectories, threshold);
// 找出最长的航迹长度
int maxLength = 0;
for (List<TargetPoint> trajectory : filteredTrajectories) {
if (trajectory.size() > maxLength) {
maxLength = trajectory.size();
}
}
// 统一所有轨迹的点数
List<List<TargetPoint>> normalizedTrajectories = normalizeTrajectories(filteredTrajectories, maxLength);
// 初始化每个位置的点列表
List<List<TargetPoint>> pointsByPosition = new ArrayList<>();
for (int i = 0; i < maxLength; i++) {
pointsByPosition.add(new ArrayList<>());
}
// 收集每个位置的点
for (List<TargetPoint> trajectory : normalizedTrajectories) {
for (int i = 0; i < trajectory.size(); i++) {
pointsByPosition.get(i).add(trajectory.get(i));
}
}
// 计算每个位置的中间点
List<TargetPoint> predictedTrajectory = new ArrayList<>();
for (List<TargetPoint> points : pointsByPosition) {
if (!points.isEmpty()) {
TargetPoint midpoint = calculateMidpoint(points);
predictedTrajectory.add(midpoint);
}
}
return predictedTrajectory;
}
public static void main(String[] args) {
// 示例数据
List<TargetPoint> trajectory1 = new ArrayList<>();
trajectory1.add(new TargetPoint( 30.0, -90.0, 1620000000L));
trajectory1.add(new TargetPoint(31.0, -91.0, 1620000600L));
trajectory1.add(new TargetPoint(32.0, -92.0, 1620001200L));
List<TargetPoint> trajectory2 = new ArrayList<>();
trajectory2.add(new TargetPoint(32.0, -92.0, 1620000000L));
trajectory2.add(new TargetPoint(33.0, -93.0, 1620000600L));
List<TargetPoint> trajectory3 = new ArrayList<>();
trajectory3.add(new TargetPoint(33.0, -93.0, 1620000000L));
trajectory3.add(new TargetPoint(34.0, -94.0, 1620000600L));
trajectory3.add(new TargetPoint(35.0, -95.0, 1620001200L));
// 模拟8条接近的航迹
List<List<TargetPoint>> similarTrajectories = new ArrayList<>();
for (int i = 0; i < 8; i++) {
List<TargetPoint> trajectory = new ArrayList<>();
for (int j = 0; j < 3; j++) {
trajectory.add(new TargetPoint( 30.0 + i, -90.0 - i, 1620000000L + j * 600L));
}
similarTrajectories.add(trajectory);
}
// 添加2条偏差较大的航迹
similarTrajectories.add(trajectory1);
similarTrajectories.add(trajectory2);
similarTrajectories.add(trajectory3);
// 预测航迹
List<TargetPoint> predictedTrajectory = predictTrajectory(similarTrajectories, 1.5); // 1.5 为阈值,可根据需要调整
// 输出预测结果
System.out.println("预测的航迹:");
for (TargetPoint point : predictedTrajectory) {
System.out.println("Lng: " + point.getLng() + ", Lat: " + point.getLat() + ", Time: " + point.getTim());
}
}
}
输出结果为:
预测的航迹:
Lng: 32.6, Lat: -92.6, Time: 1620000000
Lng: 32.85, Lat: -92.85, Time: 1620000570
Lng: 33.1, Lat: -93.1, Time: 1620001140
根据历史航迹的复杂性和是否有规律,预测的结果可能会差强人意。