GanosBase provides four categories of functions for preprocessing trajectory sampling-point data: filtering, segmentation, resampling, and simplification. These functions address common data-quality issues in GPS-based trajectory data and are available starting from GanosBase version 5.2.
GanosBase trajectories
Trajectories are spatiotemporal objects used to analyze and process moving objects such as pedestrians, vehicles, ships, and aircraft.
Trajectory data can be represented in two ways:
Discrete points: A set of individual sampling points. More sensitive to sampling frequency but algorithmically simpler. Functions for similarity computation and segmentation typically operate on discrete points.
Continuous lines: A spatial polyline that evolves over time. Less sensitive to sampling frequency and supports spatial operations on the polyline geometry.
For example, a shared bicycle reports its coordinates (114.35, 39.28) at 17:42:30 on April 11, 2020. This generates the following record:
| Time | x | y |
|---|---|---|
| 2020-04-11 17:42:30 | 114.35 | 39.28 |
Additional attributes such as speed can be recorded at each sampling point:
| Time | x | y | Speed |
|---|---|---|---|
| 2020-04-11 17:42:30 | 114.35 | 39.28 | 4.3 |
| 2020-04-11 17:43:30 | 114.36 | 39.28 | 4.8 |
| 2020-04-11 17:45:00 | 114.35 | 39.29 | 3.5 |
These points form a spatiotemporal trajectory, as shown in the following figure.

The native GanosBase trajectory engine of PolarDB introduces the trajectory type, indexing, and spatiotemporal operators to resolve issues related to the storage, retrieval, and analysis of moving objects.
Data quality issues in GPS trajectory data
In most business scenarios, trajectory data is collected by systems such as transportation management system (TMS) and automatic identification system (AIS) from GPS signals at a relatively consistent sampling frequency. However, the following issues can degrade trajectory data quality:
Drift points: GPS signal noise causes sampling points to deviate significantly from the actual movement path.
Stationary noise: Objects that remain in one location for extended periods — such as ships waiting at anchor or vehicles stopped at rest areas — generate excessive redundant points.
Uneven point density: Preprocessing steps such as noise reduction can leave gaps in the trajectory, causing uneven sampling that introduces errors in subsequent similarity calculations.
Large data volumes: High point density reduces frontend rendering performance, causing program failures and stuttering.
Processing methods
| Method | Function | Use when |
|---|---|---|
| Trajectory filtering | ST_removeDriftPoints | GPS drift or speed anomalies are present |
| Trajectory segmentation | ST_Split | Splitting a trajectory at specific points or removing segments |
| Trajectory resampling | ST_Resample | Point density is uneven after preprocessing |
| Trajectory simplification | ST_Compress, ST_CompressSED | Reducing point count while preserving movement shape |
ST_removeDriftPoints — trajectory filtering
ST_removeDriftPoints removes points that deviate significantly from the expected movement pattern. It handles two types of anomalies:
Spatial drift caused by poor GPS signal quality
Speed anomalies caused by objects jumping between locations within a short time frame due to dense but imprecise sampling
For more information, see ST_removeDriftPoints.

Example
SELECT ST_removeDriftPoints(
ST_SetSRID(
ST_MakeTrajectory(
ARRAY_AGG(ROW(traj.arrival_time::TIMESTAMP, st_x(traj.pts)::DOUBLE PRECISION, traj.lat::DOUBLE PRECISION, traj.rowid)),
FALSE, '{"rowid"}'::cstring[]
), 4326
),
40, -- maximum speed threshold
10, -- minimum distance threshold
'1 minute'::INTERVAL -- minimum time interval
) FROM (
SELECT
time,
ST_makepoint(lon, lat) pts,
lat,
rowid
FROM point_table
WHERE time IS NOT NULL AND lon IS NOT NULL AND lat IS NOT NULL
ORDER BY rowid
) traj INTO trajectory_table;ST_Split — trajectory segmentation
ST_Split divides a trajectory into multiple sub-trajectories using geometric objects. It provides three segmentation modes:
| Mode | Description | When to use |
|---|---|---|
cut_point | Splits at an existing sampling point. Both resulting sub-trajectories include the split point. | Trajectory is too long and needs to be divided at a known point for analysis |
cut_edge | Splits at an interpolated point along a trajectory edge (not limited to existing sampling points). Both sub-trajectories include the interpolated point. | Dividing trajectories by fixed intervals such as time windows or spatial grids |
drop_edge | Removes a trajectory edge. The two endpoints of the removed edge each become the end of their respective sub-trajectories. | Removing stationary segments — for example, discarding periods when a shared bicycle is parked |
For more information, see ST_Split.

