Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Bearing Only Localization

ASecurity

Use when you must locate a stationary emitter from passive angle-of-arrival bearing lines measured at known observer positions. Build the linearized bearing equations sin(beta_i)*(x - xi) - cos(beta_i)*(y - yi) = 0 per observer, solve the Stansfield closed-form weighted least squares for the two-dimensional emitter fix with an equal-angle first pass and a distance-weighted second pass, and read the fix covariance error ellipse plus the per-bearing residual angles. Produces the emitter positio...

2 stars
0 votes
0 copies
0 views
Added 9/27/2026
ai-agentspythongoangular

Works with

claude code

Security Analysis

A100/100

Scanned 9/27/2026

Install to Claude Code

$npx -y skills add ashfordeOU/aero-agent-skills --skill bearing-only-localization --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Bearing Only Localization?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Bearing Only Localization
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ashfordeou-bearing-only-localization/badge)](https://www.skillsdirectory.com/skills/ashfordeou-bearing-only-localization)

More formats (shields.io, HTML) on the badges page.

Download with Pro
Files
SKILL.md
---
name: bearing-only-localization
description: "Use when you must locate a stationary emitter from passive angle-of-arrival bearing lines measured at known observer positions. Build the linearized bearing equations sin(beta_i)*(x - xi) - cos(beta_i)*(y - yi) = 0 per observer, solve the Stansfield closed-form weighted least squares for the two-dimensional emitter fix with an equal-angle first pass and a distance-weighted second pass, and read the fix covariance error ellipse plus the per-bearing residual angles. Produces the emitter position fix, the 1-sigma error ellipse, the per-bearing residuals and the observer-geometry dilution verdict. Trigger: bearing-only-localization, angle-of-arrival-triangulation, stansfield-weighted-least-squares, bearing-line-intersection, emitter-fix-covariance, per-bearing-residual, observer-geometry-dilution."
license: Apache-2.0
compliance: STANDARDS-REF
standards:
  - id: arp4754a
    reference-only: true
gated: false
domain: gnc-autonomy
pack: navigation
compatibility: "agentskills.io SKILL.md; any SKILL host (Claude Code, Hermes, OpenClaw)"
metadata:
  domain: gnc-autonomy
  subdomain: navigation
  tags: [bearing-only-localization, angle-of-arrival-triangulation, stansfield-weighted-least-squares, bearing-line-intersection, emitter-fix-covariance, per-bearing-residual, observer-geometry-dilution]
  version: 0.1.0
  author: Aero Agent Skills
---

# Bearing-Only Localization (gnc-autonomy/navigation/bearing-only-localization)

Use when you must locate a stationary emitter from passive
angle-of-arrival bearing lines measured at known observer positions:
each observer measures the direction to the emitter, never a range, and
the batch of N bearing lines is fused into one static two-dimensional
fix. This leaf implements the classical Stansfield closed-form weighted
least squares in pure Python, stdlib only, with no RNG and no imports
beyond math. It pairs with gnc-autonomy/navigation/dilution-of-precision
for geometry quality reads on navigation problems and with the
kalman-filter-design and estimation-filtering leaves for the recursive
tracking problems this leaf deliberately does not touch. The emitter is
stationary, the observers sit at known fixed positions and all bearings
belong to a single epoch: batch fix only, no time recursion.

## Domain quick reference

- Bearing line: observer i at o_i = (xi, yi) in m, measured bearing
  beta_i in degrees from the +x axis toward +y, in [0, 360), pointing at
  the emitter z = (x, y). The line equation is
  sin(beta_i)*(x - xi) - cos(beta_i)*(y - yi) = 0, written with the unit
  line normal g_i = (sin beta_i, -cos beta_i) as g_i . z = g_i . o_i.
  Stacking N rows gives A z = b; A is N x 2 and every row is a unit
  vector, so the normals carry no range information.
- Stansfield pass 1, equal-angle weights: sigma_i is the 1-sigma bearing
  error in degrees, converted to radians inside as sigma_i * pi/180.
  With W_ii = 1/sigma_i^2 the first estimate is the exact closed form
  z1 = (A^T W A)^-1 A^T W b with the 2x2 inverse of the symmetric normal
  matrix.
- Stansfield pass 2, range weights: r_i = |z1 - o_i| and
  W_ii = 1/(sigma_i^2 * r_i^2). An angular error sigma_i on a line at
  range r_i displaces the line cross-range by about sigma_i * r_i, so
  the position-domain weight of the line falls as 1/r_i^2 and distant
  lines are down-weighted. The final fix is z2.
- Fix covariance: C = (A^T W A)^-1 evaluated with the pass-2 weights, a
  symmetric 2x2 matrix in m^2.
- 1-sigma error ellipse: eigenvalues lambda_max >= lambda_min > 0 of C
  give the semi-axes a = sqrt(lambda_max) and b = sqrt(lambda_min) in m;
  the major-axis orientation is 0.5*atan2(2*C01, C00 - C11) wrapped into
  [-180, 180) degrees.
- Per-bearing residual angle: the bearing predicted at the fix is
  beta_hat_i = atan2(y - yi, x - xi) in [0, 360); the residual is
  delta_i = wrap180(beta_i - beta_hat_i), the signed angular leftover of
  line i after the fix, and the residual RMS is the RMS of those wrapped
  values.
- Observer-geometry dilution: with S = sum_i g_i g_i^T the Gram matrix
  of the unit normals, d = 1/sqrt(lambda_min(S)), dimensionless. d = 1
  exactly for any orthogonal pair of lines; three lines spread around
  the emitter give d < 1 because the redundancy beats the orthogonal
  two-line baseline; near-parallel lines push lambda_min(S) toward 0 and
  d large. Verdicts: d <= 1.05 good observer spread, d < 2.5 moderate,
  d >= 2.5 poor (near-parallel bearing lines).
- Three-dimensional refinement: observer i at (xi, yi, zi) measures
  azimuth (degrees from +x toward +y) and elevation (degrees above the
  horizontal); the unit line of sight is u_i = (cos el * cos az, cos el
  * sin az, sin el) and the residual e_i = u_i x (z - o_i) is driven to
  zero by the damped Gauss-Newton step (J^T J + mu I) dz = -J^T e with
  mu = 1e-12 * trace(J^T J)/3.
- Units: distances in m, angles in degrees at the interface, radians
  inside the module.

## Workflow

1. Assemble the bearing-line measurement set: the observer positions
   (xi, yi), the measured bearing beta_i from each observer to the
   emitter in degrees (bearing_deg computes it toward a known target)
   and the per-line 1-sigma bearing error sigma_i in degrees. At least
   two observers with distinct bearing lines are required.
2. Form the linearized bearing equations and solve the equal-angle
   first pass: per observer sin(beta_i)*(x - xi) - cos(beta_i)*(y - yi)
   = 0, stacked as A z = b, weighted with W_ii = 1/sigma_i^2 and solved
   by wls_fix pass 1, giving the first estimate z1 (pass1_x_m,
   pass1_y_m). A singular normal matrix (parallel or coincident bearing
   lines) raises ValueError here.
3. Run the Stansfield distance-weighted second pass: pass-1 distances
   r_i = |z1 - o_i|, weights W_ii = 1/(sigma_i^2 * r_i^2), final fix z2
   (x_m, y_m) and the fix covariance C = (A^T W A)^-1 in m^2, all
   returned by the same wls_fix call with sigma_deg given (ranges_m,
   iterations 2). Without sigma_deg the solver returns the
   geometry-only unweighted fix with iterations 1.
4. Read the 1-sigma error ellipse of the fix covariance with
   error_ellipse: semi-major a, semi-minor b and the major-axis
   orientation in degrees, wrapped to [-180, 180).
5. Compute the per-bearing residual angles, measured minus the bearing
   predicted at the fix and wrapped to [-180, 180) degrees, with
   residual_angles_deg, and their RMS with residual_rms_deg. Residuals
   near zero with an RMS well below sigma mean the line set is
   consistent with the fix.
6. Assess the observer geometry with geometry_dilution_factor and read
   the observer-geometry dilution verdict from dilution_verdict (good
   observer spread, moderate, or poor near-parallel lines). Reject or
   flag the fix when the verdict is poor.
7. Optionally refine the fix in three dimensions with
   refine_3d_gauss_newton when azimuth and elevation angles are
   available at each of at least three observers: start from the 2-D fix
   lifted to z = 0 and iterate the damped normal step to the 3-D
   emitter position.
8. Close out with the deterministic contract test
   scripts/test_bearing_only_localization.py, which pins every worked
   output above and the ValueError rejections.

## Worked example

Three observers on a 1 km right triangle at (0, 0), (1000, 0) and
(0, 1000) m localize an emitter near (300, 400) m. The measured
bearings are the exact observer-to-emitter bearings corrupted by fixed
deterministic offsets (+0.5, -0.3, +0.2 deg), sigma 0.5 deg per line.
Module outputs (stdlib math, closed form, deterministic):

- Geometry: observer-to-emitter ranges 500.000, 806.226 and 670.820 m;
  true bearings 53.130102, 150.255119 and 296.565051 deg; measured
  bearings 53.630102, 149.955119 and 296.765051 deg.
- Pass-1 fix (equal-angle weights 1/sigma^2): (299.178622, 405.821689)
  m, error 5.879347 m against the truth, with pass-1 ranges to the fix
  504.182, 809.841 and 665.249 m.
- Final Stansfield fix (range weights 1/(sigma^2 * r^2)):
  (299.150033, 405.988514) m, error 6.048532 m, 2 passes: the range
  re-weighting moves the fix by less than 0.2 m on this spread
  geometry.
- Fix covariance C = [[16.195587, 1.677004], [1.677004, 25.693501]]
  m^2; the 1-sigma error ellipse has semi-major 5.097147 m, semi-minor
  3.988506 m and orientation 80.275145 deg, consistent with the about
  6 m fix error.
- Per-bearing residual angles at the final fix (measured minus the
  bearing predicted at the fix): +0.014509, +0.037982 and +0.034776
  deg, residual RMS 0.030890 deg: after the fix every line keeps a
  small angular leftover, well below the 0.5 deg sigma.
- Observer-geometry dilution factor d = 0.957062, verdict good observer
  spread: the three normals spread around the emitter condition the
  line set better than an orthogonal pair (d = 1).
- Weighting sanity: raising sigma of line 1 to 10 deg with the others
  at 0.5 pulls the fix to (300.194425, 404.784548) m, error 4.788497
  m, toward the two-line intersection of the remaining lines.
- Optional 3-D Gauss-Newton refinement (bounded, exact azimuth and
  elevation): observers at z = 0, emitter (300, 400, 50) m, start
  (280, 380, 60) m refines to (300.000000, 400.000000, 50.000000) m in
  2 iterations with residual norm 1.2e-13.

## Verification

- Confirm wls_fix on the noisy worked set returns pass-1
  (299.178622, 405.821689) and final (299.150033, 405.988514) within
  1e-6 m, with both fix errors inside the 0-50 m expectation for
  sub-degree noise on 1 km baselines.
- Confirm the covariance entries 16.195587, 1.677004 and 25.693501
  m^2 and the ellipse semi-axes 5.097147 m, 3.988506 m at orientation
  80.275145 deg.
- Confirm the per-bearing residuals +0.014509, +0.037982 and +0.034776
  deg with residual RMS 0.030890 deg, and the dilution factor 0.957062
  with the good observer spread verdict.
- Confirm the closed-form identities: noiseless exactness (fix returns
  the emitter, residuals zero), trace(C) = a^2 + b^2 and
  det(C) = a^2 * b^2 within 1e-12 relative, sigma x 2 scaling both
  semi-axes by 2, pass invariance on equal observer ranges, the
  weighting pull of a high-sigma line, d = 1 for an orthogonal pair and
  d < 1 for the three-line set.
- Confirm ValueError rejection of non-physical inputs: fewer than two
  observers, bearing or sigma count mismatches, non-finite coordinates,
  bearings or sigma, sigma <= 0, a singular normal matrix (parallel or
  coincident bearing lines), an observer within 1e-9 m of the pass-1
  fix, an indefinite covariance in error_ellipse, a singular Gram
  matrix in geometry_dilution_factor, and in refine_3d_gauss_newton
  fewer than three observers, an elevation outside [-90, 90],
  max_iters below 1 and non-convergence within max_iters.
- Run the contract test offline: python3
  scripts/test_bearing_only_localization.py (35 tests, deterministic).

## Related leaves

- gnc-autonomy/navigation/gnss-pseudorange-positioning: receiver fixes
  from satellite ranges with a clock offset, the range-based neighbor
  of this angle-only fix.
- gnc-autonomy/navigation/dilution-of-precision: geometry quality reads
  (DOP values) for navigation measurement sets.
- gnc-autonomy/navigation/navigation-frames: ECEF/NED/WGS-84 frame
  conventions for observer and emitter coordinates.
- gnc-autonomy/estimation-filtering/extended-kalman-filter: recursive
  state estimation of a moving target from sequential range and bearing
  measurements over time, the tracking alternative to this batch
  angle-only fix.
- gnc-autonomy/guidance/collision-course-guidance: the constant-bearing
  closing triangle of pursuit guidance, which is a velocity-pointing
  geometry and not a bearing-line localization operation.

## Pitfalls

- Treating the dilution factor as an accuracy number: d describes
  observer geometry only; the fix accuracy also scales with sigma and
  range through the covariance C = (A^T W A)^-1. Read d for the verdict
  and C for the error ellipse.
- Fusing nearly parallel bearing lines: near-parallel lines push the
  normal Gram matrix toward singular, d >= 2.5 (poor spread) and the
  fix covariance blows up along the weak direction, so the ellipse
  semi-major axis flags the unobservable axis long before the fix looks
  wrong.
- Feeding rounded bearings: the measured bearings enter as the fixed
  values at full precision; rounding them to a few decimals before the
  solve shifts the fix by about range times the rounding angle, which
  can exceed the covariance ellipse size on 1 km baselines.
- Expecting the range-weighted second pass to move the fix a lot: on
  well-spread geometry with comparable observer ranges the Stansfield
  re-weighting moves the fix by less than 0.2 m (worked example), while
  on geometry with one distant line it is exactly the correction that
  matters.
- Extending this leaf to moving emitters: the fix is batch-only for a
  stationary emitter at a single epoch; recursive bearing tracking over
  time belongs to the estimation-filtering leaves.
- Reading the ellipse as a hard guarantee: the covariance is the
  first-order linearized spread of the fix, consistent with the
  residual RMS but not a statement about systematic bias.

## Behavior contract (gate 3)

Run the deterministic contract test (stdlib unittest, offline):

    python3 scripts/test_bearing_only_localization.py

The test covers bearing_deg and the wrap contract, the worked noisy set
through both Stansfield passes (fix, fix error, pass-1 ranges,
covariance entries), the 1-sigma error ellipse with the trace and
determinant identities, sigma scaling, pass invariance on equal ranges,
the per-bearing residual angles and RMS, the weighting pull of a
high-sigma line, the dilution factor and verdict thresholds, noiseless
exactness, the 3-D Gauss-Newton refinement worked case, the ValueError
rejections across the module, and run-to-run determinism. All numeric
asserts are order-safe tolerances (assertAlmostEqual delta or
math.isclose), never exact float equality on computed sums.

## Compliance

- Standards referenced, not reproduced: ARP4754A (Guidelines for
  Development of Civil Aircraft and Systems) frames the system
  development context; the bearing-line and Stansfield relations above
  are standard engineering methodology, summary-only per
  standards-map.yaml.
- Revision note: ARP4754B (2023) supersedes ARP4754A; this skill keys to
  ARP4754A as the certification-baseline revision (FAA AC 20-174 cites A);
  see standards-map.yaml arp4754a.revision_decision.
- compliance: STANDARDS-REF, gated: false.

Attribution

ashfordeOUashfordeOU
View sourceMore from ashfordeOU →
SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Related Skills

Caveman

Ultra-compressed communication mode that cuts output tokens while keeping technical accuracy. Levels: lite, full, ultra and the wenyan variants. Use for /caveman, "caveman mode", "talk like caveman", "be brief" or "less tokens".

1074701 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

694821 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3351 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

691 votes

math-skill

A comprehensive mathematical reasoning skill for AI assistants — handles arithmetic to research-level problems with rigorous step-by-step reasoning, systematic verification, and transparent uncertainty handling

381 votes
View all in ai-agents →