From 824ba872fd153e4bae05c41b1dd728f5f3d4638a Mon Sep 17 00:00:00 2001 From: Augustin Gjini Date: Thu, 23 May 2024 11:27:15 +0200 Subject: [PATCH 1/2] feat(back): try to remove noise in geolocation tracking --- .../Integration/LianeTrackerTest.cs | 126 +- back/src/Liane/Liane.Test/LabeledPositions.cs | 6 +- back/src/Liane/Liane.Test/Positions.cs | 4 +- .../Geolocation/Trip_with_noise.json | 1879 +++++++++++++++++ 4 files changed, 1976 insertions(+), 39 deletions(-) create mode 100644 back/src/Liane/Liane.Test/Resources/Geolocation/Trip_with_noise.json diff --git a/back/src/Liane/Liane.Test/Integration/LianeTrackerTest.cs b/back/src/Liane/Liane.Test/Integration/LianeTrackerTest.cs index 2272530e5..13bd6777d 100644 --- a/back/src/Liane/Liane.Test/Integration/LianeTrackerTest.cs +++ b/back/src/Liane/Liane.Test/Integration/LianeTrackerTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Globalization; using System.Linq; using System.Text.Json; using System.Threading.Tasks; @@ -13,11 +14,13 @@ using Liane.Service.Internal.Mongo; using Liane.Service.Internal.Trip; using Liane.Service.Internal.Trip.Geolocation; +using Liane.Service.Internal.Util; using Liane.Test.Util; using Microsoft.Extensions.DependencyInjection; using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Driver; +using MongoDB.Driver.GeoJsonObjectModel; using NUnit.Framework; namespace Liane.Test.Integration; @@ -25,33 +28,6 @@ namespace Liane.Test.Integration; [TestFixture(Category = "Integration")] public sealed class LianeTrackerTest : BaseIntegrationTest { - private static (Api.Trip.Trip liane, FeatureCollection pings) PrepareTestData(Ref userId) - { - var departureTime = DateTime.Parse("2023-08-08T16:12:53.061Z"); - var liane = new Api.Trip.Trip( - "6410edc1e02078e7108a5895", - userId, - DateTime.Today, - departureTime, - null, - new List - { - new(LabeledPositions.Tournefeuille, 0, 0, departureTime), - new(LabeledPositions.AireDesPyrénées, 45 * 60, 65000, DateTime.Parse("2023-08-08T16:57:54.000Z")), - new(LabeledPositions.PointisInard, 19 * 60, 24000, DateTime.Parse("2023-08-08T17:17:05.000Z")) - }.ToImmutableList(), - new List - { - new(userId, LabeledPositions.Tournefeuille, LabeledPositions.PointisInard, 3), - new("63f7a5c90f65806b1adb3081", LabeledPositions.Tournefeuille, LabeledPositions.AireDesPyrénées) - }.ToImmutableList(), - new Driver(userId), - LianeState.NotStarted, - null - ); - return (liane, JsonSerializer.Deserialize(AssertExtensions.ReadTestResource("Geolocation/test-tournefeuille-pointis-inard.json"))!); - } - [Test] public async Task ShouldFinishTrip() { @@ -142,7 +118,7 @@ public async Task ShouldNotFinishTrip() var lianeDb = BsonSerializer.Deserialize(bson); var userIds = lianeDb.Members.Select((m, i) => (m, i)).ToDictionary(m => m.m.User, m => Fakers.FakeDbUsers[m.i].Id); lianeDb = lianeDb with { Members = lianeDb.Members.Select((m, i) => m with { User = userIds[m.User] }).ToImmutableList() }; - await Db.GetCollection().InsertOneAsync(lianeDb); + await db.GetCollection().InsertOneAsync(lianeDb); var liane = await tripService.Get(lianeDb.Id); var tracker = await lianeTrackerService.Start(liane, () => { finished = true; }); var pings = lianeDb.Pings.OrderBy(p => p.At).Select(p => p with { User = userIds[p.User] }).ToImmutableList(); @@ -233,7 +209,7 @@ public async Task ShouldHavePassengersInCar() Assert.Less(1, actual.Car.Position.Distance(expectedLocation!.Value)); } - private async Task<(LianeTracker, ImmutableList, ImmutableDictionary, Ref>)> SetupTracker(string file) + private async Task<(LianeTracker, ImmutableList, ImmutableDictionary, Ref>, Api.Trip.Trip)> SetupTracker(string file) { var bson = BsonDocument.Parse(AssertExtensions.ReadTestResource(file)); var lianeDb = BsonSerializer.Deserialize(bson); @@ -244,27 +220,56 @@ public async Task ShouldHavePassengersInCar() Members = lianeDb.Members.Select(m => m with { User = userMapping[m.User] }).ToImmutableList(), Pings = lianeDb.Pings.Select(p => p with { User = userMapping[p.User] }).ToImmutableList() }; - await Db.GetCollection().InsertOneAsync(lianeDb); + await db.GetCollection().InsertOneAsync(lianeDb); var liane = await tripService.Get(lianeDb.Id); var tracker = await lianeTrackerService.Start(liane); var pings = lianeDb.Pings .OrderBy(p => p.At) .ToImmutableList(); - return (tracker, pings, userMapping.ToImmutableDictionary(e => e.Value, e => e.Key)); + return (tracker, pings, userMapping.ToImmutableDictionary(e => e.Value, e => e.Key), liane); } - private async Task<(LianeTracker, ImmutableDictionary, Ref>)> SetupTrackerAt(string file, string? at = null) + private async Task<(LianeTracker, ImmutableDictionary, Ref>)> SetupTrackerAt(string file, string? at = null, bool debugGeoJson = false) { - var (tracker, pings, userMapping) = await SetupTracker(file); + var (tracker, pings, userMapping, trip) = await SetupTracker(file); // Send first few pings outside of planned route var sublist = (at is null ? pings : pings.TakeWhile(p => p.At.ToUniversalTime() < DateTime.Parse(at).ToUniversalTime())).ToList(); + var index = 0; + var geoJson = new List>(); foreach (var p in sublist) { + var args = new GeoJsonFeatureArgs(); + var properties = new BsonDocument + { + ["user"] = p.User.ToString(), + ["timestamp"] = p.At.ToString(CultureInfo.GetCultureInfo("FR_fr")), + ["index"] = index++ + }; + + args.ExtraMembers = new BsonDocument + { + ["properties"] = properties + }; + + geoJson.Add(new GeoJsonFeature(args, new GeoJsonPoint( + new GeoJson2DGeographicCoordinates(p.Coordinate.Value.Lng, p.Coordinate.Value.Lat) + ))); await lianeTrackerService.PushPing(tracker.Trip, p); } + if (debugGeoJson) + { + var routingService = ServiceProvider.GetRequiredService(); + var simplifiedRoute = + new GeoJsonFeature((await routingService.GetRoute(trip.WayPoints.Select(w => w.RallyingPoint.Location).ToImmutableList())).Coordinates.ToLatLng().ToGeoJson()); + geoJson.Add(simplifiedRoute); + + var collection = new GeoJsonFeatureCollection(geoJson); + Console.WriteLine("GEOJSON : {0}", collection.ToJson()); + } + return (tracker, userMapping); } @@ -327,7 +332,7 @@ public async Task Trip_qui_se_trouve_deja_a_destination() // Départ : Roques // Arrivée : LivingObjects - // driver thibauls : 6617e60b606952ceee7ee2aa + // driver thibault : 6617e60b606952ceee7ee2aa // augustin : ba3 // thibault se trouve déjà à destination @@ -338,15 +343,62 @@ public async Task Trip_qui_se_trouve_deja_a_destination() Assert.AreEqual("custom:001", actual.Car?.NextPoint.Id); } + [Test] + public async Task Trip_with_noise() + { + var (tracker, userMapping) = await SetupTrackerAt("Geolocation/Trip_with_noise.json", debugGeoJson: true); + + // Départ : Roques + // Arrivée : LivingObjects + + // driver thibault : 6617e60b606952ceee7ee2aa + // augustin : ba3 + + // thibault se trouve déjà à destination + //await lianeTrackerService.PushPing("6617e60b606952ceee7ee2aa", new UserPing("65f2cbd9e94a0516ac1e6dac", DateTime.Parse("2024-04-11T13:03:00+1"), TimeSpan.Zero, new LatLng(3.4845875, 44.3378072))); + + var actual = tracker.GetTrackingInfo(); + + Assert.AreEqual("bnlc:07127-C-001", actual.Car?.NextPoint.Id); + } + + private IMongoDatabase db = null!; - private IMongoDatabase Db = null!; private ITripService tripService = null!; + private ILianeTrackerService lianeTrackerService = null!; - protected override void Setup(IMongoDatabase db) + protected override void Setup(IMongoDatabase database) { - Db = db; + db = database; tripService = ServiceProvider.GetRequiredService(); lianeTrackerService = ServiceProvider.GetRequiredService(); } + + private static (Api.Trip.Trip liane, FeatureCollection pings) PrepareTestData(Ref userId) + { + var departureTime = DateTime.Parse("2023-08-08T16:12:53.061Z"); + var liane = new Api.Trip.Trip( + "6410edc1e02078e7108a5895", + userId, + DateTime.Today, + departureTime, + null, + new List + { + new(LabeledPositions.Tournefeuille, 0, 0, departureTime), + new(LabeledPositions.AireDesPyrénées, 45 * 60, 65000, DateTime.Parse("2023-08-08T16:57:54.000Z")), + new(LabeledPositions.PointisInard, 19 * 60, 24000, DateTime.Parse("2023-08-08T17:17:05.000Z")) + }.ToImmutableList(), + new List + { + new(userId, LabeledPositions.Tournefeuille, LabeledPositions.PointisInard, 3), + new("63f7a5c90f65806b1adb3081", LabeledPositions.Tournefeuille, LabeledPositions.AireDesPyrénées) + }.ToImmutableList(), + new Driver(userId), + LianeState.NotStarted, + null + ); + return (liane, JsonSerializer.Deserialize(AssertExtensions.ReadTestResource("Geolocation/test-tournefeuille-pointis-inard.json"))!); + } } \ No newline at end of file diff --git a/back/src/Liane/Liane.Test/LabeledPositions.cs b/back/src/Liane/Liane.Test/LabeledPositions.cs index f1e490e7f..15b3c4abd 100755 --- a/back/src/Liane/Liane.Test/LabeledPositions.cs +++ b/back/src/Liane/Liane.Test/LabeledPositions.cs @@ -93,6 +93,8 @@ public sealed class LabeledPositions "Balsièges", null, true); public static readonly RallyingPoint LO = new("custom:001", "Living Objects", Positions.LO, LocationType.Parking, "1 impasse Marcel Chalard", "31000", "Toulouse", 10, true); + public static readonly RallyingPoint ArdecheBeage = new("mairie:07026", "Le Beage", Positions.ArdecheLeBeage, LocationType.TownHall, "Le Village", "07630", "Le Béage", 10, true); + public static readonly RallyingPoint ArdecheBoulodrome = new("bnlc:07127-C-001", "Boulodrome", Positions.ArdecheBoulodrome, LocationType.Parking, "33 Avenue Centrale. 07380 Lalevade-d'Ardéche", "07380", "Lalevade-d'Ardéche", 10, true); public static readonly IImmutableSet RallyingPoints = ImmutableHashSet.Create( Mende, @@ -133,6 +135,8 @@ public sealed class LabeledPositions MartresTolosane, LO, Montbrun, - Choizal + Choizal, + ArdecheBeage, + ArdecheBoulodrome ); } \ No newline at end of file diff --git a/back/src/Liane/Liane.Test/Positions.cs b/back/src/Liane/Liane.Test/Positions.cs index f43e43998..081eb0530 100755 --- a/back/src/Liane/Liane.Test/Positions.cs +++ b/back/src/Liane/Liane.Test/Positions.cs @@ -15,7 +15,7 @@ public sealed class Positions public static readonly LatLng GorgesDuTarnCausses = new(44.36512686514503, 3.414840996265411); public static readonly LatLng SaintEnimieParking = new(44.36545637889574, 3.412078320980072); public static readonly LatLng Florac = new(44.319013, 3.578021); - public static readonly LatLng FloracFormares = new(44.335825,3.5847193); + public static readonly LatLng FloracFormares = new(44.335825, 3.5847193); public static readonly LatLng SaintChelyDuTarnEnHaut = new(44.338294306952264, 3.381930291652679); public static readonly LatLng ChamperbouxEglise = new(44.40842497198885, 3.414583504199982); public static readonly LatLng LavalDuTarnEglise = new(44.3533150645425, 3.352039754390717); @@ -44,4 +44,6 @@ public sealed class Positions public static readonly LatLng Choizal = new(44.4595512, 3.452795); public static readonly LatLng LO = new(43.567936, 1.390924); public static readonly LatLng Lavogne = new(44.414532, 3.5101363); + public static readonly LatLng ArdecheLeBeage = new(44.849155426, 4.11706209183); + public static readonly LatLng ArdecheBoulodrome = new(44.651711, 4.322269); } \ No newline at end of file diff --git a/back/src/Liane/Liane.Test/Resources/Geolocation/Trip_with_noise.json b/back/src/Liane/Liane.Test/Resources/Geolocation/Trip_with_noise.json new file mode 100644 index 000000000..7d80d1b53 --- /dev/null +++ b/back/src/Liane/Liane.Test/Resources/Geolocation/Trip_with_noise.json @@ -0,0 +1,1879 @@ +{ + "_id": {"$oid": "6645c7b12974cadf0042c82a"}, + "conversation": null, + "createdAt": {"$date": "2024-05-16T08:45:37.491Z"}, + "createdBy": {"$oid": "654e2de81435035edcef9b7f"}, + "departureTime": {"$date": "2024-05-16T08:50:00.000Z"}, + "driver": { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "canDrive": true + }, + "members": [ + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "from": "mairie:07026", + "to": "bnlc:07127-C-001", + "seatCount": 1, + "feedback": null, + "geolocationLevel": "Shared", + "departure": {"$date": "2024-05-16T08:46:45.443Z"}, + "cancellation": {"$date": "2024-05-16T09:28:27.615Z"} + } + ], + "pings": [ + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:46:46.310Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.121275233813979, 44.85396328565936] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:47:01.727Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.141026034230779, 44.851333312686535] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:47:01.711Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.138470207907003, 44.85352646545271] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:47:20.308Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.115581564218619, 44.84865792143153] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:47:20.330Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.111326241461533, 44.84821049064764] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:47:43.387Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.119411611595985, 44.848443524020624] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:47:43.390Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1254702847255915, 44.84861814736825] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:09.504Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.115387713060024, 44.84808408328922] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:09.518Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.111229313290036, 44.847923571438486] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:15.754Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.04982765034433, 44.82406217272065] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:15.783Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.020404803173157, 44.812627687601534] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:15.786Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.005693423997656, 44.806910460558605] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:16.071Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.005693423997656, 44.806910460558605] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:16.771Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.03917210800293, 44.817163528691765] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:44.990Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.072439667532382, 44.83215958426316] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:45.004Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.089426191978065, 44.83981304327333] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:45.460Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.089426191978065, 44.83981304327333] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:45.983Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1026185297162225, 44.84208567147703] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:50:46.007Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.112596171485797, 44.84380398096968] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:51:52.939Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9759465252955772, 44.83635906855634] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:51:52.955Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9167223501851156, 44.8327532068843] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:52:04.232Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.111829856345678, 44.86852925860523] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:52:04.294Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.111829856345678, 44.86852925860523] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:52:04.795Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.111829856345678, 44.86852925860523] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:52:05.992Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.128228545250391, 44.87153617153636] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:52:09.654Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1314021427523535, 44.866565551382166] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:52:09.673Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.133757509855768, 44.862870471146735] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:53:15.092Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.142942490121573, 44.869814131037884] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:53:15.104Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.14419296059869, 44.87332774901568] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:53:21.164Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.143266578223351, 44.867888588991676] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:53:21.174Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.142573885891295, 44.8638510934896] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:53:28.387Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1415778370370795, 44.86334357370754] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:53:28.409Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.140679816738186, 44.86289799832568] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:55:33.699Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9936729136574534, 44.84877233575852] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:55:33.720Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9747369343531314, 44.8472778130316] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:55:35.533Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9427598611796313, 44.868943324281254] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:55:35.548Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.921154137906126, 44.883582000778894] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:55:35.811Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.921154137906126, 44.883582000778894] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:55:35.838Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.906555698414674, 44.89347296921436] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:55:36.075Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.8966920666357385, 44.90015593774271] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:56:12.220Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.960840740961054, 44.88919854939013] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:56:12.236Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.011935379478622, 44.87799819415431] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:56:32.391Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.075481576587565, 44.86525924586961] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:56:32.405Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.107636385126509, 44.85879827537985] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:56:34.756Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.107636385126509, 44.85879827537985] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:15.674Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.139401999555981, 44.86964694765545] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:15.697Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.142013733320838, 44.87209458328953] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:21.224Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.141693016177923, 44.86697340751307] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:21.246Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.141404924124173, 44.86317062012352] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:31.542Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.14062156959162, 44.86272990543289] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:31.561Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.139820765465473, 44.86234691253323] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:34.853Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.119891548968022, 44.85266986381521] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:40.314Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.070189738762855, 44.830729659743234] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:40.337Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.006565754523551, 44.80267919631585] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:40.334Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.0335507322947555, 44.81457626815364] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:41.825Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.006565754523551, 44.80267919631585] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:44.909Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9758652952755527, 44.80285683791466] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:44.929Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9595740297692292, 44.802964000372775] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:46.138Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.950923100458947, 44.80301768646463] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:46.926Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9463328400157645, 44.80304734727448] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:47.257Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9438981319935453, 44.803064303050746] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:57:48.879Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.942601453187802, 44.80306998540124] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:58:17.575Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9072092938595504, 44.8136904032564] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:58:17.571Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.921037653059171, 44.809479757082364] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:58:17.589Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.8982797046222397, 44.81640938168764] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:59:05.118Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.8997059588014285, 44.84960277617342] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:58:36.250Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.890021227279566, 44.829388341031716] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:58:17.602Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.892513545350191, 44.81816512427679] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:58:20.458Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.9016204753012844, 44.8406593647494] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:59:05.136Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.907268754735051, 44.86470954884988] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:59:14.833Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.970257360991411, 44.86143040937498] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:59:14.859Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.01625905466, 44.85893227166519] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:58:36.234Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [3.8944566456184675, 44.833826533732015] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:59:23.708Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.029187186250842, 44.8590364775248] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T08:59:23.720Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.040578943253288, 44.859036076033256] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:00:08.486Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1017838545031315, 44.85378345976443] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:00:08.509Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.122683064782753, 44.85146186978412] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:00:08.851Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.122683064782753, 44.85146186978412] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:00:11.582Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.135482953769309, 44.851979866810304] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:00:11.604Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.138027465804037, 44.85208022883895] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:01:29.582Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.137006344296213, 44.855200547905746] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:01:29.563Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.138376589855615, 44.85392608968227] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:02:20.868Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.13946269386361, 44.85318532974928] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:02:20.891Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.140017171158602, 44.852682912309945] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:02:41.374Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.141068503989337, 44.851676463650186] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:02:41.420Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1417881357323765, 44.85095033633108] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:02:52.291Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.141187994320147, 44.85156844522898] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:02:52.316Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.140879812105283, 44.851874465970404] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:03:13.246Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.138898840543781, 44.85367128711316] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:03:13.264Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.137392596124038, 44.855014300993446] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:03:49.831Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.139497050528184, 44.853144807450676] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:03:49.845Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.140303367099548, 44.852421194696] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:05:18.142Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.138604437614577, 44.85394382025671] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:05:18.154Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.137177219177926, 44.855213852425756] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:05:37.470Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.139005830756314, 44.85348178087651] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:05:37.481Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.140312190749427, 44.85224234050679] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:06:17.897Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.140764662454709, 44.85194555492302] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:06:17.928Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.140668127192572, 44.85206301760653] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:06:24.439Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.11954522497415, 44.848640479693024] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:07:01.634Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.120812802923308, 44.84769206402267] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:07:34.582Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.121961567357465, 44.84683511059716] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:07:58.039Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.124185933469932, 44.84680915354869] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:11:39.666Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.128958801851109, 44.84724344189664] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:11:39.696Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1309655717822755, 44.848096576082376] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:04.146Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1581679828511735, 44.82850097453022] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:51.674Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.16160017252356, 44.82553894170078] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:52.369Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.161723135043086, 44.82540386733117] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:53.369Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.161850288514199, 44.82526686512383] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:54.369Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.161927150566282, 44.82516221706273] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:55.376Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162046196302726, 44.825084951689924] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:55.966Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162062769759597, 44.82496360786708] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:56.966Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162121443081798, 44.82487710662635] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:57.968Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.16221124594087, 44.824763562134976] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:58.970Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162277849394979, 44.82462422460767] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:12:59.972Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162356465207906, 44.82452497495898] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:00.974Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162433168244222, 44.82439509661121] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:01.976Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162494605410996, 44.8242495535359] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:02.978Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162595020610991, 44.82408061627748] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:03.979Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162694364830645, 44.82394066111669] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:04.980Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162785373632016, 44.82377128214093] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:05.982Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.162893500182929, 44.82360993050488] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:06.983Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.163015875969234, 44.823426744011066] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:07.984Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1631163749882605, 44.8232547892675] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:08.985Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.163245540116134, 44.823100855615756] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:09.986Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.163363305855694, 44.82297646817269] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:10.987Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.163500936705772, 44.82282995250525] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:11.988Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.163651976197337, 44.82270912447353] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:12.989Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1638287135829835, 44.822598644978264] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:13.990Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.164009382952157, 44.82250280682447] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:14.990Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.164167381826941, 44.82239522509726] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:15.991Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1643391270229255, 44.82233977880778] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:16.992Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.164596451450293, 44.8223239789203] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:17.992Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.164852908062234, 44.82226704547608] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:18.993Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1651201527604504, 44.82225214601012] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:19.993Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.165375046435898, 44.822211032775066] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:20.994Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.165623905141061, 44.822187353898606] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:21.994Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.165871758017843, 44.822167027783415] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:22.995Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.166119443256562, 44.822126962286255] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:23.995Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.166373247284597, 44.822080316995105] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:24.996Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1666029114314975, 44.82202474497708] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:25.996Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.166819583628482, 44.82196804140212] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:26.996Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1670313488627775, 44.82189457429675] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:27.997Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.167228669108813, 44.82183260462467] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:28.997Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1674674188039615, 44.821756160013145] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:34.998Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1687346441846955, 44.821352543214815] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:40.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.169944776225993, 44.82098048557045] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:49.000Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1711227451768345, 44.82040584748155] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:13:55.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.171818299222897, 44.81959047265799] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:14:01.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.172920644352758, 44.81902000863123] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:14:06.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.174215287732796, 44.818679723724514] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:14:12.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.175142142925575, 44.81805666819663] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:14:19.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.176112348217681, 44.8173208209172] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:14:26.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.177391552662354, 44.81712564171211] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:14:31.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.178878137314337, 44.81734871897682] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:14:36.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.180185568719831, 44.81754627294981] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:14:41.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.181447172486356, 44.81771830566298] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:14:46.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.182729286075025, 44.81769431237312] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:14:55.002Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.183750936095941, 44.81691634552671] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:15:00.002Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.184630765088317, 44.816185568652436] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:15:06.002Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.185785325569977, 44.81580216372277] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:15:15.002Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.187016413251785, 44.815488981472136] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:15:36.002Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.188470039520588, 44.81664628725947] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:15:57.662Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.189027123251601, 44.81793599891166] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:16:17.957Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.189612465517072, 44.81884561344853] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:16:45.351Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.190158674677173, 44.81969442696368] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:17:32.709Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.190693310320265, 44.82052518318924] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:18:19.318Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.19309742381601, 44.818899529002074] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:18:19.340Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.1950286424331376, 44.81708875440871] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:18:36.431Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.198436601027509, 44.814587036348215] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:18:36.418Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.196883210791975, 44.815784783443796] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:18:55.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.20491759665702, 44.81369707271905] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:19:03.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.205387179900969, 44.81284283548863] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:19:09.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.206187371168477, 44.812065744814284] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:19:27.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.208351075653181, 44.809926892672486] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:19:32.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.209238132465826, 44.80922671039105] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:19:46.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.21054803253091, 44.807555519815466] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:19:38.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.210044220093833, 44.80851718228758] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:19:52.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.210846631305758, 44.80666666634878] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:20:00.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.211290859296006, 44.80578921937953] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:20:09.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.212168044500704, 44.804717680508865] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:20:11.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.212853265825186, 44.80387129127074] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:20:16.001Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.213545462419484, 44.8030077054657] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:20:28.000Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.215023619131516, 44.80139370763584] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:20:32.000Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.215607536635758, 44.801219694481716] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:20:39.000Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.216931677844163, 44.80076983163777] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:20:47.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.217902505774254, 44.80011327662021] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:20:53.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.21805783089568, 44.79914584521959] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:20:59.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.218252987443719, 44.79854475225622] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:21:07.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.219203777784824, 44.79787105502909] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:21:13.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.220345223197557, 44.79744230227334] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:21:23.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.221695149321316, 44.79702634741067] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:21:38.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.223707728091836, 44.79638429362773] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:21:52.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.225420589347615, 44.79574813200235] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:21:56.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.225476652807036, 44.79523888667116] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:24:05.999Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.224942214790941, 44.78775089145152] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:24:54.709Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.221269159444576, 44.788204659447615] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:24:54.727Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.218470722536793, 44.78862419876266] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:25:29.641Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.210903464079843, 44.79839960424735] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:25:29.654Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.209779595860002, 44.80269797136975] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:26:01.225Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.202076965155635, 44.806831928896294] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:26:01.236Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.197836094696773, 44.80813241062278] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:26:04.998Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.2176763267806745, 44.78037797940972] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:26:20.998Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.217137482878765, 44.77975649333471] + } + }, + { + "user": {"$oid": "654e2de81435035edcef9b7f"}, + "at": {"$date": "2024-05-16T09:26:23.998Z"}, + "delay": "00:00:00", + "coordinate": { + "type": "Point", + "coordinates": [4.2172783892641, 44.779584319372454] + } + } + ], + "recurrence": null, + "return": null, + "state": "Canceled", + "totalSeatCount": 1, + "wayPoints": [ + { + "rallyingPoint": "mairie:07026", + "duration": 0, + "distance": 0, + "eta": {"$date": "2024-05-16T08:50:00.000Z"} + }, + { + "rallyingPoint": "bnlc:07127-C-001", + "duration": 3199, + "distance": 48650, + "eta": {"$date": "2024-05-16T09:43:19.000Z"} + } + ] +} From 418af3ecb1b895309cd5495c9a064432d05b0b07 Mon Sep 17 00:00:00 2001 From: Augustin Gjini Date: Fri, 31 May 2024 17:25:11 +0200 Subject: [PATCH 2/2] wip --- .../Internal/Util/KalmanFilter.cs | 44 +++++++++++++++++++ .../Liane/Liane.Service/Liane.Service.csproj | 5 ++- .../Integration/LianeTrackerTest.cs | 38 ++++++++++------ 3 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 back/src/Liane/Liane.Service/Internal/Util/KalmanFilter.cs diff --git a/back/src/Liane/Liane.Service/Internal/Util/KalmanFilter.cs b/back/src/Liane/Liane.Service/Internal/Util/KalmanFilter.cs new file mode 100644 index 000000000..3926320eb --- /dev/null +++ b/back/src/Liane/Liane.Service/Internal/Util/KalmanFilter.cs @@ -0,0 +1,44 @@ +using MathNet.Filtering.Kalman; +using MathNet.Numerics.LinearAlgebra; + +namespace Liane.Service.Internal.Util; + +public sealed class KalmanFilter +{ + private readonly DiscreteKalmanFilter dkf; + private readonly Matrix stateTransitionMatrixF; + private readonly Matrix plantNoiseMatrixG; + private readonly Matrix plantNoiseVarianceQ; + private readonly Matrix measurementVarianceMatrixR; + private readonly Matrix measurementMatrixH; + + public KalmanFilter(double x0, double v0, double dt, double plantNoiseVar = 3, double measurementCovariance = 1.5) + { + var xState = Matrix.Build.Dense(2, 1, [x0, v0]); + + var measurementCovarianceMatrix = Matrix.Build.Dense(2, 2, + [ + measurementCovariance, measurementCovariance / dt, + measurementCovariance / dt, 2 * measurementCovariance / (dt * dt) + ]); + + dkf = new DiscreteKalmanFilter(xState, measurementCovarianceMatrix); + + stateTransitionMatrixF = Matrix.Build.Dense(2, 2, [1d, 0d, dt, 1]); + plantNoiseMatrixG = Matrix.Build.Dense(2, 1, [dt * dt / 2, dt]); + plantNoiseVarianceQ = plantNoiseMatrixG.Transpose() * plantNoiseMatrixG * plantNoiseVar; + measurementVarianceMatrixR = Matrix.Build.Dense(1, 1, [measurementCovariance]); + measurementMatrixH = Matrix.Build.Dense(1, 2, [1d, 0d]); + } + + public void Update(double x, double y, double dt) + { + var z = Matrix.Build.Dense(1, 2, [x, y]); + stateTransitionMatrixF[0, 1] = dt; + plantNoiseMatrixG[0, 0] = dt * dt / 2; + plantNoiseMatrixG[1, 0] = dt; + + dkf.Predict(stateTransitionMatrixF, plantNoiseMatrixG, plantNoiseVarianceQ); + dkf.Update(z, measurementMatrixH, measurementVarianceMatrixR); + } +} \ No newline at end of file diff --git a/back/src/Liane/Liane.Service/Liane.Service.csproj b/back/src/Liane/Liane.Service/Liane.Service.csproj index b52f03301..ac2e35497 100755 --- a/back/src/Liane/Liane.Service/Liane.Service.csproj +++ b/back/src/Liane/Liane.Service/Liane.Service.csproj @@ -17,9 +17,10 @@ + - - + + diff --git a/back/src/Liane/Liane.Test/Integration/LianeTrackerTest.cs b/back/src/Liane/Liane.Test/Integration/LianeTrackerTest.cs index 13bd6777d..c30a3c46f 100644 --- a/back/src/Liane/Liane.Test/Integration/LianeTrackerTest.cs +++ b/back/src/Liane/Liane.Test/Integration/LianeTrackerTest.cs @@ -6,10 +6,9 @@ using System.Text.Json; using System.Threading.Tasks; using GeoJSON.Text.Feature; -using GeoJSON.Text.Geometry; +using Liane.Api.Auth; using Liane.Api.Routing; using Liane.Api.Trip; -using Liane.Api.Auth; using Liane.Api.Util.Ref; using Liane.Service.Internal.Mongo; using Liane.Service.Internal.Trip; @@ -22,6 +21,7 @@ using MongoDB.Driver; using MongoDB.Driver.GeoJsonObjectModel; using NUnit.Framework; +using Point = GeoJSON.Text.Geometry.Point; namespace Liane.Test.Integration; @@ -42,7 +42,7 @@ public async Task ShouldFinishTrip() var point = (f.Geometry as Point)!; var time = f.Properties["timestamp"].ToString()!; var user = f.Properties["user"].ToString()!; - return (timestamp: DateTime.Parse(time), coordinate: new LatLng(point.Coordinates.Latitude, point.Coordinates.Longitude), user: user); + return (timestamp: DateTime.Parse(time), coordinate: new LatLng(point.Coordinates.Latitude, point.Coordinates.Longitude), user); }); foreach (var p in pings.OrderBy(p => p.timestamp)) { @@ -117,7 +117,7 @@ public async Task ShouldNotFinishTrip() var bson = BsonDocument.Parse(AssertExtensions.ReadTestResource("Geolocation/liane-pings-case-1.json")); var lianeDb = BsonSerializer.Deserialize(bson); var userIds = lianeDb.Members.Select((m, i) => (m, i)).ToDictionary(m => m.m.User, m => Fakers.FakeDbUsers[m.i].Id); - lianeDb = lianeDb with { Members = lianeDb.Members.Select((m, i) => m with { User = userIds[m.User] }).ToImmutableList() }; + lianeDb = lianeDb with { Members = lianeDb.Members.Select((m, _) => m with { User = userIds[m.User] }).ToImmutableList() }; await db.GetCollection().InsertOneAsync(lianeDb); var liane = await tripService.Get(lianeDb.Id); var tracker = await lianeTrackerService.Start(liane, () => { finished = true; }); @@ -142,7 +142,7 @@ public async Task ShouldTrackNextWayPointWithPassengers() // check that next point is Quezac (the car is going towards Quezac) var actual = tracker.GetTrackingInfo(); - Assert.AreEqual("Quezac_Parking", actual.Car.NextPoint.Id); + Assert.AreEqual("Quezac_Parking", actual.Car?.NextPoint.Id); } [Test] @@ -153,8 +153,8 @@ public async Task ShouldTrackFirstWayPointWithPassengers() // check that next point is Quezac (the car is going towards Quezac) var actual = tracker.GetTrackingInfo(); - Assert.AreEqual("Quezac_Parking", actual.Car.NextPoint.Id); - Assert.Less(Math.Abs(actual.Car.Delay - 562), 10); // Check difference with expected value is less than 10 seconds + Assert.AreEqual("Quezac_Parking", actual.Car?.NextPoint.Id); + Assert.Less(Math.Abs(actual.Car!.Delay - 562), 10); // Check difference with expected value is less than 10 seconds Assert.AreEqual(DateTime.Parse("2023-12-05T07:37:34.113Z").ToUniversalTime(), actual.Car.At); } @@ -167,8 +167,8 @@ public async Task ShouldTrackDestinationWayPoint() var actual = tracker.GetTrackingInfo(); // check that next point is Mende - Assert.AreEqual("Mende", actual.Car.NextPoint.Id); - Assert.Less(Math.Abs(actual.Car.Delay - 1450), 10); // Check difference with expected value is less than 10 seconds + Assert.AreEqual("Mende", actual.Car?.NextPoint.Id); + Assert.Less(Math.Abs(actual.Car!.Delay - 1450), 10); // Check difference with expected value is less than 10 seconds } [Test] @@ -178,7 +178,7 @@ public async Task ShouldNotHavePassengersInCarWhenNoPassengersPing() var actual = tracker.GetTrackingInfo(); // Check who's in the car - CollectionAssert.AreEquivalent(ImmutableList.Create(tracker.Trip.Driver.User.Id), actual.Car.Members.Select(m => m.Id)); + CollectionAssert.AreEquivalent(ImmutableList.Create(tracker.Trip.Driver.User.Id), actual.Car?.Members.Select(m => m.Id)); } [Test] @@ -188,7 +188,7 @@ public async Task ShouldNotHavePassengersInCarBeforePickup() var actual = tracker.GetTrackingInfo(); // Check who's in the car - CollectionAssert.AreEquivalent(ImmutableList.Create(tracker.Trip.Driver.User.Id), actual.Car.Members.Select(m => m.Id)); + CollectionAssert.AreEquivalent(ImmutableList.Create(tracker.Trip.Driver.User.Id), actual.Car?.Members.Select(m => m.Id)); // Check we do have location for the other member Assert.AreEqual(1, actual.OtherMembers.Count); Assert.AreNotEqual(tracker.Trip.Driver.User.Id, actual.OtherMembers.Keys.First()); @@ -201,12 +201,12 @@ public async Task ShouldHavePassengersInCar() var actual = tracker.GetTrackingInfo(); // Check who's in the car - CollectionAssert.AreEquivalent(tracker.Trip.Members.Select(m => m.User.Id), actual.Car.Members.Select(m => m.Id)); + CollectionAssert.AreEquivalent(tracker.Trip.Members.Select(m => m.User.Id), actual.Car?.Members.Select(m => m.Id)); // Check car's current location var expectedLocation = tracker.GetCurrentMemberLocation( tracker.Trip.Members.First(m => m.User != tracker.Trip.Driver.User ).User)?.Location; - Assert.Less(1, actual.Car.Position.Distance(expectedLocation!.Value)); + Assert.Less(1, actual.Car?.Position.Distance(expectedLocation!.Value)); } private async Task<(LianeTracker, ImmutableList, ImmutableDictionary, Ref>, Api.Trip.Trip)> SetupTracker(string file) @@ -236,6 +236,18 @@ public async Task ShouldHavePassengersInCar() // Send first few pings outside of planned route var sublist = (at is null ? pings : pings.TakeWhile(p => p.At.ToUniversalTime() < DateTime.Parse(at).ToUniversalTime())).ToList(); + var startAt = sublist.First().At; + var kalmanFilter = new KalmanFilter(0, 0, 0); + foreach (var p in sublist) + { + if (p.Coordinate is null) + { + continue; + } + + kalmanFilter.Update(p.Coordinate.Value.Lng, p.Coordinate.Value.Lat, (p.At - startAt).TotalMilliseconds); + } + var index = 0; var geoJson = new List>(); foreach (var p in sublist)