Project-OSRM / osrm-backend

Open Source Routing Machine - C++ backend
http://map.project-osrm.org
BSD 2-Clause "Simplified" License
6.34k stars 3.35k forks source link

Map matching speed estimation between nodes #5911

Closed iedmrc closed 1 month ago

iedmrc commented 3 years ago

Hi,

I have a sequence of GPS coordinates and need to obtain nodes and speeds between those nodes. I provide coordinates, timestamps, and radiuses to the map matching service and specify these options:

This returns matched nodes and it's okay but it also returns several distance, duration, and speed values in different places of the resulted JSON. For example:

{
          "annotation": {
            "metadata": {
              "datasource_names": [
                "lua profile"
              ]
            },
            "nodes": [
              2202640056,
              2202640017,
              2202639978,
              2202639951
            ],
            "datasources": [
              0,
              0,
              0
            ],
            "speed": [
              11.6,
              11.1,
              10.4
            ],
            "weight": [
              0.6,
              3.5,
              0.7
            ],
            "duration": [
              0.6,
              3.5,
              0.7
            ],
            "distance": [
              6.977371,
              38.900102,
              7.24858
            ]
          },
          "steps": [
            {
              "intersections": [
                {
                  "out": 0,
                  "entry": [
                    true
                  ],
                  "bearings": [
                    248
                  ],
                  "location": [
                    27.207614,
                    38.443081
                  ]
                }
              ],
              "driving_side": "right",
              "geometry": {
                "coordinates": [
                  [
                    27.207614,
                    38.443081
                  ],
                  [
                    27.20754,
                    38.443057
                  ]
                ],
                "type": "LineString"
              },
              "mode": "driving",
              "duration": 3.3,
              "maneuver": {
                "bearing_after": 248,
                "location": [
                  27.207614,
                  38.443081
                ],
                "bearing_before": 0,
                "type": "depart"
              },
              "weight": 3.3,
              "distance": 7,
              "name": ""
            },
            {
              "intersections": [
                {
                  "out": 2,
                  "location": [
                    27.20754,
                    38.443057
                  ],
                  "bearings": [
                    0,
                    60,
                    180,
                    255
                  ],
                  "entry": [
                    true,
                    false,
                    true,
                    true
                  ],
                  "in": 1
                },
                {
                  "out": 1,
                  "location": [
                    27.207569,
                    38.442708
                  ],
                  "bearings": [
                    0,
                    180,
                    255
                  ],
                  "entry": [
                    false,
                    true,
                    true
                  ],
                  "in": 0
                }
              ],
              "driving_side": "right",
              "geometry": {
                "coordinates": [
                  [
                    27.20754,
                    38.443057
                  ],
                  [
                    27.207569,
                    38.442708
                  ],
                  [
                    27.207575,
                    38.442643
                  ]
                ],
                "type": "LineString"
              },
              "mode": "driving",
              "duration": 4.2,
              "maneuver": {
                "bearing_after": 175,
                "type": "turn",
                "modifier": "left",
                "bearing_before": 246,
                "location": [
                  27.20754,
                  38.443057
                ]
              },
              "weight": 4.2,
              "distance": 46.1,
              "name": "6244 Sokak"
            },
            {
              "intersections": [
                {
                  "in": 0,
                  "entry": [
                    true
                  ],
                  "bearings": [
                    356
                  ],
                  "location": [
                    27.207575,
                    38.442643
                  ]
                }
              ],
              "driving_side": "right",
              "geometry": {
                "coordinates": [
                  [
                    27.207575,
                    38.442643
                  ],
                  [
                    27.207575,
                    38.442643
                  ]
                ],
                "type": "LineString"
              },
              "mode": "driving",
              "duration": 0,
              "maneuver": {
                "bearing_after": 0,
                "type": "arrive",
                "modifier": "right",
                "bearing_before": 176,
                "location": [
                  27.207575,
                  38.442643
                ]
              },
              "weight": 0,
              "distance": 0,
              "name": "6244 Sokak"
            }
          ],
          "distance": 53.1,
          "duration": 7.5,
          "summary": "6244 Sokak",
          "weight": 7.5
        }
}

