当前位置: 首页 > news >正文

示波器traces采集

业务上遇到一个示波器traces采集的问题,他们用的采集脚本是好几年前的开源脚本,一直没有更新和维护,跟新的示波器不匹配,第一步通讯就卡住了,然后把问题抛给我。我对示波器的了解仅限于当年在大学实验课上接触过,并没有过多的了解,这次就当学习了。

方案选择

他们原本是想让我在以前的脚本上做修改,但我打开那个开源仓库,上次更新时间是在7.8年前,对于示波器都还不了解,一上来就让我改工具,未免有点为难我,还是另寻他法。

首先弄清楚示波器的型号,是 PICO3000E系列的。
搜索一圈下来,发现 pico 官方是有提供软件和SDK的,这样可以直接用官方的接口,然后再改写脚本到我们希望看到的效果就好了。
具体怎么操作,官方有提供教程:PyPicoSDK: Getting Started

环境搭建

这里跟着官方的教程走就可以。

1. 安装 PicoSDK

下载地址:https://www.picotech.com/downloads
选择具体示波器型号和系统对应的安装包就可以

2. 安装需要的 python 库

pipinstallpypicosdk pipinstallmatplotlib pipinstallscipy pipinstallpandas

安装 pypicosdk :
(可以看到结果,在这个过程 numpy 同时也被安装了)

安装 matplotlib :

安装 scipy :

安装 pandas :

编写脚本

在官方的仓库里,有提供挺多 example 可以参考的,可以在这个基础上加细节适配采集需求
官方仓库示例:examples

1. 验证示波器存在

用官方示例enumerate_units.py验证测试电脑能找到示波器,确保第一步成功

""" Copyright(C)2025-2025 Pico Technology Ltd. See LICENSEfileforterms. This example enumerates all PicoScopeunits(supported by pyPicoSDK), returns the number ofunitsand a list of serial numbers."""importpypicosdk as psdk# Enumerate unitsn_units,units=psdk.get_all_enumerated_units()# Print outputprint(f'Number of units: {n_units}')forunit, serialinunits.items(): print(f'{unit}: {serial}')

运行结果:

2. 适配采集需求

在需求的测试场景中,第一是要采集大量的traces用于后续分析,第二是要能够采集到触发的完整波形。
也就是需要解决波形问题,还有数据量的问题。

2.1 调整波形

首先是要配置好采集通道和触发条件。这个可以先打开上面安装的 PicoScope 7 T&M 这个工具,因为是图形界面,操作起来比脚本简单快速,也很直观。所以先用它调好参数,然后再把参数填到脚本中即可。
这是调好的波形:

2.2 编写脚本

是在官方simple_block_capture.py这个脚本的基础上去改的。

importpypicosdk as psdkimportnumpy as npimportmatplotlib.pyplot as pltimporttimeimportos from datetimeimportdatetime# ============================================================# User-adjustable parameters (modify according to your chip signal)# ============================================================CHANNEL=psdk.CHANNEL.A# Channel where the probe is connectedVOLTAGE_RANGE=psdk.RANGE.mV500# Voltage range, match your chip's output levelCOUPLING=psdk.COUPLING.DC# Coupling mode (usually DC for digital circuits)TRIGGER_CHANNEL=psdk.CHANNEL.A# Trigger source channelTRIGGER_THRESHOLD=200# Trigger level in voltsTRIGGER_DIRECTION=psdk.TRIGGER_DIR.RISING# Trigger on rising edgeTIMEBASE=1000000# Sample interval in seconds (1e-6 = 1 us, 1 MS/s)# sample_rate = 9_765_625TOTAL_SAMPLES=5000# Total number of samples per captureTOTAL_CAPTURES=10# PRE_TRIG_PERCENT = 10 # Samples to keep before the trigger point# POST_TRIGGER_SAMPLES = NUM_SAMPLES - PRE_TRIGGER_SAMPLES # Samples after triggerSAVE_DIR="./captured_traces"os.makedirs(SAVE_DIR,exist_ok=True)# ============================================================# 1. Connect to the oscilloscope (PicoScope 3000E uses psospa class)# ============================================================print("Connecting to PicoScope...")scope=psdk.psospa()scope.open_unit()print("Scope connected.")# Optional: print some device informationtry: driver_info=scope.get_unit_serial()print(f"device info: {driver_info}")except: pass# ============================================================# 2. Configure the input channel# ============================================================print("Configuring channel...\n")scope.set_channel(CHANNEL,enabled=True,coupling=COUPLING,range=VOLTAGE_RANGE)print("set channel success...\n")# Disable other channels to save resources# for ch in ["B", "C", "D"]:# try:# scope.set_channel(ch, enabled=False)# except:# pass# ============================================================# 3. Set up the trigger (external chip signal, no auto-trigger)# ============================================================print("Setting trigger...")scope.set_simple_trigger(TRIGGER_CHANNEL,threshold=TRIGGER_THRESHOLD,direction=TRIGGER_DIRECTION,auto_trigger=0# Disable auto-trigger; wait for a real signal edge)print(f"Waiting for trigger on Channel {TRIGGER_CHANNEL} "f"({TRIGGER_DIRECTION}, {TRIGGER_THRESHOLD}mV)...")# Perform simple block capture via help function (inc. buffer setup, time axis, mV conversion etc.)# timebase = scope.sample_rate_to_timebase(sample_rate=sample_rate)# print(f"Calculated timebase: {timebase}")channel_buffer, time_axis=scope.run_simple_block_capture(TIMEBASE, TOTAL_SAMPLES,time_unit="ms")print(f"time_axis: {time_axis}")# channel_buffers, time_axis = scope.run_simple_rapid_block_capture(TIMEBASE, TOTAL_SAMPLES, TOTAL_CAPTURES)# all_traces = channel_buffers[psdk.CHANNEL.A]# timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")# filename = f"./captured_traces/traces_{TOTAL_CAPTURES}_{timestamp}.npy"# np.save(filename, all_traces)# print(f"Saved {TOTAL_CAPTURES} tarces to {filename}")# Release the device from the driverscope.close_unit()# # Use matplotlib to setup the graph and plot the dataplt.figure(figsize=(13,5))plt.plot(time_axis, channel_buffer[psdk.CHANNEL.A])# for trace in all_traces:# plt.plot(time_axis, trace)# plt.plot(time_axis, all_traces[0])plt.xlabel("Time (ms)")plt.ylabel("Amplitude (mV)")plt.grid(True)plt.show()

