← 返回目录

冲浪板日志数据分析 — 电流正态分布技术方案 v2.0

版本:v2.0 · 2026-08-13
v3.0 已发布:连续航段平均速度、高负荷 1.5× 捕捉、起飞/滑行独立通道、Top15 边界。见 surfboard_current_distribution_analysis_plan_v3.md
目标:通过生产日志提取真实使用工况的电流分布,为电池工况定义提供数据依据


一、分析目标

工况段 定义 用途
高负荷(急速/带人) 电流分布 Top 5%、Top 1% 电池峰值放电倍率依据
正常巡航 电流分布核心区(μ±1σ) 续航/容量匹配依据
低速大载重滑行 低速高电流异常段(TBD) 热管理/过载保护依据

二、目录结构

analysis/
├── tools/
│   ├── current_distribution.py      # 主分析脚本(入口)
│   ├── db.py                        # MySQL 连接封装
│   ├── oss.py                       # OSS 下载 + 本地缓存封装
│   ├── filters.py                   # Log 级 + 点级筛选逻辑
│   ├── stats.py                     # 正态分布拟合 + 分位数计算
│   ├── report.py                    # 图表生成 + CSV 导出
│   └── .env                         # 环境变量(复用 trajectory-log-analyzer/.env)
│
├── data/
│   ├── oss_cache/                   # OSS JSON 本地缓存(按需保留,可共用 temp/oss_cache)
│   ├── logs_index.csv               # MySQL 筛选结果缓存(避免重复查库)
│   └── points_raw.parquet           # 汇总后的点级数据(Parquet,可反复分析)
│
├── output/
│   ├── current_distribution.png     # 电流直方图 + 正态曲线
│   ├── power_distribution.png       # 功率分布图
│   ├── speed_vs_current_heatmap.png # 速度 × 电流 热力图
│   ├── current_cdf.png              # 电流累积概率曲线 (CDF)
│   ├── summary_stats.csv            # 全量分位数统计
│   ├── speed_bin_stats.csv          # 按速度分箱统计
│   └── run_report.md                # 每次运行自动生成的分析摘要
│
└── reports/
    └── surfboard_current_distribution_analysis_plan.md   # 本文档

三、数据筛选方案

3.1 第一层:Log 级筛选(MySQL)

SELECT
    h.id               AS trajectory_id,
    h.object_key,
    a.max_speed,
    a.max_current,
    a.duration_sec,
    a.electrical_sn,
    a.board_sn,
    a.remote_sn,
    a.session_date,
    a.location,
    a.play_user_id
FROM surf_motion_trajectory_analysis a
JOIN surf_motion_trajectory_history  h ON h.id = a.trajectory_id
WHERE
    a.analyze_status  = 'done'
    AND a.max_speed   >= 25                      -- 粗筛:最高速 ≥ 25 km/h(非起飞则不会超)
    AND a.duration_sec BETWEEN 1200 AND 7200     -- 航时 20~120 分钟
    AND a.max_current  > 30                      -- 排除空跑/测试(电流很低)
    AND a.has_fault    = 0                       -- 排除有故障的航次(防数据污染)
    -- AND a.play_user_id NOT IN (10000009)      -- 可选:排除测试账号
ORDER BY a.session_date DESC;

说明:SQL 结果缓存到 data/logs_index.csv,下次跳过查库直接使用(--use-cache 参数控制)。

3.2 第二层:JSON 头字段二次确认

下载 JSON 后,读取 averageSpeed 进行精确过滤:

averageSpeed(JSON头)≥ 20 km/h   → 保留
averageSpeed < 20 km/h           → 跳过(未起飞 / 新手练习)

3.3 第三层:点级筛选

每个 trajectoryList 轨迹点,同时满足以下条件才保留:

字段 条件 说明
hourSpeed ≥ 15 km/h 去掉起飞前、停顿、制动段
electricCurrent ≥ 5 A 去掉无功耗段(滑行)
batteryVoltage ≥ 38 V 去掉低电量末段(电压跌落致电流虚高)
batteryElectricity ≥ 10 % 辅助过滤低电量末段

衍生字段:

power_w = electricCurrent × batteryVoltage    # 瞬时功率 (W)

四、程序流程详细设计

┌─────────────────────────────────────────────────────────────┐
│  STEP 1  MySQL 筛选 Log 列表                                 │
│  db.py → fetch_quality_logs()                               │
│  输出:logs_index.csv(trajectory_id, object_key, meta)    │
└────────────────────┬────────────────────────────────────────┘
                     │
