|
| 1 | +它实现了什么功能? |
| 2 | + |
| 3 | +## 1️⃣ 实时频段能量扫描(Energy Sweep) |
| 4 | + |
| 5 | +左侧柱状图表示: |
| 6 | + |
| 7 | +* X 轴:频率区间(例如 433.050 → 434.790 MHz) |
| 8 | +* Y 轴:RSSI 强度 |
| 9 | +* 每根柱:一个步进频点的瞬时/平均功率 |
| 10 | + |
| 11 | +它的意义是: |
| 12 | + |
| 13 | +* 快速查看该频段是否拥挤 |
| 14 | +* 判断是否存在强干扰 |
| 15 | +* 观察噪声底(Noise Floor) |
| 16 | +* 找出峰值位置 |
| 17 | + |
| 18 | +这不是 SDR 级 FFT,而是 **工程级信道占用判断工具**。 |
| 19 | + |
| 20 | +--- |
| 21 | + |
| 22 | +## 2️⃣ 精确频点分析(Cursor 模式) |
| 23 | + |
| 24 | +右侧 CURSOR 区域实现: |
| 25 | + |
| 26 | +* 当前指向频点(433.550 MHz) |
| 27 | +* 该频点 RSSI |
| 28 | +* 当前噪声水平 |
| 29 | + |
| 30 | +这让它从“观察”变成“测量”。 |
| 31 | + |
| 32 | +你不只是看到一堆柱子,而是可以: |
| 33 | + |
| 34 | +* 精确读取某个频点的功率 |
| 35 | +* 判断是否可用 |
| 36 | +* 判断是否存在连续干扰 |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +## 3️⃣ 自动最优信道选择(Best Channel Detection) |
| 41 | + |
| 42 | +BEST 区域实现: |
| 43 | + |
| 44 | +* 计算“最干净”的频点 |
| 45 | +* 显示推荐频率 |
| 46 | +* 显示 SNR |
| 47 | + |
| 48 | +这一步非常关键,它实现了: |
| 49 | + |
| 50 | +> 从频谱数据 → 可行动建议 |
| 51 | +
|
| 52 | +它不只是显示世界,而是**给出决策结果**。 |
| 53 | + |
| 54 | +--- |
| 55 | + |
| 56 | +## 4️⃣ 扫描进度管理 |
| 57 | + |
| 58 | +72% 进度条说明: |
| 59 | + |
| 60 | +* 扫描是区间遍历 |
| 61 | +* 用户知道系统状态 |
| 62 | +* 避免“卡住”误解 |
| 63 | + |
| 64 | +这提升了工程可用性。 |
| 65 | + |
| 66 | +--- |
| 67 | + |
| 68 | +## 5️⃣ 扫描控制(STOP / AUTO) |
| 69 | + |
| 70 | +* STOP:终止扫描 |
| 71 | +* AUTO:自动选择最佳信道 |
| 72 | + |
| 73 | +这意味着: |
| 74 | + |
| 75 | +这个页面已经从“只读显示器” |
| 76 | +变成了 |
| 77 | +“频段管理工具”。 |
| 78 | + |
| 79 | +--- |
| 80 | + |
| 81 | +# 二、这个界面在系统层面的意义 |
| 82 | + |
| 83 | +在 Trail-Mate 架构里,这个页面完成的是: |
| 84 | + |
| 85 | +### 🛰 频谱态势感知(RF Situational Awareness) |
| 86 | + |
| 87 | +它回答: |
| 88 | + |
| 89 | +* 现在这个频段干净吗? |
| 90 | +* 是否有强占用? |
| 91 | +* 我的 LoRa 该选哪个频点? |
| 92 | +* 是否存在持续干扰源? |
| 93 | + |
| 94 | +它是一个“战术前侦查页面”。 |
| 95 | + |
| 96 | +--- |
| 97 | + |
| 98 | +# 三、它属于什么级别的功能? |
| 99 | + |
| 100 | +不是: |
| 101 | + |
| 102 | +* ❌ 频谱仪 |
| 103 | +* ❌ SDR 分析工具 |
| 104 | + |
| 105 | +而是: |
| 106 | + |
| 107 | +* ✅ 信道规划工具 |
| 108 | +* ✅ 干扰检测工具 |
| 109 | +* ✅ 频段健康监测器 |
| 110 | +* ✅ 自动选频前置模块 |
| 111 | + |
| 112 | +--- |
| 113 | + |
| 114 | +# 四、从用户视角来看 |
| 115 | + |
| 116 | +这个界面完成的是: |
| 117 | + |
| 118 | +> “在野外部署前,快速检查当前 Sub-GHz 频段是否适合通信。” |
| 119 | +
|
| 120 | +这对于: |
| 121 | + |
| 122 | +* LoRa mesh |
| 123 | +* FSK 语音 |
| 124 | +* APRS |
| 125 | +* 临时战术部署 |
| 126 | + |
| 127 | +都非常实用。 |
| 128 | + |
| 129 | +--- |
| 130 | + |
| 131 | +# 五、它的核心能力总结 |
| 132 | + |
| 133 | +这个 UI 实现了: |
| 134 | + |
| 135 | +| 能力 | 是否实现 | |
| 136 | +| ------------- | ---- | |
| 137 | +| 频段扫描 | ✅ | |
| 138 | +| 功率可视化 | ✅ | |
| 139 | +| 精确频点读取 | ✅ | |
| 140 | +| 最佳信道推荐 | ✅ | |
| 141 | +| 扫描控制 | ✅ | |
| 142 | +| LoRa CAD 状态展示 | ✅ | |
| 143 | + |
| 144 | +下面按“你这个界面对应的能力”把**算法 + 功能实现方案**讲清楚,目标是:用 SX1262 在 MCU 上做一个**可用的能量扫描/信道选择器**(不是 FFT 频谱仪)。 |
| 145 | + |
| 146 | +--- |
| 147 | + |
| 148 | +## 1) 总体架构 |
| 149 | + |
| 150 | +**输入**:频段范围(f_start, f_end)、步进(step)、每点采样时长(dwell)、采样次数(N) |
| 151 | +**输出**:每个频点的能量值(RSSI/ED)、噪声底(noise floor)、最佳频点(best channel)、峰值/干扰标记、扫描进度 |
| 152 | + |
| 153 | +数据流: |
| 154 | + |
| 155 | +1. 扫频采样 → 得到 `rssi[f_i]` |
| 156 | +2. 估计噪声底 → 得到 `noise_floor` |
| 157 | +3. 计算评分/选优 → 得到 `best_freq` |
| 158 | +4. UI 渲染:柱状图、cursor、RSSI/NOISE/BEST、进度 |
| 159 | + |
| 160 | +--- |
| 161 | + |
| 162 | +## 2) 扫频采样算法(核心) |
| 163 | + |
| 164 | +### 2.1 频点序列 |
| 165 | + |
| 166 | +把频率离散化: |
| 167 | + |
| 168 | +* `bins = floor((f_end - f_start)/step) + 1` |
| 169 | +* `f_i = f_start + i * step` |
| 170 | + |
| 171 | +**步进怎么选(工程上)** |
| 172 | + |
| 173 | +* 想“看干扰哪里高”:`step = 25 kHz` 或 `50 kHz` 足够 |
| 174 | +* 想“粗扫很快”:`step = 100 kHz` |
| 175 | +* 如果你 LoRa 频道带宽是 125 kHz,你用 25 kHz 扫描能更精细地看占用“峰”的位置(但更慢) |
| 176 | + |
| 177 | +### 2.2 每个频点怎么测“能量” |
| 178 | + |
| 179 | +SX1262 拿不到 IQ,所以只能用“能量指标”。最常见是 **Instant RSSI** 或类似 ED 指标(取决于你用的库/驱动暴露的命令)。 |
| 180 | + |
| 181 | +每个频点做: |
| 182 | + |
| 183 | +1. `SetRfFrequency(f_i)` |
| 184 | +2. 进入 RX(可以是 LoRa RX 或 FSK RX,关键是能读到 RSSI) |
| 185 | +3. 等待 **settle**(本振/AGC 稳定):`t_settle ≈ 1~3 ms` |
| 186 | +4. 采样 N 次瞬时 RSSI:每次间隔 `t_gap ≈ 1~2 ms` |
| 187 | +5. 得到该频点值 `P_i` |
| 188 | + |
| 189 | +**P_i 不要直接用平均值(会被突发信号骗)** |
| 190 | +推荐三种稳健聚合方式: |
| 191 | + |
| 192 | +* **median(中位数)**:抗突发、抗偶发尖峰(推荐默认) |
| 193 | +* **trimmed mean(去头去尾均值)**:丢掉最高/最低各 10~20% |
| 194 | +* **EMA(指数滑动均值)**:适合连续扫描实时更新 |
| 195 | + |
| 196 | +> 我建议默认:`P_i = median(rssi_samples)` |
| 197 | +
|
| 198 | +### 2.3 扫描速度估算(让 UI 不卡) |
| 199 | + |
| 200 | +总时间大约: |
| 201 | + |
| 202 | +`T ≈ bins * (t_settle + N*(t_gap + t_read))` |
| 203 | + |
| 204 | +例如: |
| 205 | + |
| 206 | +* 频段宽 1.74 MHz(433.050–434.790) |
| 207 | +* step=25 kHz → bins≈70 |
| 208 | +* t_settle=2ms, N=6, t_gap=1ms |
| 209 | + → 单 bin ~ 2 + 6*(1+读寄存器开销) ≈ 10ms |
| 210 | + → 总计 ~ 700ms(很好用) |
| 211 | + |
| 212 | +--- |
| 213 | + |
| 214 | +## 3) 噪声底(NOISE)如何估计 |
| 215 | + |
| 216 | +你界面右侧有 `NOISE -104 dBm`,这不是芯片“真噪声”,而是你对扫描数据的统计估计。 |
| 217 | + |
| 218 | +### 3.1 推荐方法:分位数/中位数 + 偏置 |
| 219 | + |
| 220 | +因为频段里可能有很多峰,直接平均会被抬高。 |
| 221 | + |
| 222 | +* `noise_floor = percentile(P, 20%)` 或 `median(P)` |
| 223 | +* 然后再做一个轻微平滑:`noise = 0.7*noise + 0.3*noise_floor`(跨帧稳定) |
| 224 | + |
| 225 | +### 3.2 为什么用 20% 分位数 |
| 226 | + |
| 227 | +* 频段里如果有少数强信号,它们只占少量 bins |
| 228 | +* 20% 分位数更接近“底噪水平” |
| 229 | +* 你要的是“哪里比底噪高”,不是绝对精密测量 |
| 230 | + |
| 231 | +--- |
| 232 | + |
| 233 | +## 4) 峰值/干扰标记(柱子变红) |
| 234 | + |
| 235 | +UI 中红柱代表“干扰/占用较强”。规则建议: |
| 236 | + |
| 237 | +* `threshold = noise + margin` |
| 238 | +* margin 典型:`6 dB ~ 12 dB`(看你希望多敏感) |
| 239 | +* 若 `P_i > threshold` → 标红(Warn) |
| 240 | +* 若 `P_i > threshold + 10 dB` → 可以加一个“尖峰标记”(小三角) |
| 241 | + |
| 242 | +为了避免抖动,给红柱加**滞回**: |
| 243 | + |
| 244 | +* 进入红色:`P_i > noise + 10 dB` |
| 245 | +* 退出红色:`P_i < noise + 7 dB` |
| 246 | + |
| 247 | +--- |
| 248 | + |
| 249 | +## 5) CURSOR(指针)怎么实现 |
| 250 | + |
| 251 | +Cursor 有两种交互模式: |
| 252 | + |
| 253 | +### 5.1 自动跟随(扫描中) |
| 254 | + |
| 255 | +* cursor_index = 当前正在采样的 bin |
| 256 | +* UI 每采完一个 bin,就移动光标竖线 |
| 257 | + |
| 258 | +### 5.2 手动浏览(扫描结束/暂停) |
| 259 | + |
| 260 | +* 按键左右移动 cursor_index |
| 261 | +* 右侧显示 `freq[cursor]`、`P_cursor`、`noise` |
| 262 | + |
| 263 | +光标竖线 + 底部小三角只是渲染层,数据来自数组即可。 |
| 264 | + |
| 265 | +--- |
| 266 | + |
| 267 | +## 6) BEST(最佳信道)如何选 |
| 268 | + |
| 269 | +你要的是“最干净、最适合通信”的频点。简单选最小 RSSI 不够,因为: |
| 270 | + |
| 271 | +* 单点最低可能是偶然低谷 |
| 272 | +* LoRa/FSK 发射占带宽,不是一个点 |
| 273 | + |
| 274 | +### 6.1 “带宽窗口”评分(推荐) |
| 275 | + |
| 276 | +设通信带宽 `BW`(例如 125k),换算成需要覆盖的 bin 数: |
| 277 | + |
| 278 | +* `k = ceil(BW / step)` |
| 279 | +* 对每个中心 bin i,计算窗口内的“最坏情况”: |
| 280 | + |
| 281 | + * `score_i = max(P[i - k/2 ... i + k/2])` |
| 282 | +* 选择 score 最小的 i 作为 best |
| 283 | + |
| 284 | +这会避免选到“旁边有大峰”的位置。 |
| 285 | + |
| 286 | +### 6.2 加上保护间隔(guard) |
| 287 | + |
| 288 | +LoRa 频偏/温漂/邻道干扰都存在,可以再加 guard,例如 ±1~2 个 bin 也纳入窗口。 |
| 289 | + |
| 290 | +--- |
| 291 | + |
| 292 | +## 7) SNR +12 怎么来? |
| 293 | + |
| 294 | +在你这个“能量扫描”场景里,SNR 是**估算值**: |
| 295 | + |
| 296 | +* `snr_est = noise - P_best` (注意 dBm 越小越弱,所以符号要小心) |
| 297 | + 更直观写法: |
| 298 | +* `snr_est = (P_best - noise)`,如果 P_best 比 noise 高就是负数;但你 UI 里显示 +12,代表你希望“越干净越大”。 |
| 299 | + |
| 300 | +所以建议定义为: |
| 301 | + |
| 302 | +* `cleanliness = noise - P_best`(越大越干净) |
| 303 | +* 显示:`SNR +cleanliness` |
| 304 | + |
| 305 | +例如:noise=-104, best=-116 → cleanliness=12 → `SNR +12`(符合 UI) |
| 306 | + |
| 307 | +--- |
| 308 | + |
| 309 | +## 8) CAD(LoRa preamble 检测)怎么融合 |
| 310 | + |
| 311 | +CAD 不是全频谱扫描,它是“在某个频点上检测是否存在 LoRa 前导码”。 |
| 312 | + |
| 313 | +你 UI 顶部的 `CAD` 可以这样实现: |
| 314 | + |
| 315 | +* 当用户开启 CAD: |
| 316 | + |
| 317 | + * 每次扫描到某个 bin,如果你关心该点是否有 LoRa,执行一次 CAD |
| 318 | + * 得到 `cad_detected`(布尔) |
| 319 | + * 如果 detected:给该 bin 做一个“蓝色小点/标记”,或者让状态灯闪一下 |
| 320 | + |
| 321 | +但要注意:**CAD 会增加耗时**,所以策略上可以: |
| 322 | + |
| 323 | +* 只对“疑似忙碌”的 bins(P_i > noise+X)做 CAD |
| 324 | +* 或者扫描完成后,对 best 候选点做 CAD 复核 |
| 325 | + |
| 326 | +--- |
| 327 | + |
| 328 | +## 9) 进度条与 STOP/AUTO 行为 |
| 329 | + |
| 330 | +### 9.1 进度条 |
| 331 | + |
| 332 | +* `progress = scanned_bins / bins` |
| 333 | +* UI 每完成一个 bin 更新一次(不要每次采样更新,UI 会抖) |
| 334 | + |
| 335 | +### 9.2 STOP |
| 336 | + |
| 337 | +* 设置一个 `scan_abort` 标志 |
| 338 | +* 每个 bin 结束检查一次,立即退出 |
| 339 | +* UI 状态切换到“冻结显示 + 可移动 cursor” |
| 340 | + |
| 341 | +### 9.3 AUTO |
| 342 | + |
| 343 | +* 触发 best 计算 |
| 344 | +* 并把无线模块的工作频点切换到 best |
| 345 | +* (可选)保存到配置:让下一次上电沿用 |
| 346 | + |
| 347 | +--- |
| 348 | + |
| 349 | +## 10) 如果你要更“专业”的两点增强 |
| 350 | + |
| 351 | +### A) 动态中心频率校准(你之前提过) |
| 352 | + |
| 353 | +如果你担心频偏/温漂导致“峰”位置漂: |
| 354 | + |
| 355 | +* 在每个 bin 的 dwell 中,取前 2ms 的样本作为快速估计 |
| 356 | +* 用它对后续样本做轻微校正(本质是稳定统计,不是真频偏补偿) |
| 357 | + 更实际的做法:**只做 UI 平滑**,别做“频率校准”的强承诺。 |
| 358 | + |
| 359 | +### B) 多帧叠加(历史底噪) |
| 360 | + |
| 361 | +维护 `P_i_hist` 的 EMA: |
| 362 | + |
| 363 | +* `P_i = 0.6*P_i + 0.4*P_i_prev` |
| 364 | + 这样界面更稳,像“仪表”而不是“闪动的噪声”。 |
| 365 | + |
| 366 | +--- |
| 367 | + |
| 368 | +## 11) 你最终会得到什么? |
| 369 | + |
| 370 | +* 一个频段扫描器(几十~几百 ms 出结果) |
| 371 | +* 可视化占用峰(红柱) |
| 372 | +* 可读的底噪估计(NOISE) |
| 373 | +* 可行动的推荐频点(BEST + 清洁度) |
| 374 | +* 可选的 LoRa CAD 复核 |
| 375 | +* 并能一键 AUTO 切换工作信道 |
0 commit comments