将头顶飞过的航班实时投射到卧室天花板,这种将外部世界数据引入私人空间的尝试,本质上是一套跨学科的系统工程:从射频信号捕获到地理坐标转换,再到投影几何校正。本文提供一条从硬件组装到软件集成的完整技术路径,帮助搭建可运行的 ADS-B 航迹投影系统。
硬件层:信号捕获的基础设施
核心组件仅需三件:RTL-SDR 软件定义无线电模块(约 20-30 美元,R820T2 芯片方案)、1090MHz 专用天线、以及运行 Linux 的树莓派或旧笔记本。1090MHz 是 ADS-B Out 的国际标准频率,飞机每秒广播两次位置报文,包含经纬度、高度、速度、呼号等字段。
天线 placement 决定接收半径。室内窗边架设可捕获 30-50 公里范围内的航班;若将天线延伸至阳台或屋顶,配合低噪声放大器(LNA),接收范围可扩展至 150-200 公里。注意避开金属遮挡物和强电磁干扰源,如 Wi-Fi 路由器和微波炉。
信号解码:从射频到结构化数据
dump1090 是社区标准解码器,支持 RTL-SDR 硬件直通。运行 dump1090 --net --json 启动 JSON 数据流服务,默认在 30003 端口输出实时航班对象。每条记录包含 lat、lon、altitude、flight(呼号)、track(航向角)等字段。
建议启用 --metric 参数统一使用公制单位,避免后续单位转换错误。数据更新频率约每秒 1-2 次,取决于飞机距离和信号强度。对于投影系统,可设置过滤条件仅保留 lat 和 lon 有效且高度低于 15000 英尺的进近航班,减少数据量并聚焦可视目标。
坐标转换:从 WGS84 到本地 ENU
ADS-B 输出的是 WGS84 椭球坐标,需要转换为以接收点为中心的本地 ENU(东 - 北 - 上)笛卡尔坐标系,才能进行后续的投影计算。
转换公式采用地理坐标到本地切平面的映射:
import math
def wgs84_to_enu(lat, lon, alt, lat0, lon0, alt0):
"""将WGS84坐标转换为本地ENU坐标(单位:米)"""
R = 6371000 # 地球平均半径
# 转换为弧度
lat_rad, lon_rad = math.radians(lat), math.radians(lon)
lat0_rad, lon0_rad = math.radians(lat0), math.radians(lon0)
# 本地ENU坐标(简化球面近似,短距离误差<0.1%)
east = R * math.cos(lat0_rad) * (lon_rad - lon0_rad)
north = R * (lat_rad - lat0_rad)
up = alt - alt0
return east, north, up
以接收点为原点 (0, 0, 0),正东为 X 轴正方向,正北为 Y 轴正方向。 ceilings 投影通常只关心水平面分布,因此主要使用 (east, north) 二维坐标。
投影映射:天花板平面的几何校正
天花板投影面临两个核心问题:投影仪通常以倾斜角度向上投射,产生梯形畸变;需要将不规则的本地坐标范围映射到矩形投影画面。
步骤一:确定天花板投影区域
测量投影仪光心到天花板的垂直距离 h,以及投影仪镜头的水平 / 垂直偏移量。假设使用短焦投影仪在 3 米距离投射 2 米 ×1.5 米的画面,天花板上的投影区域是一个四边形(非矩形),需要建立从屏幕坐标 (u, v) 到世界坐标 (x, y, z) 的映射。
步骤二:单应矩阵(Homography)校正
对于平面天花板,3×3 单应矩阵 H 可将投影画面坐标映射到物理天花板坐标。通过四点标定法获取对应点:在天花板上标记四个角点,测量其物理坐标,同时在投影画面中获取对应的像素坐标,使用 OpenCV 的 findHomography 求解矩阵。
import cv2
import numpy as np
# 天花板物理坐标(米)
world_pts = np.array([[0, 0], [2, 0], [2, 1.5], [0, 1.5]], dtype=np.float32)
# 投影画面像素坐标
image_pts = np.array([[100, 100], [1820, 120], [1800, 980], [120, 960]], dtype=np.float32)
H, _ = cv2.findHomography(image_pts, world_pts)
步骤三:航迹到投影坐标的映射
将 ENU 坐标 (east, north) 归一化到投影区域的显示范围:
def enu_to_projected(east, north, range_m=50000):
"""将ENU坐标(米)归一化到[0,1]范围,range_m为最大显示半径"""
x_norm = (east / range_m + 1) / 2 # 映射到[0,1]
y_norm = (north / range_m + 1) / 2
return x_norm, y_norm
然后应用单应矩阵 H 将归一化坐标变换为投影画面像素坐标,通过投影仪输出。
实时渲染:WebGL 航迹可视化
建议使用浏览器作为渲染层,通过 WebSocket 接收 dump1090 数据,使用 Canvas 2D 或 WebGL 绘制航迹。核心渲染逻辑包括:
- 航迹缓存:维护一个字典
trails[flight_id] = [(x1,y1), (x2,y2), ...],存储每架飞机最近 30 个位置点 - 渐隐效果:使用半透明覆盖层
ctx.fillStyle = 'rgba(0,0,0,0.1)'实现航迹拖尾效果 - 方向指示:根据
track航向角绘制小箭头,增强可读性
性能优化要点:限制同时渲染的飞机数量(如最多 50 架),对超出投影范围的飞机进行裁剪,使用 requestAnimationFrame 确保 60fps 流畅度。
系统整合与调试清单
硬件检查:
- RTL-SDR 插入 USB 后运行
rtl_test检测硬件 - 天线连接牢固,SMA 接口无松动
- 树莓派供电充足(建议 2.5A 以上电源)
信号验证:
- 运行
dump1090 --interactive查看控制台航班列表 - 对比 FlightRadar24 验证位置数据准确性
- 检查 JSON 输出格式是否符合预期
投影校准:
- 投射网格测试图案到天花板,检查直线是否平直
- 从多个观察位置验证航迹位置与真实方位的一致性
- 调整
range_m参数匹配期望的视野范围
局限与扩展方向
信号接收受限于视距传播,高层建筑密集区域可能出现多径干扰导致位置跳变。投影精度依赖单应矩阵标定质量,若天花板有横梁或不平整,需改用网格变形(mesh warping)替代单应变换。
扩展方向包括:叠加气象雷达数据渲染云层、接入机场进近灯光系统数据、或使用多接收站实现多点定位(MLAT)提高精度。
参考来源:
- RTL-SDR 社区 ADS-B 教程与 dump1090 文档
- 投影映射几何校正技术综述(Perspective Correction Techniques for Projection Mapping)
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。