
# 无人机识别系统
[](https://github.com/AnwarDebes/drone-id/releases)
[](pyproject.toml)
[](LICENSE)


一个经过精选且标明来源的无人机**型号**参考目录,外加一个 API,它可以通过自由文本描述或结构化的特征集,将观察结果与已知型号进行匹配。
## 首先阅读:这是什么,以及它不是什么
该系统回答了一个问题:**“这是哪种型号的无人机?”** 它的设计确保了两个概念无法被忽视,且永远不会被混淆。
### 1. 是型号识别,而非操作者归属
该目录告诉你无人机*是什么*:它的型号、制造商,以及**生产**它的公司所在国家(`manufacturer_country`)。它绝不会告诉你无人机是*谁的*。
`manufacturer_country` 是型号的一个属性。它**不是**驾驶特定机架的人的国籍,并且在 schema 或 API 中刻意没有保留任何操作者、所有者或国籍字段。中国制造的 DJI、土耳其制造的 TB2 和美国制造的 MQ-9,都由许多不同国家的众多操作者驾驶。试图从型号推断操作者,正是这种设计拒绝犯下的错误。**操作者和归属国籍判定不在范围内**(请参阅下文的“不在范围内”)。
所以:这不是一个能证明是谁的无人机越过了边境的系统。它可以说“那看起来像一架 DJI Matrice 350 RTK”。它无法说出是谁在拿着遥控器。
### 2. 是一个目录,而不是传感器
这是一个数据库和匹配 API。它不是传感系统。它存储了某个型号*是否*支持 Remote ID,以及该型号的 RF、声音和视觉特征*是什么*样子的,以便单独的传感层可以根据它匹配观察结果。它不接收 Remote ID 广播、捕获 RF、运行雷达或对相机图像进行分类。这些需要硬件和带有标签的数据集,属于第二阶段的工作。
检测输入(Remote ID 负载字段、RF 频段列表、图像属性)旨在与目录条目进行匹配,但该项目从不模拟或伪造传感能力。特征匹配 endpoint 仅对**其他系统已经提取出的结构化特征**进行评分,而不是对原始信号。
## 包含的内容
- 带有 Alembic 迁移的 PostgreSQL 目录(`drone_models`)。
- FastAPI 应用:CRUD、丰富的过滤、语义搜索和结构化特征匹配。
- 基于模型描述和规格文本的 ChromaDB 语义搜索,默认使用多语言 embedding 模型。
- 包含三个路径的导入 pipeline(单一来源导入器、手动 YAML 整理,以及拒绝没有引用的条目的验证步骤)。
- 56 个完全注明来源的条目,涵盖九个制造商国家和从消费级到军用的范围,首先覆盖了 DJI 系列(占主导地位的市场):Mini、Air、Mavic、FPV 和企业级 Matrice / Agras 家族,以及 Autel、Skydio、Parrot、Yuneec、固定翼测绘平台(senseFly、WingtraOne、Quantum Systems),以及著名的 ISR / 打击平台(TB2、MQ-9、Global Hawk、ScanEagle、Heron、Wing Loong II 等)。运行 `python -m ingestion.audit` 查看实时细分。
- `SOURCES.md` 记录了每个数据源及其可靠性。
## 快速开始(无需 Docker)
该应用默认使用 SQLite 和离线 embedding 后端,因此无需任何外部服务即可运行。生产环境使用 PostgreSQL 和多语言模型(见下文)。
```
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt # core + dev
# 可选,用于真正的 semantic search:
# pip install -r requirements-semantic.txt
cp .env.example .env
# 首次运行的离线友好设置:
export EMBEDDING_BACKEND=hash CHROMA_MODE=persistent CHROMA_PATH=./chroma_data
alembic upgrade head # build the schema
python -m ingestion.seed --reset # validate + load the cited catalog + index
uvicorn app.main:app --reload # serve at http://127.0.0.1:8000
```
然后打开 http://127.0.0.1:8000/docs 访问交互式 API,或者:
```
curl localhost:8000/health
curl "localhost:8000/drones?manufacturer_country=CN"
curl -X POST localhost:8000/search/describe \
-H 'content-type: application/json' \
-d '{"text":"small white foldable camera quadcopter ~250g on 2.4GHz","limit":3}'
```
## 基于 PostgreSQL + ChromaDB 运行(生产形态)
```
docker compose up -d # starts postgres + chroma
cp .env.example .env # then set the two URLs below
```
在 `.env` 中:
```
DATABASE_URL=postgresql+asyncpg://drone:drone@localhost:5432/drone_id
CHROMA_MODE=http
CHROMA_HOST=localhost
CHROMA_PORT=8000
EMBEDDING_BACKEND=sentence_transformers
EMBEDDING_MODEL=paraphrase-multilingual-MiniLM-L12-v2
```
```
alembic upgrade head
python -m ingestion.seed --reset
uvicorn app.main:app --host 0.0.0.0 --port 8080
```
embedding 模型特意选用了多语言模型,因此其他语言的描述和查询也能被合理地嵌入。如果未安装语义技术栈或无法访问 Chroma,API 的其余部分将继续工作,而 `/search/describe` 会返回 503 并给出明确原因(请检查 `/health`)。
## API
| 方法 | 路径 | 认证 | 目的 |
|---|---|---|---|
| GET | `/` | - | 服务标语和范围声明 |
| GET | `/health` | - | 数据库 + 语义搜索状态 |
| GET | `/drones` | - | 列表 / 过滤目录 |
| GET | `/drones/{id_or_slug}` | - | 单个型号 |
| POST | `/drones` | admin | 创建一个型号 |
| PUT | `/drones/{id_or_slug}` | admin | 更新一个型号 |
| DELETE | `/drones/{id_or_slug}` | admin | 删除一个型号 |
| POST | `/search/describe` | - | 基于自由文本的语义搜索 |
| POST | `/match/signature` | - | 结构化特征匹配 |
`GET /drones` 上的过滤器:`manufacturer`、`manufacturer_country`、`category`、`airframe`、`freq_band`、`remote_id_supported`、`weight_min/max`、`mtow_min/max`、`q`(名称 + 别名),以及 `limit` / `offset`。
写入 endpoint 受 `X-Admin-Key` 请求头(`ADMIN_API_KEY`)中的共享密钥控制。这只是一个简单的门控,而不是完整的认证系统;在任何部署之前,请放置一个真正的身份认证层。
### `POST /match/signature`
接受结构化观察结果,并返回带有透明按组件细分的候选型号排名:
```
{
"freq_bands": ["2.4GHz", "5.8GHz"],
"remote_id_fields": {"present": true, "standard": "ASTM F3411"},
"visual_attributes": ["foldable", "quadcopter"],
"weight_estimate": {"value": 245, "tolerance": 60},
"size_estimate": {"value": 150, "tolerance": 80}
}
```
评分仅基于您实际提供的组件的加权平均值(freq 0.30,weight 0.20,size 0.20,remote_id 0.15,visual 0.15),因此稀疏的观察结果不会因为它无法测量的数据而受到惩罚。请参阅“不在范围内”中的重要限制:这仅匹配结构化特征,而非原始信号。
每个候选对象都带有型号的 `data_confidence`,因此您可以看到其规格有多可信,并且当前两个候选对象过于接近而无法自信地分开时,响应会将 `ambiguous` 设置为 `true`。这对于关键的系统非常重要:API 会展现不确定性,而不是断言一个单一的答案。
## 数据模型
只有一个表,`drone_models`。亮点:
- 身份:`model_name`、`aliases`、`manufacturer`、`manufacturer_country`(ISO 3166-1 alpha-2)、`category`、`airframe`、`slug`。
- 物理:`length_mm`、`width_mm`、`height_mm`、`diagonal_mm`、`weight_g`、`mtow_g`。
- 性能:`max_speed_kmh`、`range_km`、`endurance_min`、`max_altitude_m`、`max_payload_g`。
- 通讯:`control_freq_bands`、`video_freq_bands`、`control_protocol`、`gnss_support`。
- 检测特征:`remote_id_supported`、`remote_id_standard`、`radar_cross_section_class`、`acoustic_notes`、`visual_identifiers`。
- 来源:`sources`(`{field, url_or_citation, retrieved_at}` 的 JSON 数组)和 `data_confidence`(`verified` / `partial` / `unverified`)。
每个填充的规格字段都带有引用。未知字段留空(null),而不是进行估算。该目录是为 PostgreSQL(原生数组和 JSONB)设计并迁移的;相同的模型和迁移也可以在 SQLite 上运行,用于本地开发和测试。
## 导入
三个路径,全部汇聚于同一个经过验证的 `DroneCreate` 形态:
1. **单一来源导入器**(`ingestion/sources/`):制造商页面、FAA UAS、EASA。制造商/FAA/EASA 导入器目前是记录在案的脚手架(它们会抛出带有实现计划的 `NotImplementedError`,而不是返回虚构数据);手动 YAML 导入器已完全正常工作。
2. **手动整理**(`data/catalog/**.yaml`,每个型号一个文件):目前的主要路径。请参阅 `data/SCHEMA.md`。
3. **验证**(`app/validation.py`):拒绝任何在没有涵盖来源引用的情况下填充规格字段的条目。
```
python -m ingestion.seed --validate-only # parse + validate, touch nothing
python -m ingestion.seed --reset # rebuild catalog + index
python -m ingestion.seed --no-embed # DB only, skip ChromaDB
python -m ingestion.audit # coverage / confidence / citation snapshot
```
目录的大部分内容是通过对经过验证的网络研究构建的,这些研究以带引用的 JSON 格式记录在 `ingestion/research/` 中(作为审计跟踪保留),然后通过 `python -m ingestion.convert_research` 转换为经过验证的 YAML。该转换器是一个门控:它会剥离任何无法与引用相关联的字段,而不是猜测,因此只有带引用的数据才会被保留。选择以这种方式扩展目录,而不是通过爬虫,是刻意为之的:对于关键系统来说,经过验证和引用的数据胜过快速但脆弱的数据。
## 数据覆盖范围
来自 `python -m ingestion.audit` 的快照(56 个条目):
- 按类别:商用 16 个,消费级 15 个,军用打击 12 个,军用 ISR 7 个,VTOL 3 个,竞速 2 个,固定翼 1 个。
- 按制造商国家(生产国,绝非操作者):CN 30 个,US 13 个,TR 3 个,FR 2 个,CH 2 个,IL 2 个,RU 2 个,DE 1 个,IR 1 个。
- 置信度:89% 已验证(50/56),11% 部分(6/56)。在对主要来源进行第二轮重新验证后,仅存的“部分”条目是没有制造商或政府规格表的那些:CH-4、Wing Loong II、Lancet-3、Orlan-10、Shahed-136(开源情报估算)以及 Freefly Alta X(未发布官方高度/范围)。这些都是如实标记的,从不夸大。对于一个可能用于国防用途的系统来说,承认不确定性比虚假的自信更安全。
- 引用健康状况:每个填充的规格字段都有引用(种子程序强制执行此操作)。
国家的分布正是关键所在:它表明制造商国家只是型号的一个属性,仅此而已。同一机架由许多国家操作,这正是为什么操作者归属不在范围内的原因。
## 不在范围内(第二阶段:需要硬件和/或单独的机器学习工作)
这些是刻意不在这里构建的,设计上也不假装它们存在:
- **实时 RF、雷达和声音传感。** 需要硬件。目录存储用于匹配的特征描述符;它不捕获信号。
- **相机 + ML 检测/分类。** 一个单独的机器学习项目,需要带有标签的无人机图像数据集。目录仅存储 `visual_identifiers` 文本。
- **Remote ID 广播接收器/解码器。** 需要硬件和 RF。目录存储某个型号*是否*支持 Remote ID;实时解码是独立的工作。
- **针对真实捕获信号的 RF / 声音特征匹配。** `/match/signature` endpoint 仅基于结构化特征进行匹配。匹配真实捕获的信号需要带标签的信号数据集(RF 指纹、声音轮廓),而该项目中不存在这些数据集。
- **对检测到的无人机进行操作者/归属国籍判定。** 因“首先阅读”中所述的原因,在设计上不在范围内。
## 测试
```
pytest -q
```
所有 46 个测试均可离线通过(SQLite 加上哈希 embedder,无需任何服务)。该测试套件涵盖了评分逻辑、引用验证、schema 规则,以及针对种子目录对 API 的全面端到端通过(过滤器、语义搜索、特征匹配、管理员门控以及创建/更新/删除)。
## 项目布局
```
app/ FastAPI app: models, schemas, crud, scoring, search, routers
ingestion/ loader, seed CLI, validation use, per-source importers
data/catalog/ curated YAML, one file per model (the seed data)
migrations/ Alembic
tests/ unit + end-to-end
SOURCES.md data sources and reliability
data/SCHEMA.md YAML entry format
```