2.1 脚本Scripts:从命令行到可复用程序


2.1 脚本 Scripts:从命令行到可复用程序

本节摘要:脚本是命令的有序集合,是 Matlab 从"交互计算器"迈向编程语言的第一步。本节讲脚本的创建运行、节区结构、工作区共享机制与适用边界,并给出一个可复现实验脚本的完整样板。

复用冲动

设想你在命令行里敲了二十行,做出了一个像样的谱分析图。第二天改个采样率要再来一遍——没有人愿意重敲。把这些行存进一个文件,一键重跑,这个动作就叫脚本。演化上它几乎没有引入新语法,却改变了使用模式:计算结果开始可复现、可交付、可修改。

创建、运行与结构

在编辑器里新建脚本,保存为合法文件名(字母开头、无空格无中文是老规矩,虽然新版已放宽,跨机器协作时仍建议遵守)。运行方式三种:编辑器的"运行"按钮、命令行敲文件名、run 命令。

现代脚本的标准做法是用双百分号切节区,配节区标题:

%% 参数设置 fs = 1000; % 采样率 Hz T = 2; % 时长 s f0 = 50; % 信号频率 Hz %% 生成信号 t = 0 : 1/fs : T-1/fs; x = sin(2*pi*f0*t) + 0.3*randn(size(t)); %% 分析与绘图 Y = fft(x); plot(t, x); xlabel('时间'); title('含噪正弦');

节区不只好看:可以单独执行某一节,调参数时不必整篇重跑。这个写法也是实时脚本的雏形——后者的演化方向是把文字说明、公式与代码融进同一篇文档。

工作区:共享是把双刃剑

脚本在基础工作区里执行,它看得见你命令行里已有的所有变量,也随时可能覆盖它们。上面例子里若命令行先有一个 t,脚本第一行就把它冲掉了。小实验里这是便利——算完所有变量直接在工作区里检查;脚本一旦超过百行或多人共用,这变成隐患。

工程实践上我建议的分工是:脚本只做三件事——设参数、调函数、看结果;任何超过十行的计算块都抽成函数。脚本长成程序的过程,就是不断把肉搬进函数的过程。

⚠️ 常见坑:脚本依赖工作区遗留变量才能跑通。症状是"单独运行报错、整篇从上到下跑却正常"。自查办法是 clear all 后再跑一遍,能跑通才算可复现。

完整样板:一次可复现的数值实验

把前面的原则拼成一个可以直接搬走的小样板。场景:比较不同噪声幅度下,FFT 主峰频率的估计误差。背景是信号处理课的常见作业,也是"参数扫描"类实验的最小原型——做法是参数设置、数据生成、计算、汇总四节分离,参数只出现在第一节。

%% 参数设置 fs = 1000; T = 2; f0 = 50; amps = [0.05 0.1 0.3 0.5 0.8]; % 待扫描的噪声幅度 rng(7); % 固定种子,保证整篇可复现 nTrial = 20; % 每档重复次数 %% 扫描计算 err = zeros(numel(amps), nTrial); for a = 1:numel(amps) for k = 1:nTrial t = 0:1/fs:T-1/fs; x = sin(2*pi*f0*t) + amps(a)*randn(size(t)); X = abs(fft(x)); [~, pk] = max(X(2:floor(numel(x)/2))); % 只搜正频率半谱 fest = (pk) * fs / numel(x); % 索引换算成频率 err(a,k) = fest - f0; end end %% 汇总 boxplot(err.', 'Labels', string(amps)); ylabel('频率估计误差'); xlabel('噪声幅度')

结果解读:噪声小时误差停在频率分辨率 fs/N(本例 0.5 Hz)的量级上——这叫分辨率受限;噪声大时误差随幅度上升,逐渐由噪声主导。两类误差机制在图上一眼可辨,这正是参数扫描实验的价值:把"哪个因素在什么区间起作用"变成看得见的曲线。变式也很直接:把 amps 换成信号时长 T 的扫描,就能观察分辨率如何随时长变细。

脚本的适用边界

脚本不是低级的形态,它有明确的舒适区。适合脚本的信号:一次性探索、参数固定不变、读者就是你自己。出现以下任一情况就该往函数迁移了——同一段计算要换参数跑第二遍;脚本超过两屏;需要给别人用;两个脚本之间出现复制粘贴。另一个容易忽视的边界是变量命名:脚本在共享工作区里跑,变量名太短(at2)容易撞车,长脚本里宁可用 rawDatafftMag 这种自解释名字,代价只有多敲几个字符。

⚠️ 常见坑:脚本顶部忘了清旧状态。样板里 rng(7) 与预分配的 err 就是防御——前者钉死随机性,后者防止上一次运行残留的同名变量被悄悄续写。

从命令行运行脚本:一次真实的排错会话

脚本保存为 freq_err_scan.m 之后,命令行就是它的启动台。一次典型的排错会话长这样:

>> which freq_err_scan % 先确认脚本能被找到 % 输出打印出该脚本所在的完整文件夹与文件名,说明它在搜索路径上 >> freq_err_scan % 敲文件名即运行(不带 .m 后缀) 未定义函数或变量 'boxplot'。 % 统计工具相关的绘图函数不在当前授权里 >> edit freq_err_scan % 打开编辑器定位到 boxplot 一行 % 临时替换为不需要额外工具箱的误差棒画法: % plot(amps, mean(err,2), '-o'); hold on % errorbar(amps, mean(err,2), std(err,2), '.'); >> freq_err_scan % 重跑,出图成功

这个会话展示了三条通用排错手法:which 确认解析到的是哪个文件(同名脚本放错目录时会命中错误的那份);报错文本本身指明缺什么能力,再决定换实现还是补授权;改完立即重跑最小验证。把 whicheditwho(列出工作区变量)这三个命令用熟,脚本阶段九成的问题都能在命令行里就地解决。

顺带交代 run 与直接敲文件名的差别:run freq_err_scan 可以带路径运行不在当前目录的脚本,行为与切换目录后敲名字等价;平时少用,但在整理项目、脚本分文件夹存放时会用到。

本节要点回顾

  • 脚本是命令的序列,与基础工作区共享变量;
  • 双百分号节区让长脚本可分段执行,也是实时脚本的祖先形态;
  • 脚本做实验、函数做产品,是控制复杂度的主线分工;
  • 可复现标准:清空工作区后整篇能跑通;
  • 文件命名守旧一点,跨平台协作少踩坑。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U