SYS//ACTIVE 00:00:00Z
REC UNCLASSIFIED
48.8566N 2.3522E
NAVIGATION SYSTEM

SoOPNav Signals of Opportunity Navigation

GPS-denied positioning using non-navigation RF signals.
When satellites go dark, the spectrum stays lit.

0 Signal Types
65m Median Error @ 53km/h
0 GPS Required
SIGNAL ACQUISITION

Signal Sources

Cellular

LTE / 5G NR

Timing advance and RSRP measurements from serving and neighbour cells. Weighted across towers rather than snapping to the strongest, because a stored cell coordinate is an observation centroid biased toward the road, not a mast position.

Range: 35km Acc: ~200m

WiFi

2.4 / 5 GHz

RSSI ranging against known access point positions — the tier that carries the fix in populated terrain. Each anchor is weighted by two independent path-loss ranges, so a well-surveyed AP outweighs a barely-observed one.

Range: 100m Acc: ~15m

Bluetooth LE

2.402-2.48 GHz

Short-range beacon ranging for indoor and near-field work. Devices that travel with you — a headset, a handheld radio, a watch — are detected as tag-alongs and excluded, since a beacon that never moves relative to the receiver carries no position information.

Range: 50m Acc: ~5m

Meshtastic

868 / 915 MHz LoRa

Mesh radio nodes with known positions relay coordinates over BLE from a paired radio. SNR and hop count provide distance bounds for position estimation.

Range: 20km Acc: ~500m

APRS

144.39 / 144.80 MHz · TNC or SDR

Amateur stations broadcast position-tagged beacons over VHF, giving long-range references where nothing else is in earshot. Two receive paths run at once: a Bluetooth TNC (SPP or BLE KISS), and an on-device Bell 202 AFSK demodulator that decodes AX.25 straight from RTL-SDR I/Q — four channel filters in parallel, HDLC framing and CRC in native code. On the standard TNC test recordings it decodes 2140 frames against multimon-ng's 1680 on identical audio.

Range: 100km+ Acc: ~2km

ADS-B (SDR)

1090 MHz

Aircraft transponder squitters decoded on-device by a native Mode S demodulator — no dump1090, no companion app, just an RTL-SDR over rtl_tcp. Aircraft positions provide coarse reference points at extended range, and the same contacts paint the airborne map layer.

Range: 300km+ Acc: ~5km

FM RDS

87.5-108 MHz

Commercial FM broadcasts carry an RDS subcarrier identifying each station. A native decoder — 19 kHz pilot PLL, 57 kHz coherent mix, Gardner timing recovery, block sync — recovers the PI code and matches it against bundled transmitter databases. CA / UK / US supported today.

Range: 80km Acc: ~3km

Orbcomm

137-138 MHz VHF

LEO messaging constellation. Public TLE ephemeris plus the Doppler curve on the downlink carrier yields ranging at orbital scale — infrastructure-free positioning where nothing terrestrial is mapped.

Range: 1500km+ Acc: ~8km

Amateur CubeSats

VHF / UHF

A curated catalog of amateur LEO satellites across FM, linear, CW, digital, SSTV and LRPT modes, each with a published downlink frequency — so the Doppler fit has one less unknown than Orbcomm. TLEs load from multiple CelesTrak groups independently, and a partial refresh still flies.

Range: 2000km+ Acc: ~5km

Method

01

Scan

Sweep every available band. Collect RSSI, timing and metadata from each source in range, smoothed per transmitter so a single bad sample cannot move the fix.

02

Correlate

Match observations against a reference database of transmitter positions. Outliers are dropped by geographic consensus, and a physics check rejects any short-range anchor too far away to have been heard at all.

03

Solve

A weighted centroid in native C++ fuses every tier at once, with per-type accuracy factors so a 10 km-distant beacon cannot outvote a nearby access point. The same core runs unchanged on Linux.

04

Damp

Speed caps, direction gates and honest holds reject teleports without freezing on real motion. When the RF picture goes sparse, the fix holds rather than inventing a jump.

05

Propagate

A fix describes where you were. A constant-velocity filter and a display propagator carry it forward to now — the single largest error term while driving is age, not geometry.

Field Performance

DRIVE // 33.1 km · 48 min · 84 % moving · 53 km/h median
Moving-cycle error against GPS truth, metres
Series p50 p90 p95 max >1 km
Displayed 652513405520.00 %
Raw solver output 9643963910410.13 %

The display chain takes 32 % off the solver's own median and 47 % off its p95 on identical inputs. Zero cycles past one kilometre across the whole leg; the worst single cycle in 48 minutes was 641 m.

8.7 m Stationary median Parked cycles, separate session
1.3 s Position lag Median −19 m behind at 53 km/h
980/980 Bit-exact replay Captured cycles re-solved at 0.0000 m
0 / 12 Contract violations Behavioural invariants, every build

A change that worsens accuracy fails the build, not a field test. Every compile replays a frozen real drive through the current engine and checks both reproduction and an accuracy envelope; the damper, the filter and the DSP ports carry their own gates alongside.

Inertial & Terrain

Heading Fusion

Rotation vector + magnetometer

