Pendant_Rtc_Toy/docs/石头同频匹配方案说明.md
Rdzleo 93f0e19d1d 初始化项目:精灵吊坠 RTC 语音助手 + VEML7700 石头同频匹配
ESP32-S3 吊坠设备固件,集成火山引擎 RTC 语音助手、蓝牙配网、
VEML7700 环境光传感器驱动及石头同频匹配交友功能。

VEML7700 驱动:
- 基于 ESP-IDF i2c_master API 实现,复用项目 I2cDevice 基类
- 支持 ALS + White 双通道、自动量程、Vishay 非线性校正
- 3 次采样取中位数过滤偶发异常

石头同频匹配算法(双维度):
- 维度1:光谱比值 ALS/White(石头固有光学特征,不随光照强度变化)
- 维度2:亮度等级(5级对数划分,排除极端环境差异)
- 比值阈值 15%,实测同石头姿势变化波动 1.6%~9.6%,安全余量充足

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 11:43:57 +08:00

211 lines
9.6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 石头同频匹配方案说明
## 1. 业务背景
用户将自己的"本命石"放到设备的 VEML7700 环境光传感器上,录入光源信息。社交场景下,将其他用户的石头放到传感器上检测,如果两块石头"同频"则匹配交友成功。
**核心挑战**:录入和匹配可能发生在完全不同的光照环境下(室内/室外/阴天/晴天),算法需要在不同环境下仍能正确识别"同一类"石头。
## 2. 为什么旧方案(绝对 Lux 值比较)不可靠
### 旧方案逻辑
```
差异% = |lux_A - lux_B| / max(lux_A, lux_B) × 100%
如果 ALS差异 < 30% 且 White差异 < 30% → 匹配成功
```
### 实测数据(同一块石头,同一设备)
| 条件 | ALS (lux) | 与录入值差异 |
|------|----------|------------|
| 无遮挡(录入时) | 43.97 | 基准 |
| 无遮挡(匹配时) | 42.29 ~ 47.17 | 2% ~ 7% |
| 手掌遮挡10cm | 22.79 ~ 34.74 | **21% ~ 48%** |
**问题**同一块石头仅因为手掌遮挡模拟不同光照环境Lux 绝对值就变化了近 50%。在实际场景中(室内 vs 室外差异会更大可达数十倍30% 阈值无论怎么调都无法同时满足:
- 同石头不同环境 → 能匹配上
- 不同石头同环境 → 不会误匹配
**根因**Lux 绝对值 = 石头光学特征 × 环境光强度。环境变了,绝对值就完全不同。
## 3. 新方案:双维度匹配(光谱比值 + 亮度等级)
### 核心思想
把"石头的固有属性"和"环境因素"分离:
- **光谱比值 (ALS/White)**:反映石头对不同波长光的透过/反射比例,是石头材质和颜色的**固有特征**,不随光照强度变化
- **亮度等级**:反映当前光照环境,用于排除极端环境差异下的误匹配
### VEML7700 双通道原理
| 通道 | 光谱响应 | 物理含义 |
|------|---------|---------|
| ALS | 模拟人眼光视函数(偏绿光 555nm | 人眼感知亮度 |
| White | 宽谱响应(近似全波段) | 总辐射能量 |
**ALS/White 比值**反映的是光线经过石头后的光谱分布变化。不同材质/颜色的石头对光谱的改变不同,因此比值不同。而同一块石头无论光多强多弱,比值基本不变。
### 实测数据验证
用上一轮测试数据反向计算比值:
| 条件 | ALS | White | **ALS/White 比值** | 比值波动 |
|------|-----|-------|--------------------|---------|
| 无遮挡(录入) | 43.97 | 50.25 | **0.875** | 基准 |
| 无遮挡 #1 | 42.29 | 48.95 | **0.864** | -1.3% |
| 无遮挡 #4 | 44.90 | 51.89 | **0.865** | -1.1% |
| 无遮挡 #5 | 46.82 | 54.07 | **0.866** | -1.0% |
| 手掌轻遮挡 | 33.46 | 41.82 | **0.800** | -8.6% |
| 手掌重遮挡 | 24.01 | 34.45 | **0.697** | -20.3% |
**关键发现**
- **无遮挡条件下比值波动仅 ±1.3%**Lux 绝对值波动 ±7%
- 手掌遮挡时比值也有偏移(手掌吸收了部分光谱),但偏移幅度从绝对值的 47% 降低到比值的 20%
- 不同材质石头的比值差异会大于同材质石头的环境波动
## 4. 匹配算法详细设计
### 判定条件
**同时满足以下两个维度才算匹配成功:**
#### 维度1光谱比值匹配判断石头是否为同类
```
ratio_A = ALS_A / White_A (本命石)
ratio_B = ALS_B / White_B (对方石)
差异% = |ratio_A - ratio_B| / max(ratio_A, ratio_B) × 100%
如果 差异% ≤ 15% → PASS
```
#### 维度2亮度等级匹配排除极端环境差异
```
亮度等级划分:
0 = 极暗 (<5 lux)
1 = 暗 (5 ~ 50 lux)
2 = 中 (50 ~ 500 lux)
3 = 亮 (500 ~ 5000 lux)
4 = 极亮 (>5000 lux)
如果 |等级_A - 等级_B| ≤ 1 → PASS允许相差1个等级
```
### 为什么这样设计
| 设计决策 | 理由 |
|---------|------|
| 比值阈值 15% | 无遮挡同石头波动约 1~2%,留足余量给不同环境(如手掌遮挡约 8~20%)。不同材质石头比值差异通常 >20% |
| 亮度等级用对数划分 | 人眼对亮度的感知是对数的;室内/室外的亮度差异是数量级的10 lux vs 10000 lux|
| 允许相差 1 个等级 | 同一环境内亮度波动可能跨越等级边界(如 48 lux vs 52 lux 分属"暗"和"中"|
| 3 次采样取中位数 | 过滤传感器偶发异常读数(实测中观察到单次异常偏低 50% 的情况)|
### 匹配场景预测
| 场景 | 比值匹配 | 亮度等级 | 结果 | 说明 |
|------|---------|---------|------|------|
| 同石头 + 同光照 | ✅ (~1-2%) | ✅ 同级 | **匹配** | 理想场景 |
| 同石头 + 略有遮挡 | ✅ (~8%) | ✅ 同级 | **匹配** | 手遮一下不影响 |
| 同石头 + 室内→遮挡严重 | ⚠️ (~15-20%) | ✅ 可能同级 | **概率匹配** | 趣味性 |
| 同石头 + 室内→室外 | ✅ (~1-5%) | ❌ 差2+级 | **不匹配** | 环境差异过大 |
| 不同石头 + 同光照 | ❌ (>20%) | ✅ 同级 | **不匹配** | 不同材质 |
| 不同石头 + 不同光照 | ❌ | ❌ | **不匹配** | 双重不匹配 |
| 相似材质石头 + 同光照 | ✅ (<15%) | | **匹配** | 有缘 |
## 5. NVS 存储结构
| NVS Key | 类型 | 说明 |
|---------|------|------|
| `ratio` | int32 | 光谱比值 × 10000 0.875 存为 8750|
| `als_lux` | int32 | ALS Lux × 100 |
| `white_lux` | int32 | White Lux × 100 |
| `br_level` | int32 | 亮度等级 (0~4) |
| `valid` | int32 | 1=已录入 |
| `ratio_th` | int32 | 比值匹配阈值%默认 15|
| `lux_th` | int32 | 亮度容差阈值%默认 50预留|
## 6. 阈值调节指南
### 比值阈值 (`ratio_th`)
| | 效果 | 适用场景 |
|----|------|---------|
| 5% | 极严格几乎只有完全相同的石头能匹配 | 精确识别 |
| 10% | 严格同材质同颜色可匹配 | 科学实验 |
| **15%** | **推荐默认**兼顾准确性和社交趣味性 | **正常社交** |
| 20% | 宽松相近材质也能匹配 | 破冰社交 |
| 30% | 非常宽松大多数石头都能匹配 | 活动促进 |
### 亮度等级容差
当前固定允许相差 1 个等级如果后续需要更灵活可以通过 `lux_th` 字段扩展
## 7. 相对于旧方案的优势
| 维度 | 旧方案绝对Lux | 新方案比值+等级 |
|------|-------------------|-------------------|
| 环境光鲁棒性 | 光照变化直接导致失败 | 比值不随光强变化 |
| 石头区分能力 | 不同石头同环境可能误匹配 | 不同材质比值不同 |
| 偶发异常防护 | 单次读取 | 3次采样取中位数 |
| 极端环境保护 | | 亮度等级兜底 |
| 匹配趣味性 | 要么全过要么全挂 | 物理属性+环境=概率匹配 |
## 8. 用户使用指南与注意事项
### 操作方式
本设备为吊坠产品检测石头时用食指和大拇指捏住石头贴紧设备传感器区域进行检测
- **双击** KEY4 按键录入本命石等待提示后保持 3
- **长按** KEY4 按键 2 匹配对方石头
### 操作规范
| 要求 | 说明 | 原因 |
|------|------|------|
| 石头贴紧传感器 | 尽量让石头紧贴传感器区域减少缝隙 | 缝隙大小变化会引入环境光干扰 |
| 检测期间保持稳定 | 按键触发后保持手和石头不动约 3 | 设备需要 3 次采样取中位数晃动会影响数据 |
| 手指不要覆盖传感器 | 手指捏石头两侧即可不要让手指遮挡传感器正上方 | 手指皮肤会吸收特定波长光线改变光谱比值 |
### 推荐使用环境
| 环境 | 推荐度 | 说明 |
|------|--------|------|
| 室内正常照明日光灯/LED灯 | 推荐 | 光照稳定匹配成功率最高 |
| 室外阴天/树荫下 | 推荐 | 光照均匀无强烈直射光干扰 |
| 室外晴天非暴晒 | 可用 | 注意避免阳光直射传感器 |
| 暗室/关灯房间 | 不推荐 | 光照不足<5 lux传感器信噪比降低 |
| 强烈阳光直射 | 不推荐 | 传感器可能饱和且手指阴影影响大 |
### 录入和匹配的环境一致性
**录入和匹配不要求在完全相同的环境下进行**但需要注意
- 同一亮度等级内如都在室内匹配成功率最高
- 跨越 1 个亮度等级如室内录入 走廊匹配仍可匹配
- 跨越 2 个及以上等级如室内录入 室外烈日匹配会被系统判为环境差异过大而拒绝匹配
- **如果频繁匹配失败可以在当前环境下重新录入本命石**然后再匹配
### 实测数据参考(手指捏石头姿势)
以下为同一块石头同一环境每次故意变化捏持角度和松紧度的 5 次匹配测试
| 次序 | 光谱比值差异 | ALS亮度差异 | 结果 |
|------|-----------|-----------|------|
| 1 | 1.6% | 7.3% | 匹配成功 |
| 2 | 2.3% | 1.3% | 匹配成功 |
| 3角度变化 | 6.6% | 5.9% | 匹配成功 |
| 4角度变化大 | 9.6% | 3.1% | 匹配成功 |
| 5松紧变化 | 5.4% | 9.7% | 匹配成功 |
**结论**手指捏持姿势变化对比值的影响在 1.6%~9.6%远低于 15% 匹配阈值具有充足的安全余量5.4%正常操作下不会因姿势差异导致匹配失败
### 常见问题
| 问题 | 原因 | 解决方法 |
|------|------|---------|
| 同一块石头反复匹配失败 | 录入和匹配时光照环境差异过大 | 在当前环境重新双击录入再匹配 |
| 不同石头总是能匹配上 | 两块石头材质/颜色极其相近 | 这属于"有缘"是正常现象 |
| 录入提示传感器未初始化 | VEML7700 传感器硬件连接异常 | 重启设备检查硬件 |
| 匹配结果显示"光照环境差异过大" | 录入室内和匹配室外跨度过大 | 在相近光照环境下操作 |