
WiFi-DensePose 数据库设计解析4 张表如何接住高频姿态数据流【免费下载链接】RuViewπ RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video.项目地址: https://gitcode.com/GitHub_Trending/wi/RuViewWiFi-DensePose 把普通 WiFi 信号变成姿态检测落库侧的真实压力是纳秒级 CSI 时序高频写入、多设备并发上报、按时间窗实时回放。这套数据库设计就是在回答怎么接住。数据从哪来、到哪去先看整体流向Wi-Fi 收发端经 CSI 相位净化与模态转换网络输出多人体姿态图中右侧的关键点序列即 pose_detections 表的内容数据链路很短收发端持续产出 CSI 帧先过相位净化再进模态转换网络输出每个目标人的关键点与置信度。落到关系模型上是一条单向流水线——设备表登记采集端会话表圈定一次采集的时间边界CSI 数据表以只追加方式落原始信号姿态检测表以只追加方式落模型输出。日常查询几乎只碰后两张高频表设备与会话属于低频维度表。这个分层直接决定了后面所有表的设计取向高频表做窄、做平低频表允许厚一些。逐表拆解每张表在解决什么问题设备表采集端如何认人设备表是采集端登记表一张设备一行写入频率最低。class Device(Base, UUIDMixin, TimestampMixin): __tablename__ devices name Column(String(255), nullableFalse) mac_address Column(String(17), uniqueTrue, nullableFalse) # 业务身份键 status Column(String(20), defaultinactive, nullableFalse) # 四态枚举 coordinates_x Column(Float, nullableTrue) # 部署坐标三列分开 config Column(JSON, nullableTrue) # 厂商自定义配置 # ...三个取舍值得注意。MAC 地址做唯一约束是刻意的重命名或换 IP 时以 MAC 为锚的数据关联不断链配合validates在应用层先把格式校验掉。坐标拆成三列而非打包进 JSON因为布点规划需要按坐标做范围计算。config 用 JSON 则因为不同厂商设备的固件参数差异极大硬建模只会频繁改表结构。会话表一次采集的时间盒会话表把一次采集圈成时间盒CSI 与检测明细都挂在它下面。class Session(Base, UUIDMixin, TimestampMixin): __tablename__ sessions started_at Column(DateTime(timezoneTrue), nullableTrue) ended_at Column(DateTime(timezoneTrue), nullableTrue) status Column(String(20), defaultactive, nullableFalse) device_id Column(UUID, ForeignKey(devices.id), nullableFalse) # 归属设备 total_frames Column(Integer, default0, nullableFalse) # 帧数计数 processed_frames Column(Integer, default0, nullableFalse) # 已处理计数 # ...核心设计是冗余计数total_frames 与 processed_frames 让这次采集处理到哪了变成对 sessions 单行的一次索引查询不用对明细表做全量 count。代价是计数器与明细可能短暂不一致设计上只在会话收尾时对账。config 与 meta_data 同样交给 JSON——采集参数随实验变化属于典型的可变结构。CSI 数据表原始信号的落地格式这张表是写入压力最大的地方一行对应一帧 CSI。class CSIData(Base, UUIDMixin, TimestampMixin): __tablename__ csi_data sequence_number Column(Integer, nullableFalse) # 设备内序号 timestamp_ns Column(Integer, nullableFalse) # 纳秒时间戳 device_id Column(UUID, ForeignKey(devices.id), nullableFalse) session_id Column(UUID, ForeignKey(sessions.id), nullableTrue) # 允许后补 amplitude Column(FloatArray, nullableFalse) # 幅度谱原生数组 phase Column(FloatArray, nullableFalse) # 相位谱原生数组 num_subcarriers Column(Integer, nullableFalse) # 子载波数量 processing_status Column(String(20), defaultpending, nullableFalse) # ...两个关键决定。第一幅度与相位用 PostgreSQL 原生数组类型而非拆行存储一帧信号必须原子地读完整拆行既让行数爆炸又破坏一帧一行的读取语义。第二timestamp_ns 用整型纳秒而非 DateTime绕开浮点秒的精度损失且整型比较与范围索引都更快。session_id 设为可空对应真实部署中信号先落库、会话边界后补挂的写入顺序。姿态检测表输出结果与版本追溯姿态检测表存的是模型输出不存中间态。class PoseDetection(Base, UUIDMixin, TimestampMixin): __tablename__ pose_detections frame_number Column(Integer, nullableFalse) # 帧号 timestamp_ns Column(Integer, nullableFalse) session_id Column(UUID, ForeignKey(sessions.id), nullableFalse) # 必须有归属 person_count Column(Integer, default0, nullableFalse) # 目标人数 keypoints Column(JSON, nullableTrue) # 关键点序列 bounding_boxes Column(JSON, nullableTrue) # 边界框 detection_confidence Column(Float, nullableTrue) # 检测置信度 pose_confidence Column(Float, nullableTrue) # 姿态置信度 model_version Column(String(50), nullableTrue) # 模型版本 # ...keypoints 与 bounding_boxes 用 JSON 是因为人数可变、结构嵌套拆成独立明细表查询时反而要做按人聚合的 N1 操作。三个 confidence 拆列存储让下游可以按不同阈值分别过滤漏检和姿态模糊而不必依赖一个笼统的 overall 值。model_version 逐行冗余是刻意冗余——模型升级后历史结果仍可按版本回放与对比。表与表之间怎么说话关系与约束关系结构是一棵以 Device 为根的单向树Device → Session → CSIData / PoseDetection。三处级联都声明为cascadeall, delete-orphan含义是删除设备会递归带走它的会话、CSI 与检测明细数据库层不留下指向已删设备的孤儿行。若没有这层约束删设备后查询会抛出外键违反明细表的孤儿行则永远无法被时间窗查询正确过滤——对时序数据来说这是最隐蔽的数据污染。一个刻意的不对称CSI 表的 session_id 可空检测表的 session_id 不可空。原始信号允许先落库再挂会话而检测结果必须带着归属出生——没有会话上下文的姿态输出无法被解释。约束侧置信度列被 CheckConstraint 锁在 [0,1] 区间person_count 与帧计数器锁为非负状态列一律用IN (...)白名单非法状态在入库前被数据库直接拒绝而不是等到查询时才暴露脏数据。生产环境踩坑指南索引、约束与审计给高频查询路径建覆盖索引。时间窗回放是主查询形态单列索引idx_csi_timestamp之外按device_id timestamp_ns的组合才是真实路径。验证方式EXPLAIN ANALYZE确认走了 Index Scan 且没有回表热点。状态机列必须加 IN 约束。状态流转错误是这类系统最常见的脏数据源。验证方式尝试写入白名单外的值确认被数据库拒绝而非应用层吞掉。幂等写入靠复合唯一约束。CSI 表用UniqueConstraint(device_id, sequence_number, timestamp_ns)拦重放进程重启后重发同一帧不会产生重复行。验证方式并发重放同一帧序列确认第二笔被唯一约束拒绝。审计表记状态快照而非流水文字。AuditLog 用 before_state / after_state 两个 JSON 列存变更前后快照配合resource_type resource_id联合索引定位变更对象。验证方式抽取一段事件序列回放确认能重建任意时刻的资源状态。约束与索引在模型层的典型写法__table_args__ ( Index(idx_csi_timestamp, timestamp_ns), UniqueConstraint(device_id, sequence_number, timestamp_ns, nameuq_csi_device_seq_time), CheckConstraint(frequency 0, namecheck_frequency_positive), )规模上去之后怎么办性能与扩展性数据类型选择。定长浮点信号一律用原生数组类型实测比 JSON 序列化更省空间且支持数组内下标操作JSON 只留给真正可变的结构配置、关键点、审计快照。判断标准一个字段的结构一年内不会变就不该用 JSON。分区策略。csi_data 与 pose_detections 是两张无限增长的表单表超过 5000 万行时按 timestamp_ns 做范围分区归档退化为按分区 DROP比 DELETE 快几个数量级。批量写入。高频路径禁止逐帧 insert按秒级时间片攒批用 executemany 提交把数据库交互次数压到帧率以下。验证标准写入吞吐不低于采集帧率且无连接池耗尽告警。查询优化。点查全部走 session_id timestamp_ns 的索引路径对 keypoints 这类 JSON 列避免全表过滤先用 person_count 等标量列缩小候选集再在应用层解析 JSON。这套设计的适用边界很清晰低频维度表 中频会话 高频只追加明细复合唯一约束保幂等JSON 与原生数组各司其职——把它平移到其他时序感知系统基本可以直接复用。全部模型定义见 archive/v1/src/database/models.py自定义数组类型在 archive/v1/src/database/model_types.py 中定义排查查询性能问题可结合 docs/TROUBLESHOOTING.md 使用。【免费下载链接】RuViewπ RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video.项目地址: https://gitcode.com/GitHub_Trending/wi/RuView创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考