┌────────────────────▼────────────────────────────────────────┐
│  STEP 2  批量下载 OSS JSON(并行,带缓存)                    │
│  oss.py → download_batch()                                  │
│  · 线程池 workers=8                                          │
│  · 优先读 data/oss_cache/;命中则跳过下载                    │
│  · 下载失败 → 记录到 failed_downloads.txt,继续              │
│  · 超时(默认 30s)→ 跳过,不中断整批                        │
│  输出:data/oss_cache/<object_key_flat>.json                 │
└────────────────────┬────────────────────────────────────────┘
                     │
┌────────────────────▼────────────────────────────────────────┐
│  STEP 3  JSON 解析 + 二次 averageSpeed 过滤                  │
│  filters.py → filter_log_header()                           │
│  · JSON 解析失败 → 跳过,记录 parse_errors.txt              │
│  · averageSpeed < threshold → 跳过                          │
└────────────────────┬────────────────────────────────────────┘
                     │
┌────────────────────▼────────────────────────────────────────┐
│  STEP 4  点级过滤 + 字段提取                                 │
│  filters.py → extract_points()                              │
│  · 每个点提取:timestamp, speed, current, voltage, power    │
│  · 附带 meta:trajectory_id, board_sn, electrical_sn        │
│  · 整批点追加到内存 DataFrame                                │
└────────────────────┬────────────────────────────────────────┘
                     │
┌────────────────────▼────────────────────────────────────────┐
│  STEP 5  保存中间数据(Parquet)                              │
│  data/points_raw.parquet                                    │
│  · 方便后续反复分析,不用重新下载                             │
└────────────────────┬────────────────────────────────────────┘
                     │
┌────────────────────▼────────────────────────────────────────┐
│  STEP 6  正态分布拟合 + 分位数计算                            │
│  stats.py → analyze_distribution()                          │
│  · scipy.stats.norm.fit(current_array)  → μ, σ             │
│  · np.percentile → P50/P75/P90/P95/P99                     │
│  · 对应每个分位点:取该电流段内的功率均值、速度均值           │
└────────────────────┬────────────────────────────────────────┘
                     │
┌────────────────────▼────────────────────────────────────────┐
│  STEP 7  速度分箱分组统计                                    │
│  stats.py → speed_bin_stats()                               │
│  · 分箱:15~20 / 20~25 / 25~30 / 30~35 / >35 km/h          │
│  · 每箱:样本量、电流均值/σ/P95/P99、功率均值/P99           │
└────────────────────┬────────────────────────────────────────┘
                     │
┌────────────────────▼────────────────────────────────────────┐
│  STEP 8  输出图表 + CSV + 运行摘要                            │
│  report.py → export_all()                                   │
│  · 4 张图表(分布/CDF/热力图/功率)                           │
│  · 2 张 CSV(全量分位数 + 速度分箱)                          │
│  · 1 份 run_report.md(日期/样本量/关键数值/异常日志数)      │
└─────────────────────────────────────────────────────────────┘

五、容错设计

异常场景 处理策略 记录位置
MySQL 连接失败 打印错误,程序退出(不静默失败) 控制台 stderr
单个 OSS 下载超时(>30s) 跳过该 log,继续下一个 output/failed_downloads.txt
OSS 返回 403/404 跳过,记录 object_key output/failed_downloads.txt
JSON 解析失败(文件损坏) 跳过,记录 trajectory_id output/parse_errors.txt
JSON 无 trajectoryList 或为空 跳过,计入空日志统计 run_report.md
点级字段缺失(None/null) 单字段替换为 NaN,整点不丢弃,统计时自动忽略 —
过滤后样本量不足(<100点) 发出警告,仍继续分析,在报告中标注置信度低 run_report.md
Parquet 写入失败(磁盘满) 降级为 CSV,继续写 控制台 warning
图表依赖缺失(matplotlib) 跳过图表,仅输出 CSV,不中断 控制台 warning

进度持久化:每处理完 50 个 log,将已成功的 trajectory_id 追加写入 output/progress.txt;重启时跳过已处理的,支持断点续跑。


六、CLI 参数设计

python analysis/tools/current_distribution.py [OPTIONS]

选项:
  --min-speed-log INT       Log级粗筛最大速度阈值 (默认 25 km/h)
  --avg-speed-thresh INT    JSON头 averageSpeed 精筛阈值 (默认 20 km/h)
  --min-speed-point INT     点级速度阈值 (默认 15 km/h)
  --min-duration INT        最短航时,秒 (默认 1200)
  --max-duration INT        最长航时,秒 (默认 7200)
  --min-voltage FLOAT       最低电压过滤,V (默认 38.0)
  --min-current FLOAT       最低电流过滤,A (默认 5.0)
  --workers INT             并行下载线程数 (默认 8)
  --out PATH                输出目录 (默认 analysis/output/)
  --cache-dir PATH          OSS 缓存目录 (默认 analysis/data/oss_cache/)
  --use-cache               跳过 MySQL,直接读 logs_index.csv
  --resume                  跳过 progress.txt 中已处理的 log
  --no-charts               不生成图表(纯 CSV 模式,无需 matplotlib)
  --exclude-users 10000009  排除指定 play_user_id(逗号分隔)
  --date-from YYYY-MM-DD    仅处理此日期之后的数据
  --date-to   YYYY-MM-DD    仅处理此日期之前的数据
  --limit INT               最多处理 N 个 log(调试用)

