Metadata-Version: 2.4
Name: rfdf
Version: 0.1.0
Summary: Hardware-agnostic RF direction finding, signal classification, and phased-array research platform
Project-URL: Homepage, https://github.com/ernesto01louis/rf-direction-finding
Project-URL: Documentation, https://github.com/ernesto01louis/rf-direction-finding
Project-URL: Issues, https://github.com/ernesto01louis/rf-direction-finding/issues
Project-URL: Changelog, https://github.com/ernesto01louis/rf-direction-finding/blob/main/CHANGELOG.md
Author-email: Louis <louis_ernesto@aol.com>
License: Apache-2.0
License-File: LICENSE
Keywords: direction-finding,doa,phased-array,research,rf,sdr,signal-classification
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.11
Requires-Dist: numpy>=1.26
Requires-Dist: platformdirs>=4
Requires-Dist: pydantic-settings>=2.3
Requires-Dist: pydantic>=2.7
Requires-Dist: rich>=13.7
Requires-Dist: scipy>=1.13
Requires-Dist: sigmf>=1.2
Requires-Dist: structlog>=24
Requires-Dist: typer>=0.12
Provides-Extra: all
Requires-Dist: ai-edge-torch>=0.2; extra == 'all'
Requires-Dist: ai-orchestrator-client<0.2,>=0.1.1; extra == 'all'
Requires-Dist: coremltools>=8.0; extra == 'all'
Requires-Dist: fastapi>=0.115; extra == 'all'
Requires-Dist: h5py>=3.11; extra == 'all'
Requires-Dist: hamlib-py>=4.5; extra == 'all'
Requires-Dist: httpx>=0.27; extra == 'all'
Requires-Dist: modal>=0.65; extra == 'all'
Requires-Dist: necpp>=1.7; extra == 'all'
Requires-Dist: onnx>=1.17; extra == 'all'
Requires-Dist: onnxruntime>=1.20; extra == 'all'
Requires-Dist: pyadi-iio>=0.0.18; extra == 'all'
Requires-Dist: pynec>=1.7; extra == 'all'
Requires-Dist: runpod>=1.7; extra == 'all'
Requires-Dist: scikit-learn>=1.5; extra == 'all'
Requires-Dist: scikit-rf>=1.2; extra == 'all'
Requires-Dist: skypilot[aws,gcp]>=0.7; extra == 'all'
Requires-Dist: soapysdr>=0.8; extra == 'all'
Requires-Dist: torch>=2.5; extra == 'all'
Requires-Dist: torchsig>=2.0; extra == 'all'
Requires-Dist: torchvision>=0.20; extra == 'all'
Requires-Dist: uhd>=4.7; extra == 'all'
Requires-Dist: uvicorn[standard]>=0.32; extra == 'all'
Requires-Dist: vastai>=0.2; extra == 'all'
Requires-Dist: websockets>=13; extra == 'all'
Provides-Extra: all-compute
Requires-Dist: modal>=0.65; extra == 'all-compute'
Requires-Dist: runpod>=1.7; extra == 'all-compute'
Requires-Dist: skypilot[aws,gcp]>=0.7; extra == 'all-compute'
Requires-Dist: vastai>=0.2; extra == 'all-compute'
Provides-Extra: all-hardware
Requires-Dist: hamlib-py>=4.5; extra == 'all-hardware'
Requires-Dist: httpx>=0.27; extra == 'all-hardware'
Requires-Dist: pyadi-iio>=0.0.18; extra == 'all-hardware'
Requires-Dist: soapysdr>=0.8; extra == 'all-hardware'
Requires-Dist: uhd>=4.7; extra == 'all-hardware'
Provides-Extra: antenna
Requires-Dist: necpp>=1.7; extra == 'antenna'
Requires-Dist: pynec>=1.7; extra == 'antenna'
Requires-Dist: scikit-rf>=1.2; extra == 'antenna'
Provides-Extra: api
Requires-Dist: fastapi>=0.115; extra == 'api'
Requires-Dist: uvicorn[standard]>=0.32; extra == 'api'
Requires-Dist: websockets>=13; extra == 'api'
Provides-Extra: compute-modal
Requires-Dist: modal>=0.65; extra == 'compute-modal'
Provides-Extra: compute-runpod
Requires-Dist: runpod>=1.7; extra == 'compute-runpod'
Provides-Extra: compute-skypilot
Requires-Dist: skypilot[aws,gcp]>=0.7; extra == 'compute-skypilot'
Provides-Extra: compute-vastai
Requires-Dist: vastai>=0.2; extra == 'compute-vastai'
Provides-Extra: crosscheck
Requires-Dist: matplotlib>=3.5; extra == 'crosscheck'
Requires-Dist: pyargus>=1.0; extra == 'crosscheck'
Provides-Extra: dev
Requires-Dist: commitizen>=3; extra == 'dev'
Requires-Dist: hypothesis>=6; extra == 'dev'
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pre-commit>=4; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest-cov>=5; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.7; extra == 'dev'
Requires-Dist: types-pyyaml; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.27; extra == 'docs'
Provides-Extra: geometry-grbl
Requires-Dist: httpx>=0.27; extra == 'geometry-grbl'
Provides-Extra: ml
Requires-Dist: h5py>=3.11; extra == 'ml'
Requires-Dist: scikit-learn>=1.5; extra == 'ml'
Requires-Dist: torch>=2.5; extra == 'ml'
Requires-Dist: torchsig>=2.0; extra == 'ml'
Requires-Dist: torchvision>=0.20; extra == 'ml'
Provides-Extra: ml-coreml
Requires-Dist: coremltools>=8.0; extra == 'ml-coreml'
Provides-Extra: ml-hailo
Provides-Extra: ml-onnx
Requires-Dist: onnx>=1.17; extra == 'ml-onnx'
Requires-Dist: onnxruntime>=1.20; extra == 'ml-onnx'
Provides-Extra: ml-tflite
Requires-Dist: ai-edge-torch>=0.2; extra == 'ml-tflite'
Provides-Extra: orchestrator
Requires-Dist: ai-orchestrator-client<0.2,>=0.1.1; extra == 'orchestrator'
Provides-Extra: rotator-antrunner
Requires-Dist: httpx>=0.27; extra == 'rotator-antrunner'
Provides-Extra: rotator-hamlib
Requires-Dist: hamlib-py>=4.5; extra == 'rotator-hamlib'
Provides-Extra: sdr-pluto
Requires-Dist: pyadi-iio>=0.0.18; extra == 'sdr-pluto'
Provides-Extra: sdr-soapy
Requires-Dist: soapysdr>=0.8; extra == 'sdr-soapy'
Provides-Extra: sdr-uhd
Requires-Dist: uhd>=4.7; extra == 'sdr-uhd'
Description-Content-Type: text/markdown

