冲浪板日志数据分析 — 电流正态分布技术方案 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(待开发)
方案状态:✅ 已审阅,可开始编码