(因为后续是要采集大量traces的,这里只展示采集单个波形,所以脚本显得注释掉的很多,当时也是不断的在调,修修改改,不停的看效果,然后再优化)

看下没调对触发条件是怎样的:
只有噪声,没有触发事件。

调对了trigger ,但是波形只能采集到一半

这里卡了挺久的,后面不断的调采集点samples 和 采样间隔 timebase ,才悟出来,这两个东西反相关的。采集间隔小,那么采集点要足够大,才能采集到完整波形;采集间隔大,那采集点就可以不用那么多。

timebase: 采样间隔,用于控制采样率。 timebase 和采集的样本总数samples 共同决定总采集时间窗口:总采集时间=timebase * samples

因为采集需求是要大量的traces ,所以这里牺牲采样时长来缓解内存压力,这样采样点就可以少,只是采样时间会变长。
最后采集出来的波长跟示波器捕捉到的一致。


下面这个脚本是采集多条traces 的,结果保存为 .trs 文件

importpypicosdk as psdkimportnumpy as npimportmatplotlib.pyplot as pltimportos from datetimeimportdatetimeimporttrsfile from trsfileimportTrace, SampleCoding, TracePadding, Header# ============================================================# User-adjustable parameters (modify according to your chip signal)# ============================================================CHANNEL=psdk.CHANNEL.A# Channel where the probe is connectedVOLTAGE_RANGE=psdk.RANGE.mV500# Voltage range, match your chip's output levelCOUPLING=psdk.COUPLING.DC# Coupling mode (usually DC for digital circuits)TRIGGER_CHANNEL=psdk.CHANNEL.A# Trigger source channelTRIGGER_THRESHOLD=200# Trigger level in voltsTRIGGER_DIRECTION=psdk.TRIGGER_DIR.RISING# Trigger on rising edgeTIMEBASE=10000000# Sample interval in seconds (1e-6 = 1 us, 1 MS/s)TOTAL_SAMPLES=500# Total number of samples per captureTOTAL_CAPTURES=100# PRE_TRIG_PERCENT = 10 # Samples to keep before the trigger point# POST_TRIGGER_SAMPLES = NUM_SAMPLES - PRE_TRIGGER_SAMPLES # Samples after triggerSAVE_DIR="./captured_traces"os.makedirs(SAVE_DIR,exist_ok=True)# ============================================================# 1. Connect to the oscilloscope (PicoScope 3000E uses psospa class)# ============================================================print("Connecting to PicoScope...")scope=psdk.psospa()scope.open_unit()print("Scope connected.")# Optional: print some device informationtry: driver_info=scope.get_unit_serial()print(f"device info: {driver_info}")except: pass# ============================================================# 2. Configure the input channel# ============================================================print("Configuring channel...\n")scope.set_channel(CHANNEL,enabled=True,coupling=COUPLING,range=VOLTAGE_RANGE)print("set channel success...\n")# Disable other channels to save resources# for ch in ["B", "C", "D"]:# try:# scope.set_channel(ch, enabled=False)# except:# pass# ============================================================# 3. Set up the trigger (external chip signal, no auto-trigger)# ============================================================print("Setting trigger...")scope.set_simple_trigger(TRIGGER_CHANNEL,threshold=TRIGGER_THRESHOLD,direction=TRIGGER_DIRECTION,auto_trigger=0# Disable auto-trigger; wait for a real signal edge)print(f"Waiting for trigger on Channel {TRIGGER_CHANNEL} "f"({TRIGGER_DIRECTION}, {TRIGGER_THRESHOLD}mV)...")# Perform simple block capture via help function (inc. buffer setup, time axis, mV conversion etc.)# channel_buffer, time_axis = scope.run_simple_block_capture(TIMEBASE, TOTAL_SAMPLES)channel_buffers, time_axis=scope.run_simple_rapid_block_capture(TIMEBASE, TOTAL_SAMPLES, TOTAL_CAPTURES,time_unit="ms")# print(f"time_axis: {time_axis}")all_traces=channel_buffers[psdk.CHANNEL.A]timestamp=datetime.now().strftime("%Y%m%d_%H%M%S")filename=f"./captured_traces/traces_{TOTAL_CAPTURES}_{timestamp}.trs"headers={Header.DESCRIPTION:'Encryption traces for side-channel analysis', Header.LABEL_X:'Time (ns)', Header.LABEL_Y:'Voltage (mV)', Header.SAMPLE_CODING: SampleCoding.FLOAT}with trsfile.open(filename,'w',headers=headers,TracePadding=TracePadding.AUTO)as trs_file:fori, trace_datainenumerate(all_traces): trace=Trace(SampleCoding.FLOAT, trace_data)trs_file.append(trace)if(i+1)%200==0: print(f"Writing trace {i+1}/{len(all_traces)}")print(f"Saved {len(all_traces)} traces to {filename}")# time_base, unit = scope.get_time_axis(...)# Release the device from the driverscope.close_unit()# # Use matplotlib to setup the graph and plot the data# plt.plot(time_axis, channel_buffer[psdk.CHANNEL.A])# below is to display the waveform, it's not necessary, can delete. Add here is to verify the waveform we fetched.plt.plot(time_axis, all_traces[0])plt.xlabel("Time (ms)")plt.ylabel("Amplitude (mV)")plt.grid(True)plt.show()print("traces acquisition completed")