七、输出说明

7.1 summary_stats.csv

指标 电流 (A) 功率 (W) 对应速度中位数 (km/h)
均值 μ — — —
标准差 σ — — —
P50(中位数) — — —
P75 — — —
P90 — — —
P95(Top 5%) — — —
P99(Top 1%) — — —

7.2 speed_bin_stats.csv

速度段 样本量 电流均值(A) 电流σ P95电流(A) P99电流(A) 功率均值(W) P99功率(W)
15~20 km/h — — — — — — —
20~25 km/h — — — — — — —
25~30 km/h — — — — — — —
30~35 km/h — — — — — — —
>35 km/h — — — — — — —

7.3 图表说明

current_distribution.png
全量电流直方图 + 正态拟合曲线,标注 μ、μ±σ、P95、P99 竖线及数值

current_cdf.png
电流累积概率曲线(CDF),横轴电流,纵轴百分位,便于读任意分位值

speed_vs_current_heatmap.png
速度(x轴,每2km/h一格)× 电流(y轴,每10A一格)二维密度热力图,颜色深=高频

power_distribution.png
瞬时功率分布图,标注 P95/P99 功率值

7.4 run_report.md(自动生成)

# 分析运行摘要 · 2026-08-13 10:30

## 数据规模
- 候选 Log 数:XXX
- averageSpeed 过滤后:XXX
- 有效数据点:XXX 万点
- 覆盖时间:YYYY-MM-DD ~ YYYY-MM-DD

## 容错统计
- 下载失败:X 条(见 failed_downloads.txt)
- 解析失败:X 条(见 parse_errors.txt)
- 点级过滤前/后:XXX → XXX 点(保留率 XX%)

## 关键结论
- 电流 μ = XX A,σ = XX A
- P95 电流 = XX A,对应功率 XX W,速度中位 XX km/h
- P99 电流 = XX A,对应功率 XX W,速度中位 XX km/h

## 工况定义建议
| 工况 | 电流范围 | 功率范围 | 代表速度 |
|---|---|---|---|
| 巡航(μ±1σ) | XX~XX A | XX~XX W | ~XX km/h |
| 高负荷(P95)| ≥ XX A | ≥ XX W | ~XX km/h |
| 峰值(P99) | ≥ XX A | ≥ XX W | ~XX km/h |

八、执行步骤

# 1. 进入工作目录
cd d:\project\jetwave-fly-logs

# 2. 安装依赖(一次性)
pip install pymysql pandas scipy matplotlib seaborn pyarrow python-dotenv

# 3. 配置环境变量
cp trajectory-log-analyzer/.env analysis/tools/.env

# 4. 首次完整运行
python analysis/tools/current_distribution.py \
    --workers 8 \
    --out analysis/output/ \
    --cache-dir analysis/data/oss_cache/

# 5. 调试模式:只跑 20 个 log
python analysis/tools/current_distribution.py --limit 20 --no-charts

# 6. 断点续跑(上次中断后继续)
python analysis/tools/current_distribution.py --resume

# 7. 复用已下载缓存,仅重新分析
python analysis/tools/current_distribution.py --use-cache \
    --min-speed-point 20        # 调整点级阈值重新分析,无需重新下载

九、依赖清单

pymysql          # MySQL 连接
pandas           # 数据处理
scipy            # 正态分布拟合 (scipy.stats.norm)
numpy            # 数值计算
matplotlib       # 图表生成
seaborn          # 热力图
pyarrow          # Parquet 格式(中间数据持久化)
python-dotenv    # 读取 .env

十、后续扩展方向

方向 说明
按 ESC 固件版本分层 不同版本电流采样精度可能不同,分别建模
按 electricalSn 分组 识别特定电调个体的异常电流特征
温度联合分析 (电流 × 温度) 二维分布,识别热管理边界
时序切片分析 分析一次航行内前/中/后段电流变化趋势
季节/水域分层 夏季高温工况 vs 冬季,国内 vs 海外

实现脚本:analysis/tools/current_distribution.py(待开发)
方案状态:✅ 已审阅,可开始编码