I can use one of these speed values as well as calculating distance/duration. But I need the realized one, based on the timestamps that I provided, not the one sourced from the profile file. Which way should I prefer and how can I obtain that speed?

An example request here:

/match/v1/driving/27.203487499999998,38.4519495;27.203487499999998,38.4519495;27.204560899999997,38.4527066;27.204599299999998,38.4527509;27.2046566,38.4527511;27.2047009,38.4527802;27.2047837,38.452795099999996;27.204768299999998,38.452718399999995;27.2047071,38.4526991;27.2046775,38.4524498;27.2047159,38.4525764;27.2047442,38.4524849;27.2046496,38.4523638;27.2045994,38.452235699999996;27.204656399999998,38.451868499999996;27.2047468,38.4516834;27.2048126,38.4515397;27.2052206,38.4510094;27.2045049,38.4498488;27.2042988,38.449934299999995;27.2044273,38.449704499999996;27.2045598,38.4498086;27.204655,38.449815099999995;27.205411599999998,38.448273199999996;27.2056486,38.4478182;27.2053634,38.4477421;27.2054533,38.4478672;27.2056389,38.4479584;27.2058789,38.4474928;27.205824999999997,38.4470953;27.205946599999997,38.4469497;27.2061115,38.4466319;27.2066259,38.4458992;27.2069358,38.445674;27.2067269,38.4455673;27.2065949,38.4455133;27.2062784,38.4451841;27.2069646,38.4449841;27.207215299999998,38.444608699999996;27.207882299999998,38.4443145;27.208122699999997,38.444139799999995;27.2081368,38.443916099999996;27.208224599999998,38.4435704;27.208089899999997,38.4431686;27.2076085,38.4430902;27.2072878,38.4429148;27.207322899999998,38.4426294;27.207446599999997,38.4422705;27.2076297,38.4419383;27.2077523,38.4416095;27.2078831,38.4412653;27.2079822,38.4409007;27.2085649,38.4377989;27.2086087,38.4375742;27.2084604,38.4374737;27.2081926,38.4373467;27.2076149,38.4371357;27.2070398,38.4369374;27.2066779,38.4368391;27.206637299999997,38.436693;27.2067856,38.4364145;27.2069413,38.4361183;27.2070492,38.4358277;27.207029,38.4355295;27.2068716,38.4353656;27.2069281,38.435192;27.207093699999998,38.4348926;27.207264799999997,38.434549499999996;27.2072912,38.4344508;27.207571599999998,38.433885599999996;27.207646999999998,38.4335338;27.2075389,38.4335103;27.2073884,38.4334312;27.207367599999998,38.4335124;27.2074097,38.4335771;27.207477299999997,38.433569;27.2075352,38.433568799999996?timestamps=1607373726;1607373730;1607373861;1607373915;1607373919;1607373932;1607373943;1607373958;1607373980;1607374023;1607374028;1607374033;1607374038;1607374043;1607374049;1607374055;1607374059;1607374065;1607374069;1607374075;1607374080;1607374085;1607374090;1607374095;1607374100;1607374105;1607374110;1607374116;1607374122;1607374126;1607374133;1607374138;1607374143;1607374148;1607374155;1607374161;1607374164;1607374169;1607374175;1607374186;1607374189;1607374195;1607374200;1607374210;1607374222;1607374226;1607374231;1607374235;1607374241;1607374245;1607374250;1607374255;1607374305;1607374310;1607374315;1607374320;1607374330;1607374337;1607374348;1607374351;1607374358;1607374360;1607374365;1607374372;1607374375;1607374385;1607374390;1607374399;1607374405;1607374415;1607374424;1607374429;1607374434;1607374439;1607374449;1607374521;1607374582&radiuses=1100;1100;18;16;15;15;16;17;26;26;24;24;14;19;18;15;72;49;22;31;34;25;50;28;28;24;18;21;24;16;14;111;40;22;15;17;87;9;7;6;7;10;10;13;13;12;12;12;11;11;11;11;15;15;15;17;17;21;92;19;14;15;15;15;12;15;8;7;8;8;9;9;11;10;10;12;10&annotations=true&overview=full&geometries=geojson&tidy=true&gaps=split&steps=true
mjjbell commented 3 years ago

