最近调一个双电机扭矩协调的模型,Scope里一次挂了六路转速、三路转矩指令和母线电压,仿真一跑起来整个Scope窗口就是一团乱麻——颜色倒是花花绿绿,可你根本说不清哪条线对应哪个信号。旁边实习生冒了一句:“给Scope加个图例不就行了?”我当时一愣,因为在印象里Simulink的Scope模块一直就没有图例功能,往常全靠自己记住颜色顺序,或者干脆把数据导到MATLAB工作区里重新画图。结果一查才发现,新版Scope早就支持图例了,只是入口藏得比较深,网上能搜到的又大多是老版本的资料,照着做根本对不上号。这篇文章就专门讲清楚Scope图例这件事,覆盖新版和旧版Scope的操作方式,也会讲信号线命名、命令行控制这些“图例好不好用”的底层细节,适合刚接触Simulink的新手,也适合从老版本过渡过来、被界面差异卡住的老用户。
1. 为什么你的Scope找不到图例选项——新旧版本差异是根源
1.1 新版Scope与旧版Scope的分水岭
先说一个最让人头疼的现实:你在网上搜“Simulink Scope 图例”,十篇教程里有八篇是老版本Scope的界面,甚至有一半讲的是“Floating Scope”(浮动示波器),这个东西在很多新版本里早就被移除或者改了交互逻辑。这就是为什么你明明跟着步骤走,却找不到人家说的那个按钮。
从一开始理清楚:MATLAB/Simulink从R2012a开始引入基于UIAxes的新版Scope,之后经过好几个版本的迭代,到了R2018b及之后,新版Scope基本已经成为默认形态。新版Scope的界面和旧版是完全两套东西,配置方式也完全不同。
为了给你一个直观感受,我把新旧Scope的主要差异列一下:
| 对比项 | 新版Scope(R2018b及以后常见) | 旧版Scope / Floating Scope |
|---|---|---|
| 窗口形态 | 独立的Figure风格窗口,带菜单栏和工具栏 | 独立窗口,工具栏很简陋 |
| 配置方式 | 通过“Configuration Properties”面板 | 通过“Parameters”对话框 |
| 是否原生支持图例 | 支持,Display选项中可勾选 | 不支持原生图例 |
| 数据光标/测量 | 内置,直接可用 | 功能非常有限 |
| 信号显示样式 | 可精细调整线型、颜色、标记 | 需要右键曲线设置,操作隐蔽 |
判断你用的Scope是哪种,有一个很简单的办法:看Scope窗口顶部的菜单栏。新版Scope会有“File、Tools、View、Help”这样的标准菜单,窗口左上角还有一个齿轮形状的“Configuration Properties”按钮。旧版Scope的工具栏更朴素,通常只有打印、缩放、参数设置这几个按钮。
1.2 网上教程为什么时灵时不灵
很多论坛帖子、问答社区里的回答,时间跨度非常大。你在2024年用R2022b或R2023b搜到一个2016年的回答,人家说的“双击信号线直接进Scope”“右键信号线选择Update Diagram”,这些在新版本里依旧成立,但真正关键的图例开启入口已经完全变化。
还有一个特别常见的误区:经常有人把Scope和"Simulink Data Inspector"(信号记录查看器)混为一谈。很多教程会教你"右键信号线 -> Log Selected Signals"或"信号线 -> 连接日志",然后把数据在Data Inspector里查看。Data Inspector确实有非常完善的图例、对比、光标功能,但它是另一个工具,不是Scope模块。如果你只想让Scope窗口里能直观区分信号,那还是要从Scope本身的配置入手,不要被这些“曲线救国”的方案带偏。
所以,当你发现自己在Scope里翻来覆去找不到“图例”选项时,先不要怀疑自己是不是眼花了,先确认手里的Scope到底是新版还是旧版。这个版本判断是所有后续操作的地基。
2. 新版Scope开启图例:菜单、配置面板到显示样式
2.1 最稳妥的路径:View菜单下的Configuration Properties
新版Scope开启图例的操作非常简单,麻烦的是版本不同入口略有差异。我这边以R2019b到R2023b等几个常用版本为例,下面这条路径几乎都能走通:
- 双击模型中的Scope模块,打开Scope窗口。
- 在Scope窗口顶部菜单栏点击“View -> Configuration Properties”,或者直接点击工具栏上的齿轮图标。
- 在弹出的“Configuration Properties”配置面板中,找到“Display”选项卡。
- 在Display选项卡中,勾选“Legend”复选框。
- 点击“Apply”或“OK”按钮。
只要勾选了Legend,Scope绘图区的右上角(默认位置)就会立刻出现一个图例框,里面列出了当前显示的所有信号名以及对应的曲线颜色。这里有个值得说的点:新版Scope的配置面板是选项卡式的,不同版本里选项卡名称略有差异,有些版本叫“Display”,有些版本把它合并到“Main”或“Style”里,但“Legend”这个英文关键词始终存在。如果你找不到,建议直接在配置面板里用快速搜索或逐个点开看一下。
此外,如果你打开了多个Scope端口,或者一个Scope模块有多个输入端子(也就是多坐标轴模式),那每个子图会显示各自的图例,不会串到一起。这一点实测下来很舒服,不用自己手动区分。
2.2 图例显示后的细节调整:位置与多坐标轴
图例打开之后,还有一个经常被忽略的问题——位置。默认情况下图例出现在右上角,但如果你仿真信号的范围很宽,图例正好遮住趋势线的波峰波谷,那调整位置就是必须的操作。
在新版Scope的Configuration Properties里,Display选项卡除了Legend复选框之外,通常还有一个“Figure Legend”或“Legend position”相关的下拉选项,支持把图例放在右侧、底部、左上、右上等位置。不同版本可选的方位不完全一样,但基本都能覆盖主要需求。如果找不到这个选项,也可以直接在Scope窗口里尝试拖动图例框,部分版本支持鼠标拖拽移动。
还有几个和显示效果相关的属性值得顺手配置:
- Grid(网格):开启后曲线对比时更容易定位数值。
- Data Cursor(数据光标):鼠标悬停时显示具体坐标值,排查问题非常有用。
- Axes Colors(背景色):默认黑色背景看时间长了眼睛累,可以改成白色,论文截图也更干净。
这些选项虽然和图例没有直接关系,但搭配使用才能让Scope真正变成“能看懂的示波器”,而不只是挂了个图例的花架子。
有一点必须说明:新版Scope的图例是实时绑定信号名的,也就是说仿真过程中图例会跟着当前显示的信号动态更新。如果你在仿真中途修改了信号名称,图例文字也会立刻改变,这比导出数据后手动加图例要灵活得多。
3. 图例显示“#1”不显示信号名?先解决信号命名问题
3.1 显式命名与信号名传播
很多人遇到过一个尴尬的场面:好不容易把图例选项打开了,结果图例里显示的是“1”、“2”、“3”,或者是一长串看不懂的“signal.1”“Constant.1”之类的文本。这时候问题的根源不在图例本身,而在信号线没有名字。
Simulink的Scope图例显示的文本,遵循一个优先级规则:如果信号线被显式命名,图例就显示这个信号线的名称;如果信号线没有手工命名,Simulink会尝试从上游模块传播信号名,比如Constant模块输出端口的信号名传播到线上,图例可能显示成“Constant.1”;如果上游也没有可传播的名称,图例就只能用编号或模块路径来占位了。
所以,想要图例可读,第一步是给信号线命名,具体操作有两个办法:
- 双击信号线,光标会自动变成文本输入状态,直接输入信号名,回车确认。
- 右键信号线 -> Properties,在“Signal name”一栏填写名称,点击OK。
这两种方式效果一样,双击最方便。我个人的使用习惯是:在搭模型阶段就顺手给每条分支信号命名,尤其是要送入Scope的信号,一定先用下划线分隔的关键词命名,比如“speed_left_motor”“torque_right_motor”这种。这样不管是Scope图例、数据记录还是后期做Find Signal分析,都清晰得多。
3.2 常见显示异常:中文乱码、重名、端口编号
信号名命好之后,依然会遇到几个具体的显示异常,这里分别说说。
中文信号名乱码。新版Scope在Windows系统下对中文支持已经很好了,但如果你用的是旧版,或者系统字体配置有问题,中文信号名可能显示成乱码方块。即便显示正常,中文名在命令行分析、跨平台模型共享时也容易出现编码问题。所以在模型里给信号命名,我的原则是“能英文就英文,能拼音就拼音”,不建议用中文。
信号重名。当两条信号线都叫“speed”,Scope图例会显示成“speed”和“speed_1”或者“speed:1”“speed:2”,版本不同处理方式不同。与其事后看这些自动加的后缀去猜哪条是哪条,不如一开始就把名字起得足够具体。比如“speed_ref”和“speed_feedback”分开,图例一目了然。
端口编号显示。如果你用的是Mux或Bus Creator将多路信号合并后送入Scope,Scope只能看到合并后的信号,图例可能只显示Mux的输出线名称,而不是里面每个分量的名字。解决办法是通过Mux模块时,在进入Mux之前的每条信号线上都命名好,然后在Scope的图例中就能看到“Mux.Signal1”形式的分量名。如果想要更干净,直接在Scope输入前把Mux展开、用多个输入端口分别接入,让每个信号都有自己的显示轴,图例也会更清晰。
信号名带空格或特殊符号。Scope图例能显示空格,但后续命令行操作很麻烦,比如find_system、get_param里引用带空格的信号名都会增加转义难度。建议命名时统一用英文字母、数字、下划线,不要用空格和中文符号。
我之前就是因为信号没命名,图例打开后一片“1、2、3”,在排查一个反馈环路的振荡问题时花了整整一个下午。后来养成了命名习惯,看图例比对信号趋势,基本两分钟就能锁定抖动是从哪个环节传过来的。
4. 旧版Scope怎么加图例:Legend模块与“打印到Figure”
4.1 Legend模块的用法与局限
如果你还在用旧版Scope,或者公司项目锁定在比较老的MATLAB版本里,那很遗憾,旧版Scope本身确实没有图例开关。这时候还可以用Simulink库里的一个隐藏利器——Legend模块。
这个模块在Simulink库浏览器里直接搜索“Legend”就能找到,放在模型画布上后,把需要显示的信号线分支连接过去,Legend模块就会自动列出所有输入信号的名称,并用对应颜色标注。具体操作步骤:
- 打开Simulink Library Browser,在搜索框输入“Legend”,从搜索结果里把Legend模块拖到模型中。
- 把需要查看图例的信号线复制一个分支(按住Ctrl拖动信号线到新位置,或者用Branch方式从原信号线上引出一条),连接到Legend模块的输入端口。
- 更新模型(Ctrl+D),Legend模块图标上就会显示所有信号名和颜色对照。
这个模块的实际效果是显示在模型画布上的一个图例框,相当于把每根线的颜色和名字贴在模型旁边。它的优点是不需要改Scope的任何设置,缺点是图例不会嵌进Scope窗口里,而是作为模型的一部分显示,截图时有时会显得散。
Legend模块还有一个比较烦人的限制:如果信号线没有名字,它照样只能显示编号。所以无论你用新版还是旧版,信号命名都是绕不开的基础工作。
4.2 兜底方案:Print to Figure后手动加图例
除了Legend模块,还有一个被很多人当成“标准答案”的老办法,就是先Scope截图、再导成Figure手动加图例。实际上这个方法直到现在依然好用,特别是做论文配图。
操作路径是这样的:
- 在Scope窗口的菜单栏选择“File -> Print to Figure”(部分版本写作“Print to Figure…”)。
- Scope会把当前画面转换成一个独立的MATLAB Figure窗口。
- 在生成的Figure中,用标准的MATLAB
legend命令手动添加图例。
% 假设当前打开的Figure是scope导出的 legend('speed_ref', 'speed_feedback', 'torque_cmd');这个方法最大的好处是能精确控制图例内容、位置、字体大小,方便直接用于论文或技术报告。缺点也相当明显:它是静态的,仿真运行过程中不会实时更新,每次修改模型参数后都需要重新导出。
我平时做控制算法验证时,Scope窗口开着图例看实时趋势,最后正式出图时再用Print to Figure导一次,把图例位置和字体调好,这样既兼顾了调试效率又保证了出图质量。
5. 不想点鼠标?用ScopeConfiguration脚本化控制图例
5.1 在命令行中读取和修改Scope配置
如果你经常批量处理模型,或者写自动化测试脚本时需要统一打开多个Scope的图例,手动点配置面板就很低效了。新版Scope的上层配置对象是ScopeConfiguration,通过get_param可以拿到它,然后直接用命令操作。
核心代码非常简单:
% 获取模型中Scope模块的配置对象 cfg = get_param('my_model/Scope', 'ScopeConfiguration'); % 开启图例 cfg.ShowLegend = true;这里的ScopeConfiguration对象实际上包含了你在Configuration Properties面板里看到的所有选项。除了ShowLegend,还有很多实用属性,比如OpenAtSimulationStart(仿真开始时是否自动打开Scope窗口)、NumInputPorts(设置输入端口数)、DisplayData(是否实时显示数据)等等。在命令行里敲一下cfg,回车,就能看到当前Scope支持的所有属性和当前值。
这个对象化配置的思路其实和图形界面是同一套数据,改任何一边,另一边都会同步生效。所以你在命令行开启图例后,下次打开Scope窗口,图例依然在。
5.2 一个可供参考的脚本化综合示例
实际项目中我经常遇到的情况是:模型里有一二十个Scope模块,分布在不同的子系统中,想给所有Scope统一打开图例并开启网格显示。如果一个个手动配置会崩溃,写个循环脚本再合适不过。
下面这段脚本可以直接复制使用,它会把模型里所有Scope模块的图例和网格都打开:
% 加载模型(请替换成你自己的模型名) load_system('my_model'); % 找到模型中的所有Scope模块 allScopes = find_system('my_model', 'BlockType', 'Scope'); % 遍历并开启图例和网格 for i = 1:numel(allScopes) % 获取该Scope的配置对象 cfg = get_param(allScopes{i}, 'ScopeConfiguration'); % 开启图例 cfg.ShowLegend = true; % 开启网格(不同版本属性名可能略有差异,若报错可注释掉) cfg.ShowGrid = true; end % 保存模型 save_system('my_model');有几个细节要提醒:
find_system默认只搜索顶层模型,不搜索子系统内部。要搜索所有层级,需要加参数'LookUnderMasks', 'all', 'FollowLinks', 'on',并把搜索深度设置为'AllLevels'。完整写法是find_system('my_model', 'LookUnderMasks', 'all', 'FollowLinks', 'on', 'BlockType', 'Scope')。ShowGrid这个属性在部分版本里可能叫ShowGrid,有些版本则需要在Axes子对象里设置。如果执行时提示属性不存在,直接删掉那一行,只保留ShowLegend的设置即可。- 脚本执行后记得保存模型,否则下次打开模型时改动会丢失。
如果只想在命令行临时设置当前仿真的Scope显示,也可以直接用set_param控制Scope模块的基础参数,比如:
set_param('my_model/Scope', 'OpenScope', 'on');但set_param这种方式能控制的属性比较有限,不如ScopeConfiguration灵活。我个人的建议是:凡是涉及Scope显示样式、图例、网格这类配置,统一走ScopeConfiguration对象,语义清晰、可读性好,也方便后续统一管理。
实际操作几次之后你就会发现,命令行配置Scope其实比鼠标点来点去更可控,特别是当你需要把模型发给同事或跑批量测试时,一份脚本比口头交代“你手动把每个Scope的图例打开”要靠谱得多。
我在实际项目中的体会是,给Scope添加图例从来不是单点操作,而是和信号命名、Scope配置、数据导出一整套习惯联系在一起的。光开图例不命名,等于没有图例;光命名图例却开在旧版本Scope里,依然无能为力。建议你拿到一个陌生模型时,先花十几秒给关键信号线补上名字,再顺手打开图例,这个习惯能帮你省下大量排查曲线的时间。