Example (remove edges longer than 10 spatial units in 2D)
WITH traj AS (
SELECT '{"trajectory":{"version":1,"type":"STPOINT","leafcount":19,...}}'::trajectory AS a
)
SELECT ST_Split(a, '{"drop_edge.spatial_distance_2d":10}') FROM traj;ST_Resample — trajectory resampling
ST_Resample corrects uneven point distribution across a trajectory. Uneven density typically results from noise-reduction preprocessing and can degrade the performance of local trajectory analysis.
Two resampling strategies are available:
| Strategy | Description | When to use |
|---|---|---|
add_point | Increases point density by interpolating new points | Detailed analysis such as density statistics or similarity matching |
drop_point | Decreases point density by removing points | Extracting long-term movement trends or simplifying the trajectory |
For more information, see ST_Resample.
Example (add interpolated points so consecutive points are no more than 5 minutes apart)
SELECT ST_Resample(ST_OnlyST(traj), '{"add_point.period_lesser":"5 minute"}')
FROM table;Trajectory simplification
Trajectory simplification (lossy compression) reduces the number of sampling points while preserving the overall movement shape. This decreases storage requirements and improves rendering performance.
Two simplification functions are available:
| Function | Algorithm | When to use | Reference |
|---|---|---|---|
ST_Compress | Douglas-Peucker | 2D trajectories where all sampling points lie on the same plane | ST_Compress |
ST_CompressSED | Synchronized Euclidean Distance (SED) | Spatiotemporal trajectories that include a time dimension | ST_CompressSED |
How the algorithms work
The Douglas-Peucker algorithm specifies a tolerance value — the maximum allowed deviation between the original and simplified trajectory. Starting from the endpoints, it iteratively identifies the point farthest from the simplified path, adds it back, and repeats until all remaining points fall within the tolerance. The algorithm operates in 2D and requires all points to lie on the same plane.

For spatiotemporal trajectories, applying the 2D Douglas-Peucker algorithm can produce incorrect results. When an object is stationary, its trajectory forms a vertical line along the time axis that collapses to a single point in 2D — causing the standard algorithm to drop one of the line's endpoints and distort the 3D structure. ST_CompressSED uses Synchronized Euclidean Distance (SED) instead of perpendicular Euclidean distance, which preserves the temporal dimension and produces accurate compression for spatiotemporal data.
Best practices
Remove drift points from ship trajectory data
To build an accurate ship navigation trajectory from AIS point data, construct a trajectory from the collected latitude and longitude values, remove GPS drift points, and save the cleaned trajectory.
SELECT
ST_removeDriftPoints(
ST_SetSRID(
ST_MakeTrajectory(
ARRAY_AGG(ROW(traj.arrival_time::TIMESTAMP, st_x(traj.pts)::DOUBLE PRECISION, traj.lat::DOUBLE PRECISION, traj.rowid)),
FALSE, '{"rowid"}'::cstring[]
), 4326
),
40,
10,
'1 minute'::INTERVAL
)
FROM (
SELECT
time,
ST_makepoint(lon, lat) pts,
lat,
rowid
FROM point_table
WHERE time IS NOT NULL
AND lon IS NOT NULL
AND lat IS NOT NULL
ORDER BY rowid
) traj INTO trajectory_table;Resample drone trajectory points and calculate point density
To analyze drone movement patterns, segment the trajectory into 5-minute intervals, resample the points within each interval, and calculate point density for use as input to a machine learning model.
SELECT
ST_Density(
ST_Resample(ST_OnlyST(traj),
'{"add_point.period_lesser":"5 minute"}'),
100, '30 minute'
)
FROM table;Simplify freight vehicle trajectories by removing long stationary edges
To focus analysis on active travel segments in freight vehicle trajectory data, remove long edges — which typically represent stationary periods — and generate shorter, analyzable sub-trajectories.
WITH traj AS (
SELECT
'{"trajectory":{"version":1,"type":"STPOINT","leafcount":19,"start_time":"2000-01-01 00:01:19.067179","end_time":"2000-01-01 03:24:25.946085","spatial":"LINESTRING(-100 -100 -100,-88.8925775739675 -86.6512698383691 -92.3767832526937,-79.6904716538265 -80.6515727923252 -84.2357598245144,-75.8435507711644 -73.7572890928326 -80.5007370118983,-70.6238425321256 -67.8213750167439 -74.5733173238113,-61.6014582272619 -61.0636760429479 -67.9874239303172,-56.1098577060426 -54.4264591250879 -64.5007972046733,-46.9800617334743 -49.4026757289345 -61.6160059720278,-41.7122942996211 -46.3224360072054 -56.5283147455193,-35.5646221285375 -38.1688933617746 -49.2775720101781,-31.7230528349367 -33.6970051738123 -44.1693710885011,-23.1585765127093 -26.5895827477798 -40.6539742602035,-16.7020264320696 -21.6133877349397 -37.3055470525287,-12.1044529232507 -14.1236051704424 -28.2295028120279,-3.77185660181567 -7.74744770256802 -24.3842111621052,0.488159407706304 -3.68223926316326 -19.9478872027248,6.33406881305078 4.54123636645575 -15.0410129944794,15.6666049417108 10.5611746329814 -11.2770220567472,14 11 -10)","timeline":["2000-01-01 00:01:19.067179","2000-01-01 00:12:36.116007","2000-01-01 00:23:53.164835","2000-01-01 00:35:10.213663","2000-01-01 00:46:27.262491","2000-01-01 00:57:44.311319","2000-01-01 01:09:01.360147","2000-01-01 01:20:18.408975","2000-01-01 01:31:35.457803","2000-01-01 01:42:52.506631","2000-01-01 01:54:09.555459","2000-01-01 02:05:26.604287","2000-01-01 02:16:43.653115","2000-01-01 02:28:00.701943","2000-01-01 02:39:17.750771","2000-01-01 02:50:34.799599","2000-01-01 03:01:51.848427","2000-01-01 03:13:08.897255","2000-01-01 03:24:25.946085"]}}'::trajectory AS a
)
SELECT ST_Split(a, '{"drop_edge.spatial_distance_2d":10}') FROM traj;