Smooth GPS Waypoints for Ego Localization
R2026bThis example shows how to smooth an ego trajectory obtained from the Global Positioning System (GPS) and Inertial Measurement Unit (IMU) sensors.
You can use virtual driving scenarios to recreate real-world scenarios from recorded vehicle data. To generate a reliable virtual scenario, you must have accurate trajectory information. You can obtain ego trajectory information from GPS and IMU sensors. However, data from these sensors is often noisy which results in inaccurate waypoints. You can smooth these noisy waypoints to accurately localize the ego vehicle.
In this example, you preprocess the GPS data and smooth noisy ego waypoints using a kinematic motion model and a window-based statistical model.
Load and Preprocess GPS Data
Download the GPS data. The data contains a structure with these fields:
timeStamp— Time at which the data was collected. Units are in microseconds.velocity— Velocity of the ego vehicle. Units are in meters per second.yawRate— Yaw rate of the ego vehicle. Units are in degrees.latitude— Latitude coordinate values of the ego trajectory. Units are in degrees.longitude— Longitude coordinate values of the ego trajectory. Units are in degrees.altitude— Altitude values of the ego trajectory. Units are in meters.
sensorData = fullfile(tempdir,"AutomotiveDataset"); if ~isfolder(sensorData) mkdir(sensorData) end if ~exist("data","var") url = "https://ssd.mathworks.com/supportfiles/driving/data/highwayLaneChangeDatase/ins2.mat"; filePath = fullfile(sensorData,"ins.mat"); if ~isfile(filePath) websave(filePath,url); end data = load(filePath); end
Insert the startTime, egoSampleTime and endTime to the sim object.
startTime— Time to start collecting the data. Units are in microseconds.endTime— Time to stop collecting the data. Units are in microseconds.egoSampleTime— Time interval between each consecutive data point. Units are in microseconds.
sim.startTime = 1461634424950000; sim.endTime = 1461634434950000; sim.egoSampleTime = 0.05;
Compute the start and end timestamp indices, and the number of data points, by using the helperTimestampIndex function.
[~,sim.gps.startstep,sim.gps.endstep] = helperTimestampIndex([data.ins.timeStamp]',sim.startTime,sim.endTime);
Extract the GPS data for the specified timestamp range.
dataSelected.ins = data.ins(sim.gps.startstep:sim.gps.endstep); gps = table([dataSelected.ins.timeStamp]',[dataSelected.ins.latitude]',[dataSelected.ins.longitude]',[dataSelected.ins.altitude]',VariableNames=["Timestamp","Latitude","Longitude","Altitude"]);
gps is an M-by-4 table containing latitude, longitude, and altitude values for each timestamp, where M is the number of data points.
Display the first five entries of the table.
gps(1:5,:)
ans = 5×4 table
1461634424978430 45.5320 -122.6188 34.8609
1461634425028360 45.5320 -122.6188 34.8498
1461634425078181 45.5320 -122.6187 34.8388
1461634425128114 45.5320 -122.6187 34.8248
1461634425178370 45.5320 -122.6187 34.7892
Convert the GPS coordinates to local east-north-up (ENU) coordinates by using the latlon2local function. The transformed coordinates define the waypoints of the ego vehicle. Units are in meters.
referenceLocation = [gps.Latitude(1) gps.Longitude(1) gps.Altitude(1)]; [gps.East,gps.North,gps.Up] = latlon2local(gps.Latitude,gps.Longitude,gps.Altitude,referenceLocation);
Calculate the yaw and velocity of the ego vehicle from the GPS data.
[yaw,velocity] = helperCalculateYawAndVelocity(gps,sim); EgoData = table(gps.Timestamp,[gps.East,gps.North,gps.Up],velocity,yaw,VariableNames=["Time","Waypoints","Velocity","Yaw"]);
Display the first five entries of the EgoData table.
EgoData(1:5,:)
ans = 5×4 table
1461634424978430 0,0,0 0,0,0 -13.2888
1461634425028360 1.2552,-0.3930,0.3747 27.0783,-6.3955,0 -13.2888
1461634425078181 2.6257,-0.6759,0.1122 19.3517,-4.2481,0 -12.3813
1461634425128114 3.5158,-0.9135,0.3314 31.2638,-7.0961,0 -12.7880
1461634425178370 5.0913,-1.4249,0.2686 20.7799,-12.2542,0 -30.5285
Raw GPS data often contains noise. In this example, you can smooth the noisy GPS waypoints by using a kinematic motion model and a window based statistical model. The kinematic motion model is preferred over the statistical method as it uses motion information to smooth the trajectory.
Smooth Ego Trajectory Using Motion Model
Create a smooth, jerk-limited trajectory from the ego waypoints by using the smoothTrajectory function. The generated ego trajectory features a smooth transition of accelerations between waypoints.
% Jerk tolerance jerk = 0.1; waypoints = EgoData.Waypoints; speed = vecnorm(EgoData.Velocity,2,2); yaw = EgoData.Yaw; scenario.SampleTime = 0.05; scenario = drivingScenario(SampleTime=scenario.SampleTime); egoVehicle = vehicle(scenario,ClassID=1,Position=waypoints(1,:),Velocity=EgoData.Velocity(1,:),Yaw=yaw(1)); % Apply trajectory smoothing using smoothTrajectory smoothTrajectory(egoVehicle,waypoints,Yaw=yaw,Jerk=jerk) % Obtain smooth trajectory waypoints reScenario = record(scenario); for idx = 1:size(reScenario,2) smoothWaypoints(idx,:) = reScenario(idx).ActorPoses(1).Position; end
Visualize the smoothed ego trajectory. Note that this model is unable to smooth the trajectory because this is a high-frequency dataset. You can downsample the data and perform smoothing to reduce the error, but this can lead to data loss.
figure scatterPlot1 = scatter3(waypoints(:,1),waypoints(:,2),waypoints(:,3),"filled"); hold on scatterPlot2 = scatter3(smoothWaypoints(:,1),smoothWaypoints(:,2),smoothWaypoints(:,3)); hold off view(0,270) axis([190 217 -130 -110]) legend([scatterPlot1 scatterPlot2],{'Sensor Reading','Smooth Waypoints'}) title("Smoothed Trajectory Using smoothTrajectory") xlabel("X") ylabel("Y") zlabel("Z")

Smooth Ego Trajectory Using Statistical Model
Smooth the ego trajectory by using the smoothdata function. This function uses a statistical window-based, moving-average method to smooth the trajectory.
% The smoothData function smooths out x,y, and z separately smoothFactor = 0.75; % Between 0 and 1 % sgolay smooths the waypoints using a Savitzky-Golay filter, which is more effective than other methods for varying data. smoothWaypoints = smoothdata(waypoints(:,1:3),"sgolay",SmoothingFactor=smoothFactor'); % smoothdata can be further used to smooth yaw smoothYaw = smoothdata(yaw,"sgolay",SmoothingFactor=smoothFactor);
Visualize the smoothed trajectory. For high-frequency data, the smoothing results are better for the statistical model than for the motion model.
scatterPlot1 = scatter3(waypoints(:,1),waypoints(:,2),waypoints(:,3),"filled"); hold on scatterPlot2 = scatter3(smoothWaypoints(:,1),smoothWaypoints(:,2),smoothWaypoints(:,3)); hold off view(0,270) axis([190 217 -130 -110]) legend([scatterPlot1 scatterPlot2],["Sensor Reading","Smooth Waypoints"]) title("Smoothed Trajectory Using smoothData") xlabel("X") ylabel("Y") zlabel("Z")

Helper Function
helperCalculateYawAndVelocity — Calculate yaw angles and velocity from the GPS and timestamp data.
function [calculatedYaw,calculatedVelocity] = helperCalculateYawAndVelocity(gps,sim) % helperCalculateYawAndVelocity calculates yaw angles and velocity from the GPS and timestamp data % This is a helper function for example purposes and may be removed or modified in the future. % Copyright 2022 The MathWorks, Inc. gps.relativeTime = double(gps.Timestamp - sim.startTime)/10^6; gps.speed = helperComputeSpeed(gps.East,gps.North,gps.relativeTime); sim.TotalTime = (sim.endTime - sim.startTime)/10^6; importedScenario = drivingScenario(SampleTime=sim.egoSampleTime,StopTime=sim.TotalTime); egoVehicleGPS = vehicle(importedScenario,ClassID=1,Position=[gps.East(1) gps.North(1) 0]); trajectory(egoVehicleGPS,[gps.East gps.North zeros(size(gps,1),1)],gps.speed); positionIndex = [1 3 6]; velocityIndex = [2 4 7]; i = 1; while advance(importedScenario) position(1,:) = actorPoses(importedScenario).Position; simEgo.data(i,positionIndex) = position; velocity(1,:) = actorPoses(importedScenario).Velocity; simEgo.data(i,velocityIndex) = velocity; simEgo.data(i,5) = i; yaw = actorPoses(importedScenario).Yaw; simEgo.data(i,8) = yaw; simEgo.data(i,9) = importedScenario.SimulationTime; i = i + 1; end calculatedVelocity = [[0 0 0]; simEgo.data(:,velocityIndex)]; calculatedYaw = [simEgo.data(1,8); simEgo.data(:,8)]; end
See Also
Functions
Topics
- Overview of Scenario Generation from Recorded Sensor Data
- Ego Vehicle Localization Using GPS and IMU Fusion for Scenario Generation
- Preprocess Lane Detections for Scenario Generation
- Extract Lane Information from Recorded Camera Data for Scene Generation
- Extract Vehicle Track List from Recorded Camera Data for Scenario Generation
- Generate High Definition Scene from Lane Detections and OpenStreetMap
- Generate Scenario from Actor Track Data and GPS Data