The Automatic Identification System (AIS) was designed for collision avoidance, not surveillance. Vessels broadcast their identity, position, course and speed every few seconds to a few minutes, depending on speed and class. Terrestrial receivers pick these up within roughly 40 nautical miles of the coast; satellite receivers fill in the open sea, with longer revisit times.
A “dark” period is any interval where we expected to hear from a vessel and did not. The naive approach — flag every gap longer than N hours — drowns analysts in noise. In a simulated North Sea dataset of 11,000 vessels over 30 days, a flat 6-hour threshold produced over 2,300 alerts per day. Almost all were coverage holes.
§01Step 1 — Model when you should have heard from it
The first step is to replace “time since last message” with “messages missed”. For each vessel and each segment of its track we estimate an expected reporting interval from its class, speed, and the receiver coverage of the area it was in. A gap is then scored by how many expected reports were missed, not its raw duration.
with pings as (
select
mmsi,
ts,
lat,
lon,
sog,
lag(ts) over w as prev_ts,
lag(lat) over w as prev_lat,
lag(lon) over w as prev_lon
from ais.positions
where ts >= now() - interval '30 days'
window w as (partition by mmsi order by ts)
)
select
p.mmsi,
p.prev_ts as gap_start,
p.ts as gap_end,
extract(epoch from p.ts - p.prev_ts) / 3600 as gap_hours,
st_distance(
st_point(p.prev_lon, p.prev_lat)::geography,
st_point(p.lon, p.lat)::geography
) / 1852 as gap_nm,
c.expected_interval_s
from pings p
join coverage.cells c
on c.h3 = h3_lat_lng_to_cell(p.prev_lat, p.prev_lon, 5)
where p.ts - p.prev_ts > make_interval(secs => 6 * c.expected_interval_s);The coverage table is the unsung hero. We aggregate receiver hits into an H3 grid and compute, per cell and per hour of day, the median interval between consecutive messages from all vessels. A gap inside a cell where everyone goes quiet is a coverage problem. A gap where everyone else keeps talking is interesting.
§02Step 2 — Score the gap in context
Candidate gaps then go through a scoring model. We deliberately use an interpretable additive score rather than a black box: analysts need to see why something was flagged, and the score must be defensible in a report.
| Feature | Weight | Rationale |
|---|---|---|
| Missed reports vs coverage baseline | 0.30 | Separates silence from blind spots |
| Implied speed across the gap | 0.20 | Unrealistic jumps suggest spoofing or loitering |
| Distance from expected route | 0.15 | Deviation from typical lanes for the vessel class |
| Proximity to other dark vessels | 0.15 | Possible ship-to-ship transfer |
| Port call history | 0.10 | Recent calls at ports of interest |
| Weather severity | −0.10 | Storms explain equipment drop-outs |
Weather enters with a negative weight. A gap during force-9 winds is less surprising, and showing that a factor reduced a score is just as useful to an analyst as showing what raised it.
- Candidate gaps (÷10)
- Flagged for analyst
§03Step 3 — Fuse with other feeds
A flagged gap is a lead, not a conclusion. Kimo Defense Intelligence attaches context automatically: nearby vessels during the gap, the last and next port calls, any open-source reporting that mentions the vessel name or IMO number, and — where available — imagery tasking windows that overlap the gap.
- Rendezvous candidates — other vessels that were dark in the same H3 cell within ±6 hours.
- Identity checks — changes of name, flag or MMSI before and after the gap.
- Pattern of life — whether this vessel has gone dark in the same area before.
§04Step 4 — Close the loop with analysts
Every flagged event lands in a queue where an analyst marks it as explained, of interest or false positive, with a free-text note. Those labels feed back into weight tuning each week. In the simulated deployment, the median time from gap end to analyst triage fell to seven minutes, and the false-positive rate dropped from 61% to 18% over six weeks of feedback.
The full pipeline runs on-premise, including the coverage model and the scoring service. Read how a (fictional) maritime authority deployed it in the anonymized case study, or explore simulated tracks in the map view of the demo.
- #Maritime
- #AIS
- #Anomaly detection
Writes about ADS-B, Alerting, Airspace, Maritime.
People, companies and figures in this article are illustrative; charts use simulated data. All aircraft data shown in Kimo is simulated.