The device's own heading is fused into the displayed bearing so direction survives the stretches where RF goes sparse and a fix-to-fix bearing would simply freeze. The app learns the circular offset between RF course and device heading while RF is trustworthy — one term that absorbs both the mounting rotation and magnetic declination, so no declination lookup is needed. It latches once proven and is invalidated only by the phone moving relative to the vehicle.

Pedestrian Dead Reckoning

Weinberg step-length model

Walking speed from step cadence and acceleration amplitude rather than from position differences, so it does not drift with the fix. The hardware step detector is used where it is trustworthy and a software accelerometer detector takes over where it is not — some chipsets batch or silently drop hardware steps — with an arbiter between them that makes double-counting structurally impossible.

External IMU

WitMotion WT901BLE · 9-axis

A phone strapped in a cradle is not always the best place to measure attitude. When a supported BLE inertial unit is present it supersedes the phone's sensors entirely — compass, magnetometer, accelerometer, gyro and the step feed behind dead reckoning all switch over. Discovery is by scan rather than by pairing, because these units never truly bond and rotate their addresses.

Terrain-Anchored Altitude

Barometer + DEM

Neither sensor can produce an altitude alone: a barometer is precise but drifts metres per hour with the weather, and a digital elevation model knows the ground but nothing about the overpass you are on. The filter estimates the bias between them rather than the altitude itself, updates robustly so one bad terrain sample cannot move it, and publishes a real 1-σ alongside the number. Verified on-device at 341 m against an independent survey's 342 m.

HARD RULE Inertial data and terrain elevation are display and gating inputs only. Neither enters the position solve — the elevation is sampled at the RF fix, so feeding it back would be circular. GPS is held to the same wall: it is recorded as a passive observer for evaluation, and is never an input to a fix, a gate or a hold.

Situational Awareness

Map Layers

Anchors · airborne · ground stations

Three selectable overlays: the anchor database around you, airborne contacts (drones and ADS-B aircraft, each drawn as itself and rotated to its track), and ground stations — APRS, Meshtastic and FM transmitters, each with its own shape so the source is readable without a legend. Stations currently feeding the fix are ringed, so the map shows not just what is out there but what the position is actually made of.

Drone Remote ID

ASTM F3411 / ASD-STAN prEN 4709-002

Broadcast Remote ID rides on Bluetooth LE and WiFi — radios the app already scans — so cooperative drones appear with their operator-declared position and identity at no extra cost. They are never used for positioning: Remote ID is unsigned, forgeable in a single packet and derived from the drone's own GNSS, so a recognised emitter is excluded from the anchor set unconditionally, whether or not you are looking at the layer.

GPS / RF Divergence

Spoofing and jamming indicator

Because the position does not come from satellites, it can arbitrate rather than merely suspect. When a real GPS fix and the RF fix disagree past a threshold for several consecutive cycles, the map says so outright. Mock-provider fixes are rejected from the comparison, and a divergent GPS reading never becomes the anchor — the disagreement is reported, not resolved in GPS's favour.

Multi-Device Sharing

SNLS · off by default

A cluster of phones on a shared hotspot sees more of the RF environment than any one of them. Peers advertise over mDNS and serve their scan snapshots on the LAN; one device fuses everything through the same engine it uses for its own signals. Peer contributions are geographically gated before they are trusted — a peer whose location cannot be corroborated from the receiver's own anchor cache is dropped rather than believed.

Interface

System Specifications

Platform Android 8.0+ (API 26-34)
Language Kotlin / Jetpack Compose
UI Framework Material 3, Dark Tactical Theme
Positioning Core Native C++, shared verbatim with a Linux daemon build
Position Algorithm RSSI-weighted centroid, per-type accuracy factors, geographic + physics outlier gates
Path Loss Model Log-distance with per-signal-type calibration
Display Chain Motion damper → constant-velocity filter → time-of-validity propagation
Signal DSP Native C++ — Mode S, FM RDS, Bell 202 AFSK, LEO Doppler
Altitude DEM-anchored barometric fusion with robust update and reported 1-σ
Inertial Heading fusion + pedestrian dead reckoning; phone or external BLE IMU
Reference Data ~27 M-record anchor database, bundled transmitter assets, public TLE catalogs
Transport Security Certificate pinning across leaf, intermediate and root
Verification Bit-exact engine replay + precision-regression gates on every build
Role of GPS Passive observer for evaluation only — never an input to a fix
License Proprietary

Download

Android APK available for sideloading, published under a verified Android developer identity — so it keeps installing as Google's developer-verification requirement rolls out (September 2026, worldwide 2027). Requires Android 8.0 or later. The SDR tiers additionally need an RTL-SDR and its driver app; everything else runs on an unmodified handset.

Get SoOPNav

About

SoOPNav is a research project exploring GPS-denied positioning through signals of opportunity. It fuses measurements from cellular, WiFi, Bluetooth LE, Meshtastic mesh radios, APRS digipeaters, ADS-B aircraft transponders, LEO satellite Doppler (Orbcomm and amateur CubeSats), and FM broadcast RDS to provide position fixes where satellite navigation is unavailable, jammed, or degraded.

The discipline the project holds itself to is as much the point as the fixes: GPS never enters the decision pipeline, every claim about accuracy comes from a logged drive rather than a model, and a change that makes positioning worse fails the build.

Part of DomainsProject.org — an initiative dedicated to building open datasets and tools for understanding the internet.