至此,就完成了 PICO示波器的traces 采集。

http://www.jsqmd.com/news/720466/

相关文章:

  • 驾校培训办公管理系统 专属驾校的OA系统 驾培管理行业
  • Win11Debloat:让Windows系统重获清爽体验的专业优化工具
  • DeepSeek V4 深度测评:基于工程化协同方法论的 5 维实验验证
  • 躲开跨国文化陷阱:英美澳企业全英文面试中的“红牌”行为与高情商沟通术
  • Mac 访问 Linux 共享文件夹:Samba 配置完整指南
  • OpenAI 从模型研发到算力霸权的史诗跃迁
  • 2026 年无刷电机厂家口碑推荐榜:无人机电机、机器人电机、空心杯电机、无框力矩电机厂家选择指南 - 海棠依旧大
  • AI应用的可观测性工程2026:让LLM系统从黑盒变白盒
  • Paperxie AI PPT 生成器:毕业答辩 PPT 的 “懒人救星”,让你告别熬夜改模板
  • Windows Cleaner终极指南:3分钟彻底解决C盘爆红问题
  • 5分钟上手:ComfyUI-BiRefNet-ZHO智能AI图像背景去除与视频抠图工具终极指南
  • 从gethostbyname到getaddrinfo:现代Linux网络编程为何要升级你的DNS查询代码?
  • 2026年立式开装封一体机厂家推荐排行榜/开装封一体机,卧式开装封一体机 - 品牌策略师
  • 别再被PyTorch的Tensor布尔值搞晕了!手把手教你用.all()和.any()的正确姿势
  • VSCode新手必看:CodeGeeX插件安装到实战避坑全指南(2024最新版)
  • Xenia Canary终极指南:在现代PC上完美运行Xbox 360游戏的完整解决方案
  • 【触想智能】嵌入式工业一体机在智能化设备上应用产生的意义
  • UniApp动态渲染头像避坑指南:为什么你的`userInfo.avatar`在微信小程序里总变成‘/pages/index/undefined’?
  • 知识竞赛的类型与特点全面解析
  • Axure RP中文语言包:3分钟搞定专业界面本地化,告别英文烦恼!
  • PHP 8.9类型严格模式上线倒计时:3类遗留项目(Laravel 9、Symfony 6、WordPress插件)紧急适配清单
  • 【2026 Turnitin对策】英文文章AI率95%降至0%实测:掌握这4个高阶修改法
  • 如何使用MouseClick跨平台鼠标连点工具提升工作效率
  • 告别深拷贝的痛:在鸿蒙PC与ArkTS中玩转 `@ObservedV2` 装饰器
  • 如何3分钟内完成Windows文件完整性验证?HashCheck右键菜单工具完全指南
  • ComfyUI IPAdapter plus:如何用一张参考图实现精准AI图像风格迁移?
  • 蓝牙GAP通用访问协议详解:从原理到多平台实战代码
  • 【开源】我写了一个轻量级本地数据库浏览工具,支持 MySQL/Redis 只读查询
  • FIFA 23 Live Editor 完全指南:新手快速上手指南
  • 警惕!打击家教行业乱象,北师大家教中心如何成为北京家长的宠儿 - 教育资讯板