I'd suggest looking at the result object documentation to understand what the different response values represent.

In particular, the route object that is used to represent possible matchings, and the annotation object which provides additional data about route legs.

If I understand correctly, you want the speed and node data from the annotation.

iedmrc commented 3 years ago

Thanks for the answer. I already read it many times but things are not clear I think. So, I want to ask the community to make it clear. Here is the Annotation Object description:

distance: The distance, in metres, between each pair of coordinates
duration: The duration between each pair of coordinates, in seconds. Does not include the duration of any turns.
datasources: The index of the datasource for the speed between each pair of coordinates. 0 is the default profile, other values are supplied via --segment-speed-file to osrm-contract or osrm-customize. String-like names are in the 
speed: Convenience field, calculation of distance / duration rounded to one decimal place

What should I understand from this? If you read duration first, you don't have any information about is it calculated by using OSRM profile speeds or by using the timestamps I supplied. If you go on and read datasources, it says speed comes from OSRM profiles. But if you read speed section after all this, this time it says, the speed is calculated by this division: distance / duration . However, there is no clue how the duration is calculated (as I wrote above, either using the supplied profiles or the time difference of the supplied timestamps).

If you read about Route Leg Object:

distance: The distance traveled by this route leg, in float meters.
duration: The estimated travel time, in float number of seconds.

Duration is an estimation by using what? Does it use the OSRM profile as the ground truth or the timestamps that I provided to the map matching service?

In other words, It's not clear or I don't understand. I provided an example JSON above and is there anyone who can help me how can I obtain the duration or the speed between two nodes which accepts the timestamps that is passed to the service (map matching service), as the ground truth.

danpat commented 3 years ago

The timestamps you supply are only used to decide on the match - they do not affect the timing along the matched path. Duration values in the response come purely from the speeds decided in the Lua profiles.

iedmrc commented 3 years ago

Oh, I see. Do you have any suggestions or a common way to achieve this? In other words, how do you calculate the actual speed between nodes (which returned by map matching service)? Thanks!

danpat commented 3 years ago

Each pair of coordinates you supply to /match will result in a leg[] object in the JSON response. Each leg will have a distance property that describes how long it is.

To find the average speed for a leg, you would divide the leg distance by the difference in time between your two coordinates that correspond to the start/end of that leg (from your recorded timestamps). This would give you a result in metres/second.

iedmrc commented 3 years ago

Good idea but what about such cases: https://github.com/Project-OSRM/osrm-backend/issues/5490#issuecomment-507453301 I mean, coordinates don't always mean they correspond to a node. Sometimes there are distances between nodes and coordinates that I supplied. And since this process done on small scales, an aberration might result in a huge error rate, in total. What do you think about this?

danpat commented 3 years ago

As I said, you should use leg[].distance - this is the length of the leg from the point your first coordinate was snapped to the network, to the point the second coordinate was snapped to, following the best path between.

iedmrc commented 3 years ago

I thought leg[].distance is the distance between the first node and the last node in the annotations. Then, that solves everything. But I have one more question here. How do you calculate the distance between the first coordinate that was snapped to the network and the first node it matched? Is it haversine?

github-actions[bot] commented 2 months ago

This issue seems to be stale. It will be closed in 30 days if no further activity occurs.