powermonitor-hvpm 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. powermonitor_hvpm-0.1.0/LICENSE +21 -0
  2. powermonitor_hvpm-0.1.0/PKG-INFO +199 -0
  3. powermonitor_hvpm-0.1.0/README.md +160 -0
  4. powermonitor_hvpm-0.1.0/THIRD_PARTY_NOTICES.md +55 -0
  5. powermonitor_hvpm-0.1.0/pyproject.toml +84 -0
  6. powermonitor_hvpm-0.1.0/setup.cfg +4 -0
  7. powermonitor_hvpm-0.1.0/src/powermonitor/__init__.py +3 -0
  8. powermonitor_hvpm-0.1.0/src/powermonitor/__main__.py +7 -0
  9. powermonitor_hvpm-0.1.0/src/powermonitor/_vendor/__init__.py +1 -0
  10. powermonitor_hvpm-0.1.0/src/powermonitor/_vendor/pymonsoon/HVPM.py +246 -0
  11. powermonitor_hvpm-0.1.0/src/powermonitor/_vendor/pymonsoon/LICENSE.txt +7 -0
  12. powermonitor_hvpm-0.1.0/src/powermonitor/_vendor/pymonsoon/Operations.py +139 -0
  13. powermonitor_hvpm-0.1.0/src/powermonitor/_vendor/pymonsoon/__init__.py +3 -0
  14. powermonitor_hvpm-0.1.0/src/powermonitor/_vendor/pymonsoon/calibrationData.py +97 -0
  15. powermonitor_hvpm-0.1.0/src/powermonitor/_vendor/pymonsoon/pmapi.py +241 -0
  16. powermonitor_hvpm-0.1.0/src/powermonitor/_vendor/pymonsoon/sampleEngine.py +688 -0
  17. powermonitor_hvpm-0.1.0/src/powermonitor/acquisition.py +469 -0
  18. powermonitor_hvpm-0.1.0/src/powermonitor/app.py +137 -0
  19. powermonitor_hvpm-0.1.0/src/powermonitor/backends/__init__.py +7 -0
  20. powermonitor_hvpm-0.1.0/src/powermonitor/backends/base.py +38 -0
  21. powermonitor_hvpm-0.1.0/src/powermonitor/backends/monsoon.py +365 -0
  22. powermonitor_hvpm-0.1.0/src/powermonitor/backends/simulator.py +93 -0
  23. powermonitor_hvpm-0.1.0/src/powermonitor/models.py +102 -0
  24. powermonitor_hvpm-0.1.0/src/powermonitor/statistics.py +123 -0
  25. powermonitor_hvpm-0.1.0/src/powermonitor/storage.py +445 -0
  26. powermonitor_hvpm-0.1.0/src/powermonitor/ui/__init__.py +5 -0
  27. powermonitor_hvpm-0.1.0/src/powermonitor/ui/formatting.py +75 -0
  28. powermonitor_hvpm-0.1.0/src/powermonitor/ui/plots.py +738 -0
  29. powermonitor_hvpm-0.1.0/src/powermonitor/ui/table.py +393 -0
  30. powermonitor_hvpm-0.1.0/src/powermonitor/ui/theme.py +157 -0
  31. powermonitor_hvpm-0.1.0/src/powermonitor/ui/window.py +1074 -0
  32. powermonitor_hvpm-0.1.0/src/powermonitor_hvpm.egg-info/PKG-INFO +199 -0
  33. powermonitor_hvpm-0.1.0/src/powermonitor_hvpm.egg-info/SOURCES.txt +55 -0
  34. powermonitor_hvpm-0.1.0/src/powermonitor_hvpm.egg-info/dependency_links.txt +1 -0
  35. powermonitor_hvpm-0.1.0/src/powermonitor_hvpm.egg-info/entry_points.txt +2 -0
  36. powermonitor_hvpm-0.1.0/src/powermonitor_hvpm.egg-info/requires.txt +11 -0
  37. powermonitor_hvpm-0.1.0/src/powermonitor_hvpm.egg-info/top_level.txt +1 -0
  38. powermonitor_hvpm-0.1.0/tests/test_acquisition.py +358 -0
  39. powermonitor_hvpm-0.1.0/tests/test_backend_monsoon.py +78 -0
  40. powermonitor_hvpm-0.1.0/tests/test_backend_simulator.py +49 -0
  41. powermonitor_hvpm-0.1.0/tests/test_controller_safety.py +186 -0
  42. powermonitor_hvpm-0.1.0/tests/test_core.py +205 -0
  43. powermonitor_hvpm-0.1.0/tests/test_core_edges.py +520 -0
  44. powermonitor_hvpm-0.1.0/tests/test_current_ui_performance.py +135 -0
  45. powermonitor_hvpm-0.1.0/tests/test_live_capture_reader.py +225 -0
  46. powermonitor_hvpm-0.1.0/tests/test_live_zoom_follow.py +108 -0
  47. powermonitor_hvpm-0.1.0/tests/test_long_live_history_acceptance.py +113 -0
  48. powermonitor_hvpm-0.1.0/tests/test_plots.py +594 -0
  49. powermonitor_hvpm-0.1.0/tests/test_recent_snapshot.py +155 -0
  50. powermonitor_hvpm-0.1.0/tests/test_sdk_lifecycle.py +253 -0
  51. powermonitor_hvpm-0.1.0/tests/test_sdk_sample_engine.py +177 -0
  52. powermonitor_hvpm-0.1.0/tests/test_sdk_vendor_namespace.py +15 -0
  53. powermonitor_hvpm-0.1.0/tests/test_ui.py +826 -0
  54. powermonitor_hvpm-0.1.0/tests/test_ui_app.py +162 -0
  55. powermonitor_hvpm-0.1.0/tests/test_waveform_display.py +139 -0
  56. powermonitor_hvpm-0.1.0/tests/test_waveform_truth_acceptance.py +81 -0
  57. powermonitor_hvpm-0.1.0/tests/test_y_range_persistence.py +103 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 XuNeo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,199 @@