# rf-direction-finding

[![CI](https://github.com/ernesto01louis/rf-direction-finding/actions/workflows/ci.yml/badge.svg)](https://github.com/ernesto01louis/rf-direction-finding/actions/workflows/ci.yml)
[![Coverage](https://codecov.io/gh/ernesto01louis/rf-direction-finding/branch/main/graph/badge.svg)](https://codecov.io/gh/ernesto01louis/rf-direction-finding)
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![PyPI](https://img.shields.io/badge/pypi-not--yet--published-lightgrey)](#)

> Hardware-agnostic RF direction finding, signal classification, and phased-array research.

## What this is

`rfdf` is a Python platform for RF direction-finding (DOA), signal classification, and
phased-array experimentation. It is **hardware-agnostic** by design: every SDR, rotator,
antenna geometry, and compute provider sits behind an abstract interface (the HAL). The
B210 + AntRunner reference set is the *first concrete validation* of the abstractions, not
the system itself. A user with a HackRF, an RTL-SDR, or just a directory of SigMF files
is a first-class user.

`rfdf` runs **standalone** without `ai-orchestrator`. Installing the `[orchestrator]`
extra makes it a consumer of [`ernesto01louis/ai-orchestrator`](https://github.com/ernesto01louis/ai-orchestrator),
adding evidence-bundle production, Hindsight memory writes, L5 vault notes,
planner-dispatched GNU Radio flowgraphs, and ntfy alerts.

> **Validate RF research workflows on canned data before buying €8500 of gear.**

## Status

**v0.1.0 — first stable release (Stage 7: orchestrator integration + REST
API).** Stage 7 closes the build: an optional, lazy-imported integration with
[`ai-orchestrator`](https://github.com/ernesto01louis/ai-orchestrator) —
consumer registration, citation-grade evidence bundles, Hindsight memory
writes, L5 vault notes, planner-dispatched GNU Radio flowgraphs, and ntfy
alerts — plus a standalone REST API (`rfdf api serve`) that doubles as the
orchestrator's capability callback target. The platform remains
**standalone-first**: `pip install rfdf` is a complete DOA + classification +
capture platform with no orchestrator awareness; the `[orchestrator]` extra is
a bonus, never a baseline. Prior stages: `v0.1.0-alpha` reference hardware
backends (USRP B210, AntRunner, GRBL rails, RTL-SDR/KrakenSDR contrib),
`v0.1.0-beta` the operator-facing software ecosystem (Ansible / Kasm /
Guacamole / monitoring, hosted *alongside* the platform, never a dependency).
With `v0.1.0` the public API is stable under SemVer. See
[docs/standalone-vs-orchestrator.md](docs/standalone-vs-orchestrator.md),
[docs/orchestrator/](docs/orchestrator/), and [ROADMAP.md](ROADMAP.md).

## Install (zero hardware path)

```bash
pip install rfdf                 # standalone — complete without an orchestrator
pip install rfdf[orchestrator]   # + optional ai-orchestrator integration
```

The base install pulls only platform-essential dependencies (NumPy, SciPy, Pydantic,
Typer, Rich, sigmf, structlog, platformdirs). **Zero RF or ML dependencies are required
to use the platform.** Hardware and compute providers live behind extras and entry points.

## Install (with hardware / compute extras)

| Extras | What it pulls in |
|---|---|
| `[sdr-uhd]` | Ettus UHD (B210 / B200mini / X-series) |
| `[sdr-pluto]` | pyadi-iio (PlutoSDR) |
| `[sdr-soapy]` | SoapySDR (HackRF, LimeSDR, others) |
| `[rotator-hamlib]` | hamlib-py (Yaesu / SPID / generic rotctld) |
| `[ml]` | PyTorch + TorchSig + scikit-learn |
| `[ml-onnx]` | ONNX Runtime for portable inference |
| `[compute-runpod]` | RunPod GPU rental |
| `[compute-modal]` | Modal serverless GPU |
| `[compute-vastai]` | Vast.ai marketplace GPU |
| `[compute-skypilot]` | SkyPilot multi-cloud GPU |
| `[orchestrator]` | `ai-orchestrator-client` integration |
| `[api]` | FastAPI + uvicorn (REST + WebSocket) |
| `[antenna]` | scikit-rf + PyNEC for antenna modelling |
| `[dev]` | Test + lint + type-check toolchain |
| `[all-hardware]` | All SDR + rotator extras together |
| `[all-compute]` | All compute backends together |
| `[all]` | The kitchen sink (ML + API + antenna + hardware + compute + orchestrator) |

## Documentation

| Doc | What's in it |
|---|---|
| [VISION.md](VISION.md) | Why this exists, the principles, when-in-doubt questions |
| [ARCHITECTURE.md](ARCHITECTURE.md) | Layered design, HAL contracts, backend discovery, config precedence |
| [ROADMAP.md](ROADMAP.md) | Stages 1–7 with status + acceptance criteria |
| [CLAUDE.md](CLAUDE.md) | Working conventions (used by AI coding assistants) |
| [CONTRIBUTING.md](CONTRIBUTING.md) | Dev setup, branch flow, commit conventions |
| [SECURITY.md](SECURITY.md) | Threat model, secret handling, EIRP enforcement |
| [CHANGELOG.md](CHANGELOG.md) | Per-release changes |

## License + acknowledgments

[Apache-2.0](LICENSE). Matches `ai-orchestrator` and `aero-research-platform`.

This project builds on the work of many upstream RF and ML communities. Specific
attributions live in [docs/acknowledgments.md](docs/) once that document is populated
(Stage 3+).