1
+ Metadata-Version: 2.4
2
+ Name: powermonitor-hvpm
3
+ Version: 0.1.0
4
+ Summary: Offline-first Monsoon HVPM desktop capture and analysis
5
+ Author: XuNeo
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/XuNeo/powermonitor-hvpm
8
+ Project-URL: Repository, https://github.com/XuNeo/powermonitor-hvpm
9
+ Project-URL: Issues, https://github.com/XuNeo/powermonitor-hvpm/issues
10
+ Project-URL: Changelog, https://github.com/XuNeo/powermonitor-hvpm/releases
11
+ Keywords: monsoon,hvpm,power-monitor,power-measurement,embedded,current-sensing,pyside6
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: X11 Applications :: Qt
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Operating System :: MacOS :: MacOS X
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
23
+ Classifier: Topic :: System :: Hardware :: Hardware Drivers
24
+ Requires-Python: <3.14,>=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ License-File: THIRD_PARTY_NOTICES.md
28
+ Requires-Dist: numpy<3,>=1.25
29
+ Requires-Dist: PySide6==6.8.3
30
+ Requires-Dist: pyqtgraph==0.14.0
31
+ Requires-Dist: pyusb<2,>=1.3
32
+ Provides-Extra: test
33
+ Requires-Dist: pytest<10,>=8; extra == "test"
34
+ Requires-Dist: pytest-qt<5,>=4.4; extra == "test"
35
+ Requires-Dist: psutil>=6; extra == "test"
36
+ Requires-Dist: ruff>=0.9; extra == "test"
37
+ Requires-Dist: pyright>=1.1; extra == "test"
38
+ Dynamic: license-file
39
+
40
+ # powermonitor-hvpm
41
+
42
+ Monsoon HVPM 功耗监测桌面工具:Python 3 + PySide6,本地离线运行。支持无硬件的确定性模拟模式,以及通过内置(vendored)的官方 PyMonsoon SDK 连接真实 HVPM,完成供电控制、实时电流波形、时间窗口统计、原始录制保存、离线回放和 CSV 导出。电压和功率仍保留在原始数据、统计和 CSV 中,不再单独绘制波形。
43
+
44
+ 通信所需的 PyMonsoon SDK 已按固定上游 commit 私有内置进本项目包内,安装本分发即可使用,无需再从 GitHub 安装任何 `Monsoon` 包,运行环境中也不存在外部顶层 `Monsoon` 命名空间。内置范围、相对上游的机械性改动和许可证事实见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
45
+
46
+ 首版仅覆盖 HVPM 主通道。不包含 LVPM、USB/Aux 通道控制、触发采集、PT5 兼容、固件升级和远程控制。
47
+
48
+ ## 状态
49
+
50
+ - Linux 模拟模式与自动化已验证:供电控制、5 kHz 录制、单电流波形、窗口统计、CSV 和回放;具体结果见 [验证记录](docs/validation-results.md)。
51
+ - macOS 模拟模式(simulator)的软件验证已通过;真实硬件的 USB 联调在 macOS 上仍未实测,见下文平台说明。
52
+ - 真实 HVPM:适配按固定 SDK 版本实现,实物验收尚未进行,见 [硬件验收清单](docs/hardware-validation.md)。
53
+
54
+ 不要把模拟结果当作实机结果。
55
+
56
+ ## 环境要求
57
+
58
+ - Linux(参考环境 Ubuntu 22.04,glibc 2.35)或 macOS。
59
+ - Python 3.10 至 3.13。
60
+ - 连接真实硬件需要系统提供 libusb-1.0 运行库及(Linux 上)相应 udev 权限;模拟模式不需要任何 USB 库。SDK 经 pyusb 访问设备,pyusb 已作为正式依赖随包安装,但它只是 libusb 的 Python 绑定,libusb 共享库本身由操作系统提供,不通过 pip 安装。
61
+ - 依赖建议预留 1.5 GB;原始录制每小时约 792 MB,CSV 通常更大。
62
+ - Linux 桌面 Qt 需要 X11/Wayland 运行库;本机 X11 缺少 `libxcb-cursor.so.0`,已通过项目虚拟环境内解压的发行版 `libxcb-cursor0` 包验证,不修改系统。常规桌面安装可由系统包管理器提供该库。
63
+ - PySide6 6.8.3 的 macOS wheel 要求 macOS 12 或更高,x86_64 与 ARM64 均有 wheel;Linux wheel 为 manylinux_2_28,要求 glibc 不低于 2.28。
64
+
65
+ ## 安装
66
+
67
+ ### 用户主路径(PyPI)
68
+
69
+ ```sh
70
+ pip install powermonitor-hvpm
71
+ ```
72
+
73
+ 安装后直接运行命令:
74
+
75
+ ```sh
76
+ powermonitor --demo
77
+ ```
78
+
79
+ 分发包名为 `powermonitor-hvpm`,安装提供的命令仍为 `powermonitor`。上述命令安装的是发布到 PyPI 的正式依赖(numpy、PySide6、pyqtgraph、pyusb),不含外部 `Monsoon` 包,也不需要访问 github.com。
80
+
81
+ ### 开发者 / 从源码运行
82
+
83
+ 推荐使用 uv,在项目根目录执行:
84
+
85
+ ```sh
86
+ uv sync --extra test
87
+ ```
88
+
89
+ 然后所有命令都通过 `uv run` 执行,例如:
90
+
91
+ ```sh
92
+ uv run python -m powermonitor --demo
93
+ uv run python tools/validate.py
94
+ ```
95
+
96
+ 此时模拟模式功能完整;内置 SDK 的协议、生命周期和版本固定测试无需实物即可运行,只有真实 USB/供电验收需要 HVPM。发布打包工具放在独立的 `release` dependency group(build、twine),仅在构建分发包时需要:
97
+
98
+ ```sh
99
+ uv run --group release python -m build
100
+ uv run --group release twine check dist/*
101
+ ```
102
+
103
+ 如不用 uv,也可以手动 venv:
104
+
105
+ ```sh
106
+ python3 -m venv .venv
107
+ . .venv/bin/activate
108
+ python -m pip install --upgrade pip
109
+ pip install -e '.[test]'
110
+ ```
111
+
112
+ 不要安装 PyPI 上的 `monsoon` 包:本项目不依赖它,内置 SDK 位于本项目包内,额外安装同名外部包没有作用,还可能造成命名混淆。
113
+
114
+ ### Linux USB 权限(仅真实硬件)
115
+
116
+ 内置 SDK 通过 pyusb 访问 USB VID 0x2AB9 / PID 0x0001。系统通常已自带 libusb-1.0;若发行版未提供,用发行版自己的包管理器安装,不使用 sudo pip。
117
+
118
+ 默认 udev 规则下非 root 用户通常无法直接打开设备。最小权限做法是新增一条只匹配该 VID/PID 的 udev 规则,把设备节点授权给一个专用用户组(如 `plugdev`,前提是当前用户已在该组),例如:
119
+
120
+ ```text
121
+ SUBSYSTEM=="usb", ATTRS{idVendor}=="2ab9", ATTRS{idProduct}=="0001", MODE="0660", GROUP="plugdev"
122
+ ```
123
+
124
+ 安装或重载规则属于系统级权限变更,接入实物时确认后执行;不要长期以 root 运行应用。规则生效后重新插拔设备。macOS 不使用 udev,通常需安装系统 libusb;该平台的真实 USB 联调仍待验证。
125
+
126
+ ## 启动
127
+
128
+ 安装后启动桌面窗口(命令入口):
129
+
130
+ ```sh
131
+ powermonitor --demo # 模拟模式,无硬件,默认入口
132
+ powermonitor --open 录制目录 # 离线打开已有 .pmcap 录制
133
+ ```
134
+
135
+ 从源码运行时把 `powermonitor` 换成 `python -m powermonitor`:
136
+
137
+ ```sh
138
+ uv run python -m powermonitor --demo
139
+ uv run python -m powermonitor --open 录制目录
140
+ ```
141
+
142
+ 本工作区也可用 `tools/run-local.sh --demo`,它优先使用 uv;没有 uv 时才回退到已有 `.venv`。模拟模式不会访问 USB,也不会给任何物理端口上电。真实 HVPM 必须在界面中手动扫描并连接。
143
+
144
+ 使用流程:Scan → Connect →(真实设备先 OFF)→ Apply target → 确认 Enable → RUN。波形页只显示电流:普通滚轮缩放时间轴,Shift+滚轮缩放电流轴,左键拖框只放大 X 时间轴并把该范围作为统计选区。图上缩放不会取消 Follow latest,实时窗口会保留缩放宽度并继续锚定最新数据;右键逐级恢复之前的 X/Y 缩放。只有手动取消 Follow 或在采集中输入固定数值选区时,视图才冻结;重新勾选后立即跳回最新数据。实时采样/录制保持 5 kHz,波形展示在 macOS 上按 2 Hz 刷新以避免 Retina/Cocoa 持续重绘卡顿。采集中的完整历史直接从正在增长的 `.pmcap/samples.bin` 只读映射,recent 10 秒缓存不再限制 X 轴;STOP 后无缝切换到最终回放并保留当前 X/Y、选区和右键缩放历史。
145
+
146
+ 电流波形按示波器方式自适应渲染,且只作用于屏幕显示,不改动采集、录制、统计或导出的任何数据:
147
+
148
+ - 放大到可见样本不超过约两个绘图区逻辑像素列一个样本时进入 raw 模式:主线逐点连接全部原始有效样本,只在缺口和无效值处断开,不平滑、不抽点。
149
+ - 样本更密时进入 aggregate 模式:每个逻辑像素列内,主线画该列有效样本的 mean 趋势点,叠加一条同色淡细线画的垂直包络,从该列真实 min 到真实 max;包络按点对绘制,列与列之间不连接。单样本尖峰由包络保留,mean 只表达该时间列的真实平均,不替代尖峰。
150
+ - 同一列内若被 GAP_BEFORE、超过 0.2 ms 容差的时间跳变、NaN/Inf 或 INVALID/DEVICE_ERROR 标记分开,会拆成独立聚合组,趋势线和包络都不跨缺口;LOSS_UNKNOWN 不隐藏当前值。首尾部分列只按实际落入样本计算,空列不画。
151
+ - 主线和包络都显式关闭 pyqtgraph 的 peak 二次降采样和视口裁剪;缩放或平移后按新的原始视口重新聚合,而不是放大旧包络。因此缩小视图是“平均趋势 + 真实范围”,放大后自动看到全部原始点,不再把每个抽取桶的 min/max 极值按时间连成原始信号中不存在的锯齿折线。图下常显平均电流/功率;完整统计与原始表格分别在 Statistics / Raw samples。STOP 只停采集,OFF 单独关断;录制路径始终显示,结束后自动回放,未主动删除录制。
152
+
153
+ 无硬件验证用统一入口(自动设置 offscreen Qt 平台,顺序执行 ruff、应用源码 Pyright、排除性能阈值项的稳定 pytest;依赖一致性另由 `uv pip check` 验证):
154
+
155
+ ```sh
156
+ uv run python tools/validate.py
157
+ ```
158
+
159
+ 刷新耗时阈值依赖主机负载,单独执行:
160
+
161
+ ```sh
162
+ QT_QPA_PLATFORM=offscreen uv run pytest -q -m performance
163
+ ```
164
+
165
+ 稳定入口包含离屏 Qt 交互测试;原生 X11 窗口的端到端验证命令如下(需 Xvfb 及 Qt X11 依赖):
166
+
167
+ ```sh
168
+ QT_QPA_PLATFORM=xcb xvfb-run -a -s '-screen 0 1440x1100x24' \
169
+ uv run python tools/gui_smoke.py artifacts/gui-run
170
+ ```
171
+
172
+ 目标目录必须不存在。脚本仅操作模拟器,真实点击供电确认、采样与导出控件,保存浅/深色波形、统计和数据表截图;添加 `--seconds 600` 可执行十分钟窗口耐久测试。
173
+
174
+ 一个用于复现实验环境的参考冻结版本见 `requirements-linux.lock.txt`(Linux x86_64 / Python 3.10,仅供参考,不参与包构建;macOS 需另行验证并锁定自己的版本)。
175
+
176
+ ## 供电安全模型(使用前必读)
177
+
178
+ - 连接、重连、打开文件、开始采集都不会自动上电。
179
+ - 真实设备连接后输出状态为未知:必须先显式关断一次,应用才允许重新使能输出。
180
+ - 设置电压只是暂存目标值,不改变设备输出;使能需要在界面确认目标电压后才下发。
181
+ - 允许软件范围 0.80 至 13.50 V,0.01 V 步进,越界值直接拒绝。软件允许不等于待测板可承受:接入 DUT 前先确认待测板安全电压。
182
+ - RUN/STOP 只控制采集,不停电;关断按钮独立且始终可达。采集中按关断会先停止采集、退出采样模式,再下发 0 V,且不自动恢复采集。
183
+ - 关断或通信失败时输出状态按未知处理,不假定已断电。正常退出只关闭本次应用使能的输出,不替其他来源的输出负责。
184
+ - 详细硬件接线与验收步骤见 [硬件验收清单](docs/hardware-validation.md)。
185
+
186
+ ## 数据与时间轴说明
187
+
188
+ - 内部单位统一为秒、安培、伏特;SDK 上报电流为毫安,适配层换算为安培。
189
+ - SDK 时间戳是主机收到 USB 包的秒级时间,同一包内所有样本相同。应用同时保存该原值(host_elapsed_s)和按样本序号、标称 5 kHz 重建的时间轴(time_s,相邻样本 0.2 ms)。重建时间不是硬件采样时间,界面与导出均按此标注。
190
+ - 录制格式为目录形式的 `.pmcap`:metadata.json、samples.bin、events.jsonl,不使用 pickle。异常退出的录制带不完整标记,回放时提示尾部截断。
191
+ - 选区为左闭右开区间,统计只基于原始样本,缺口不补零、不跨缺口积分;时间轴存在无法定位的丢样时结果标记为不完整。
192
+ - 屏幕波形的 raw/aggregate 切换只用于显示层。Cursor、键盘游标、Statistics、CSV 导出和 Raw samples 表格始终读取原始 records,从不读取 mean 主线或 min/max 包络。
193
+
194
+ ## 文档
195
+
196
+ - [第三方许可与内置 SDK 说明](THIRD_PARTY_NOTICES.md)
197
+ - [SDK 适配说明](docs/sdk-notes.md)
198
+ - [硬件验收清单](docs/hardware-validation.md)
199
+ - [实现接口契约](docs/implementation-contract.md)
@@ -0,0 +1,160 @@
1
+ # powermonitor-hvpm
2
+
3
+ Monsoon HVPM 功耗监测桌面工具:Python 3 + PySide6,本地离线运行。支持无硬件的确定性模拟模式,以及通过内置(vendored)的官方 PyMonsoon SDK 连接真实 HVPM,完成供电控制、实时电流波形、时间窗口统计、原始录制保存、离线回放和 CSV 导出。电压和功率仍保留在原始数据、统计和 CSV 中,不再单独绘制波形。
4
+
5
+ 通信所需的 PyMonsoon SDK 已按固定上游 commit 私有内置进本项目包内,安装本分发即可使用,无需再从 GitHub 安装任何 `Monsoon` 包,运行环境中也不存在外部顶层 `Monsoon` 命名空间。内置范围、相对上游的机械性改动和许可证事实见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
6
+
7
+ 首版仅覆盖 HVPM 主通道。不包含 LVPM、USB/Aux 通道控制、触发采集、PT5 兼容、固件升级和远程控制。
8
+
9
+ ## 状态
10
+
11
+ - Linux 模拟模式与自动化已验证:供电控制、5 kHz 录制、单电流波形、窗口统计、CSV 和回放;具体结果见 [验证记录](docs/validation-results.md)。
12
+ - macOS 模拟模式(simulator)的软件验证已通过;真实硬件的 USB 联调在 macOS 上仍未实测,见下文平台说明。
13
+ - 真实 HVPM:适配按固定 SDK 版本实现,实物验收尚未进行,见 [硬件验收清单](docs/hardware-validation.md)。
14
+
15
+ 不要把模拟结果当作实机结果。
16
+
17
+ ## 环境要求
18
+
19
+ - Linux(参考环境 Ubuntu 22.04,glibc 2.35)或 macOS。
20
+ - Python 3.10 至 3.13。
21
+ - 连接真实硬件需要系统提供 libusb-1.0 运行库及(Linux 上)相应 udev 权限;模拟模式不需要任何 USB 库。SDK 经 pyusb 访问设备,pyusb 已作为正式依赖随包安装,但它只是 libusb 的 Python 绑定,libusb 共享库本身由操作系统提供,不通过 pip 安装。
22
+ - 依赖建议预留 1.5 GB;原始录制每小时约 792 MB,CSV 通常更大。
23
+ - Linux 桌面 Qt 需要 X11/Wayland 运行库;本机 X11 缺少 `libxcb-cursor.so.0`,已通过项目虚拟环境内解压的发行版 `libxcb-cursor0` 包验证,不修改系统。常规桌面安装可由系统包管理器提供该库。
24
+ - PySide6 6.8.3 的 macOS wheel 要求 macOS 12 或更高,x86_64 与 ARM64 均有 wheel;Linux wheel 为 manylinux_2_28,要求 glibc 不低于 2.28。
25
+
26
+ ## 安装
27
+
28
+ ### 用户主路径(PyPI)
29
+
30
+ ```sh
31
+ pip install powermonitor-hvpm
32
+ ```
33
+
34
+ 安装后直接运行命令:
35
+
36
+ ```sh
37
+ powermonitor --demo
38
+ ```
39
+
40
+ 分发包名为 `powermonitor-hvpm`,安装提供的命令仍为 `powermonitor`。上述命令安装的是发布到 PyPI 的正式依赖(numpy、PySide6、pyqtgraph、pyusb),不含外部 `Monsoon` 包,也不需要访问 github.com。
41
+
42
+ ### 开发者 / 从源码运行
43
+
44
+ 推荐使用 uv,在项目根目录执行:
45
+
46
+ ```sh
47
+ uv sync --extra test
48
+ ```
49
+
50
+ 然后所有命令都通过 `uv run` 执行,例如:
51
+
52
+ ```sh
53
+ uv run python -m powermonitor --demo
54
+ uv run python tools/validate.py
55
+ ```
56
+
57
+ 此时模拟模式功能完整;内置 SDK 的协议、生命周期和版本固定测试无需实物即可运行,只有真实 USB/供电验收需要 HVPM。发布打包工具放在独立的 `release` dependency group(build、twine),仅在构建分发包时需要:
58
+
59
+ ```sh
60
+ uv run --group release python -m build
61
+ uv run --group release twine check dist/*
62
+ ```
63
+
64
+ 如不用 uv,也可以手动 venv:
65
+
66
+ ```sh
67
+ python3 -m venv .venv
68
+ . .venv/bin/activate
69
+ python -m pip install --upgrade pip
70
+ pip install -e '.[test]'
71
+ ```
72
+
73
+ 不要安装 PyPI 上的 `monsoon` 包:本项目不依赖它,内置 SDK 位于本项目包内,额外安装同名外部包没有作用,还可能造成命名混淆。
74
+
75
+ ### Linux USB 权限(仅真实硬件)
76
+
77
+ 内置 SDK 通过 pyusb 访问 USB VID 0x2AB9 / PID 0x0001。系统通常已自带 libusb-1.0;若发行版未提供,用发行版自己的包管理器安装,不使用 sudo pip。
78
+
79
+ 默认 udev 规则下非 root 用户通常无法直接打开设备。最小权限做法是新增一条只匹配该 VID/PID 的 udev 规则,把设备节点授权给一个专用用户组(如 `plugdev`,前提是当前用户已在该组),例如:
80
+
81
+ ```text
82
+ SUBSYSTEM=="usb", ATTRS{idVendor}=="2ab9", ATTRS{idProduct}=="0001", MODE="0660", GROUP="plugdev"
83
+ ```
84
+
85
+ 安装或重载规则属于系统级权限变更,接入实物时确认后执行;不要长期以 root 运行应用。规则生效后重新插拔设备。macOS 不使用 udev,通常需安装系统 libusb;该平台的真实 USB 联调仍待验证。
86
+
87
+ ## 启动
88
+
89
+ 安装后启动桌面窗口(命令入口):
90
+
91
+ ```sh
92
+ powermonitor --demo # 模拟模式,无硬件,默认入口
93
+ powermonitor --open 录制目录 # 离线打开已有 .pmcap 录制
94
+ ```
95
+
96
+ 从源码运行时把 `powermonitor` 换成 `python -m powermonitor`:
97
+
98
+ ```sh
99
+ uv run python -m powermonitor --demo
100
+ uv run python -m powermonitor --open 录制目录
101
+ ```
102
+
103
+ 本工作区也可用 `tools/run-local.sh --demo`,它优先使用 uv;没有 uv 时才回退到已有 `.venv`。模拟模式不会访问 USB,也不会给任何物理端口上电。真实 HVPM 必须在界面中手动扫描并连接。
104
+
105
+ 使用流程:Scan → Connect →(真实设备先 OFF)→ Apply target → 确认 Enable → RUN。波形页只显示电流:普通滚轮缩放时间轴,Shift+滚轮缩放电流轴,左键拖框只放大 X 时间轴并把该范围作为统计选区。图上缩放不会取消 Follow latest,实时窗口会保留缩放宽度并继续锚定最新数据;右键逐级恢复之前的 X/Y 缩放。只有手动取消 Follow 或在采集中输入固定数值选区时,视图才冻结;重新勾选后立即跳回最新数据。实时采样/录制保持 5 kHz,波形展示在 macOS 上按 2 Hz 刷新以避免 Retina/Cocoa 持续重绘卡顿。采集中的完整历史直接从正在增长的 `.pmcap/samples.bin` 只读映射,recent 10 秒缓存不再限制 X 轴;STOP 后无缝切换到最终回放并保留当前 X/Y、选区和右键缩放历史。
106
+
107
+ 电流波形按示波器方式自适应渲染,且只作用于屏幕显示,不改动采集、录制、统计或导出的任何数据:
108
+
109
+ - 放大到可见样本不超过约两个绘图区逻辑像素列一个样本时进入 raw 模式:主线逐点连接全部原始有效样本,只在缺口和无效值处断开,不平滑、不抽点。
110
+ - 样本更密时进入 aggregate 模式:每个逻辑像素列内,主线画该列有效样本的 mean 趋势点,叠加一条同色淡细线画的垂直包络,从该列真实 min 到真实 max;包络按点对绘制,列与列之间不连接。单样本尖峰由包络保留,mean 只表达该时间列的真实平均,不替代尖峰。
111
+ - 同一列内若被 GAP_BEFORE、超过 0.2 ms 容差的时间跳变、NaN/Inf 或 INVALID/DEVICE_ERROR 标记分开,会拆成独立聚合组,趋势线和包络都不跨缺口;LOSS_UNKNOWN 不隐藏当前值。首尾部分列只按实际落入样本计算,空列不画。
112
+ - 主线和包络都显式关闭 pyqtgraph 的 peak 二次降采样和视口裁剪;缩放或平移后按新的原始视口重新聚合,而不是放大旧包络。因此缩小视图是“平均趋势 + 真实范围”,放大后自动看到全部原始点,不再把每个抽取桶的 min/max 极值按时间连成原始信号中不存在的锯齿折线。图下常显平均电流/功率;完整统计与原始表格分别在 Statistics / Raw samples。STOP 只停采集,OFF 单独关断;录制路径始终显示,结束后自动回放,未主动删除录制。
113
+
114
+ 无硬件验证用统一入口(自动设置 offscreen Qt 平台,顺序执行 ruff、应用源码 Pyright、排除性能阈值项的稳定 pytest;依赖一致性另由 `uv pip check` 验证):
115
+
116
+ ```sh
117
+ uv run python tools/validate.py
118
+ ```
119
+
120
+ 刷新耗时阈值依赖主机负载,单独执行:
121
+
122
+ ```sh
123
+ QT_QPA_PLATFORM=offscreen uv run pytest -q -m performance
124
+ ```
125
+
126
+ 稳定入口包含离屏 Qt 交互测试;原生 X11 窗口的端到端验证命令如下(需 Xvfb 及 Qt X11 依赖):
127
+
128
+ ```sh
129
+ QT_QPA_PLATFORM=xcb xvfb-run -a -s '-screen 0 1440x1100x24' \
130
+ uv run python tools/gui_smoke.py artifacts/gui-run
131
+ ```
132
+
133
+ 目标目录必须不存在。脚本仅操作模拟器,真实点击供电确认、采样与导出控件,保存浅/深色波形、统计和数据表截图;添加 `--seconds 600` 可执行十分钟窗口耐久测试。
134
+
135
+ 一个用于复现实验环境的参考冻结版本见 `requirements-linux.lock.txt`(Linux x86_64 / Python 3.10,仅供参考,不参与包构建;macOS 需另行验证并锁定自己的版本)。
136
+
137
+ ## 供电安全模型(使用前必读)
138
+
139
+ - 连接、重连、打开文件、开始采集都不会自动上电。
140
+ - 真实设备连接后输出状态为未知:必须先显式关断一次,应用才允许重新使能输出。
141
+ - 设置电压只是暂存目标值,不改变设备输出;使能需要在界面确认目标电压后才下发。
142
+ - 允许软件范围 0.80 至 13.50 V,0.01 V 步进,越界值直接拒绝。软件允许不等于待测板可承受:接入 DUT 前先确认待测板安全电压。
143
+ - RUN/STOP 只控制采集,不停电;关断按钮独立且始终可达。采集中按关断会先停止采集、退出采样模式,再下发 0 V,且不自动恢复采集。
144
+ - 关断或通信失败时输出状态按未知处理,不假定已断电。正常退出只关闭本次应用使能的输出,不替其他来源的输出负责。
145
+ - 详细硬件接线与验收步骤见 [硬件验收清单](docs/hardware-validation.md)。
146
+
147
+ ## 数据与时间轴说明
148
+
149
+ - 内部单位统一为秒、安培、伏特;SDK 上报电流为毫安,适配层换算为安培。
150
+ - SDK 时间戳是主机收到 USB 包的秒级时间,同一包内所有样本相同。应用同时保存该原值(host_elapsed_s)和按样本序号、标称 5 kHz 重建的时间轴(time_s,相邻样本 0.2 ms)。重建时间不是硬件采样时间,界面与导出均按此标注。
151
+ - 录制格式为目录形式的 `.pmcap`:metadata.json、samples.bin、events.jsonl,不使用 pickle。异常退出的录制带不完整标记,回放时提示尾部截断。
152
+ - 选区为左闭右开区间,统计只基于原始样本,缺口不补零、不跨缺口积分;时间轴存在无法定位的丢样时结果标记为不完整。
153
+ - 屏幕波形的 raw/aggregate 切换只用于显示层。Cursor、键盘游标、Statistics、CSV 导出和 Raw samples 表格始终读取原始 records,从不读取 mean 主线或 min/max 包络。
154
+
155
+ ## 文档
156
+
157
+ - [第三方许可与内置 SDK 说明](THIRD_PARTY_NOTICES.md)
158
+ - [SDK 适配说明](docs/sdk-notes.md)
159
+ - [硬件验收清单](docs/hardware-validation.md)
160
+ - [实现接口契约](docs/implementation-contract.md)
@@ -0,0 +1,55 @@
1
+ # Third-Party Notices
2
+
3
+ 本文件记录本分发中包含的第三方源代码及其改动事实。除特别说明的内置(vendored)代码外,其余第三方组件(numpy、PySide6、pyqtgraph、pyusb 等)均由包管理器在安装时从 PyPI 获取,不随本项目源码分发,其条款以各自主页或分发包为准。本文件只陈述来源与改动事实,不构成任何法律结论。
4
+
5
+ ## 内置的 Monsoon PyMonsoon SDK
6
+
7
+ 本项目内置(vendor)了官方 Python SDK 的一部分,用于与 Monsoon HVPM 通信。
8
+
9
+ - 上游仓库:https://github.com/msoon/PyMonsoon
10
+ - 上游版本:commit `1afab10eac4468bd54f0f2256a9ed870eb5346c4`
11
+ - 上游版本号标识:该 commit 的 `setup.py` 报告版本 `0.1.88`(与 PyPI 上较早发布的 `monsoon` 0.1.88 同名,但内容不能仅凭版本号判定一致,本项目只以上述 commit 为准)。
12
+ - 内置模块(五个):`HVPM.py`、`sampleEngine.py`、`Operations.py`、`pmapi.py`、`calibrationData.py`。这五个模块覆盖 HVPM 主通道设备访问、协议常量、USB 传输、校准数据与采样引擎;上游的 LVPM、命令行入口与固件刷新等模块未内置。
13
+ - 该 SDK 经 pyusb(`usb.core` / `usb.util`)通过系统 libusb-1.0 访问设备,USB VID 0x2AB9 / PID 0x0001。运行时仍需系统提供 libusb,Linux 上通常还需配置 udev 权限,详见 README。
14
+
15
+ ### 相对上游所做的改动
16
+
17
+ 在内置过程中,对上述五个模块做了以下机械性改动;设备协议、校准公式、量程切换和物理量换算逻辑保持上游原样:
18
+
19
+ 1. 改为包内相对导入:上游模块中的 `from Monsoon import ...` / `from Monsoon.calibrationData import ...` 改为指向本项目内置包的相对导入。因此本分发不再依赖、也不安装任何外部顶层 `Monsoon` 命名空间包;内置 SDK 位于本项目自己的包内。
20
+ 2. 移除未使用的 scipy 导入:`sampleEngine.py` 上游第 17、18 行为 `import scipy as sp` 与 `import scipy.stats`,但该模块源码中没有任何对 `sp` 或 `scipy` 的实际调用。内置版本删除了这两行导入,因此本项目运行依赖中不再需要 scipy。
21
+ 3. 修正一处 Python 字符串比较:`platform.system() is "Windows"` 改为语义等价且正确的 `==`,避免解释器的 `SyntaxWarning`。
22
+ 4. 在上游模块首部增加仅用于本项目工具链的 `ruff` / `pyright` 文件级说明;这些说明不改变运行时行为。
23
+ 5. 清理行尾空白并统一文本文件末尾换行,不改变运行时行为。
24
+ 6. 除上述机械性改动外,未改动采样、校准与协议处理代码。
25
+
26
+ ### 上游许可证(事实记录)
27
+
28
+ - 该 commit 自带 `LICENSE.txt`,文本为标准 MIT 授权,版权署名 Monsoon Solutions, Inc. (2017);其 `setup.py` 中 `license='MIT'`。
29
+ - 同一 `setup.py` 的 trove classifier 写的是 `License :: OSI Approved :: GNU General Public License (GPL)`,与 `LICENSE.txt` 文本及 `license` 字段不一致。本项目仅如实记录这一不一致,不就适用条款作结论;对外分发前由责任人自行向上游确认。
30
+
31
+ 上游 MIT 授权文本(按上游 `LICENSE.txt` 标准 MIT 文本转录):
32
+
33
+ ```
34
+ MIT License
35
+
36
+ Copyright (c) 2017 Monsoon Solutions, Inc.
37
+
38
+ Permission is hereby granted, free of charge, to any person obtaining a copy
39
+ of this software and associated documentation files (the "Software"), to deal
40
+ in the Software without restriction, including without limitation the rights
41
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42
+ copies of the Software, and to permit persons to whom the Software is
43
+ furnished to do so, subject to the following conditions:
44
+
45
+ The above copyright notice and this permission notice shall be included in all
46
+ copies or substantial portions of the Software.
47
+
48
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
54
+ SOFTWARE.
55
+ ```
@@ -0,0 +1,84 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "powermonitor-hvpm"
7
+ version = "0.1.0"
8
+ description = "Offline-first Monsoon HVPM desktop capture and analysis"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10,<3.14"
11
+ license = "MIT"
12
+ license-files = ["LICENSE", "THIRD_PARTY_NOTICES.md"]
13
+ authors = [{ name = "XuNeo" }]
14
+ keywords = [
15
+ "monsoon",
16
+ "hvpm",
17
+ "power-monitor",
18
+ "power-measurement",
19
+ "embedded",
20
+ "current-sensing",
21
+ "pyside6",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 4 - Beta",
25
+ "Environment :: X11 Applications :: Qt",
26
+ "Intended Audience :: Developers",
27
+ "Operating System :: POSIX :: Linux",
28
+ "Operating System :: MacOS :: MacOS X",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.10",
31
+ "Programming Language :: Python :: 3.11",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Programming Language :: Python :: 3.13",
34
+ "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
35
+ "Topic :: System :: Hardware :: Hardware Drivers",
36
+ ]
37
+ dependencies = [
38
+ "numpy>=1.25,<3",
39
+ "PySide6==6.8.3",
40
+ "pyqtgraph==0.14.0",
41
+ "pyusb>=1.3,<2",
42
+ ]
43
+
44
+ [project.optional-dependencies]
45
+ test = ["pytest>=8,<10", "pytest-qt>=4.4,<5", "psutil>=6", "ruff>=0.9", "pyright>=1.1"]
46
+
47
+ [dependency-groups]
48
+ release = [
49
+ "build>=1.2,<2",
50
+ "twine>=5,<7",
51
+ ]
52
+
53
+ [project.urls]
54
+ Homepage = "https://github.com/XuNeo/powermonitor-hvpm"
55
+ Repository = "https://github.com/XuNeo/powermonitor-hvpm"
56
+ Issues = "https://github.com/XuNeo/powermonitor-hvpm/issues"
57
+ Changelog = "https://github.com/XuNeo/powermonitor-hvpm/releases"
58
+
59
+ [project.scripts]
60
+ powermonitor = "powermonitor.app:main"
61
+
62
+ [tool.setuptools.packages.find]
63
+ where = ["src"]
64
+
65
+ [tool.setuptools.package-data]
66
+ "powermonitor._vendor.pymonsoon" = ["LICENSE.txt"]
67
+
68
+ [tool.pytest.ini_options]
69
+ testpaths = ["tests"]
70
+ qt_api = "pyside6"
71
+ markers = ["performance: extended performance checks", "sdk: tests against the pinned official SDK"]
72
+
73
+ [tool.pyright]
74
+ venvPath = "."
75
+ venv = ".venv"
76
+ include = ["src", "tests", "tools"]
77
+ extraPaths = ["src"]
78
+ pythonVersion = "3.10"
79
+
80
+ [tool.ruff]
81
+ line-length = 100
82
+
83
+ [tool.ruff.lint]
84
+ select = ["E", "F", "I"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """Monsoon HVPM capture, simulation and offline analysis."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,7 @@
1
+ """Run the desktop application with `python -m powermonitor`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .app import main
6
+
7
+ raise SystemExit(main())
@@ -0,0 +1 @@
1
+ """Vendored third-party packages used by powermonitor."""