EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
MATLAB程序调试基本方法分享
0 j+ r! }; I( T+ e/ m* | |8 r前言) z) `4 _ n) B, p+ N' d" Q" N
本文主要是对MATLAB程序调试中的一般方法进行总结,也是自己学习的记录。全文大致分为三个段落:
# ^- t8 j+ G" E7 R
: |9 @/ U6 i9 L. X9 \ 1)代码内调试;+ k1 V" S# w5 @" L+ y
6 k2 _. k |" v; k, x8 P1 w2 c 2)断点调试方法;
* E. g8 {$ d* |$ Z& I$ K
B$ |/ a3 X. l# I5 a 3)指令调试方法;; j: G/ _. v/ H$ y
' d5 _) s B2 H9 h
本文主要为个人学习总结,并借鉴了前人的经验,相应链接在最后一并附上。
. J1 ?9 }5 ~4 l6 g % `! n2 v3 c6 ~" o/ d5 X, u. d
0 m$ o# q% s& N; W
一、代码内调试
; V, x6 W. H, ~ ]5 r3 T A-打印变量8 @$ [( G$ Z- k* R* H1 O
- z=hilbert(testdata'); % 希尔伯特变换
- a=abs(z) % 包络线
- fnor=instfreq(z); % 瞬时频率+ X* _9 O: G+ b8 R: }
* C9 ~5 J5 {4 O7 z. M( M% x: S- @) y3 I% `: d; m
上面的代码,如果希望检查a是否正常:去掉末尾的分号;,即可在Command Window查看到对应的输出信息,特别是当变量出现在function时,如果不输出,则在Workspace中无法直接查看,此时该操作较方便。" M" G) h' [2 [. M' J7 J
B-局部执行
$ d; O5 k" l0 q) W- z=hilbert(testdata'); % 希尔伯特变换
- a=abs(z); % 包络线
- fnor=instfreq(z); % 瞬时频率) p2 U9 t* f. E5 F: Y6 }4 g' c( P$ a
0 \ N# W- O2 F
8 u& D; H$ Q; J( a* W* m2 t如果希望对某一部分代码,进行调试,则完全没有必要每次都从头运行,这时局部执行较方便。仍是这段代码,如果希望仅仅执行高亮部分,则箭头选中并按F9,此时程序仅仅运行高亮部分,可利用这个方法调试局部代码。
- G2 @+ {4 h* i# }6 a C-配合绘图(该操作可以配合以下各类方法使用)* |1 |3 f r' P
图形比数据更易于观察,在调试过程中打开Workspace中的变量(快捷键:Crtl + D),然后选择plot,即可根据需求对数据进行绘图,便于观察特性:
5 C6 j L3 U% ~7 ^/ j% T l# I1 a# Q u \; c8 O! ]" r7 S& D
例如选择需要观察的数据,分别选择bar以及suRF指令,即可绘制对应图形: / R& d: f8 {. j2 }% i% k
4 V. W+ |# ?2 A& }是不是也算方便? . z# M3 c- ]. I! ]; `8 S
# P0 \9 C# F3 L2 V5 T! ]
% F4 }+ ~7 d* s& X, ^
二、断点调试方法
% p9 E$ ~2 k! h% ?+ R0 i调试代码最经典的就是利用设置断点的方法,此处给出对应快捷键:
+ o) i# n- u% d) n$ T- F12:设置/取消 断点
- F10:单步执行
- F11:单步执行,且碰到function跳入函数内执行,F10则不会跳入,这是二者的明显区别
- Shift + F11:跳入function之后,通过该指令推出function
- F5:执行相邻两次断点见的所有指令,如:断点在for循环中,则F5一次,循环执行一次
- Shift + F5:退出断点调试
$ x9 v2 l; W4 g B ; J. Z0 M8 S# X4 h8 }- |
4 _+ W' h- D; v- e% Q: ]" E* m
三、指令调试方法
( R! y8 ]1 A3 Y A-keyboard + (return)3 k% T# o! G' _ E7 s3 Y' M: x& k
经常碰到一些情况,如:矩阵相乘A*B时(假设A已知,B需要运算得出),矩阵B的size难以确定,是用A*B还是A'*B难以确定,可不可以先计算B,运算完之后观察B的特性,再确定用A还是A‘?keyboard可以解决这个问题。 keyboard顾名思义,就是键盘的意思,即:把控制权交给键盘。执行程序的过程中,把控制权交给键盘,如何再重新返回程序呢?因此: keyboard 与 return 通常联合使用。如执行: - max_eig = max( eig(G'*pinv(F)*G) ); %此处难以确定,还是max_eig = max( eig(G*pinv(F)*G') )
- P_tmp = real(m+1 - max_eig);
; @( b& _$ l( M) C$ f
! R; x/ o( [/ ]" I( t6 g* D8 `6 }# `3 \* |3 W2 ~) P- a: M
但难以确定G还是G’,利用keyboard则可以修改为: - keyboard
- P_tmp = real(m+1 - max_eig);
( a$ ~8 R$ a. [ 0 y+ M7 W& u6 \/ [
% X! }5 e; L: Z( k: _5 T1 X* `& z9 O9 m$ w ?* X
在进入K>> 之后,此时已经可以观察F、G的size,因此在Command Windows输入: - max_eig = max( eig(G'*pinv(F)*G) );
- return;/ q: h6 ]0 L. x. c4 n
1 q. f5 P6 w V9 u5 P
2 z b; A$ [6 D; B6 q2 e0 S% ~- d
即可保证程序顺利执行。 B- try + (catch) + end 我们知道,matlab的代码是按行执行的,如果碰到错误行,则程序中断。try..catch可以使得可能出错的代码不影响后面代码的继续执行,也可以检查,排查,解决程序的一些错误,增强代码的鲁棒性和可靠性。 - try ... end8 I+ }7 h* x7 q1 P: f
try...end用于尝试运行一段也许可能出错的代码,比如:- m = rand(3,4);
- n = magic(5);
- try
- a = m*n;
- disp(a)
- end
- disp(m)" L: m }7 a' M, E; m7 p
% G, X# J0 b" ?* S5 P$ m: Q" }' H8 N: m% A+ T0 W1 b5 Q' Y
这段代码里面,a = m*n运行会出错,不满足矩阵乘法的原则。所以,a = m*n和disp(a)不执行,但后面的disp(m)亦然会执行。: l: D# g W9 N7 a; }8 _( k
- try...catch...end
* \* W# m4 w; u& v
try...catch...end用于检查错误,如 - m = rand(3,4);
- n = magic(5);
- try
- a = m*n;
- disp(a)
- catch
- disp(size(m))
- disp(size(n))
- end
- disp(m)# e K% g: U/ y+ x9 l
6 E1 }( P. p* ~, H0 R; J0 K2 i2 ^6 A
! u& }; K' o( g* C9 m这里面,当程序碰到 a = m*n;错误后,就会跳转到catch里面的语句,继续执行,有点类似于if...else...end。 C-dbstop - dbstop if error
: t, s7 y) b; Y4 \) n, E
在程序执行前输入: - dbstop if error
- %================以下为main部分=================
- ....%略
# t; G5 j& y. u# c8 T! p% k% l . @) h' _* g9 t
% |; e( [! ~# k" q: k 如果运行出现错误,matlab会自动停在出错的那行,并且保存所有相关变量。真心好用。 - dbstop in file
7 K: i h! V/ U' {8 c6 r! W2 u
在.m文件中,插入dbstop in file指令,如下面这段程序,我们在其中加入了dbstop in VMD,其中VMD是一个function: - load './data/Gdpyear.mat'
- data=data-mean(data);%去均值,即数据中心化
- dbstop in VMD
- t=linspace(1992.0,2016.5,length(data)); %设定x轴
- for st=1:9
- K=st+1;
- [u, u_hat, omega] = VMD(data, length(data), 0, K, 0, 1, 1e-5);
- u=flipud(u);& J: I3 u; H# u$ j# X
8 ~# D+ B% ] H, ?9 m% X3 b2 `* P' ~7 ~3 Z$ ], T
效果如下:
7 I# a) L V6 u O6 G ]
即设置断点并运行至VMD程序内部,此时通过F10/F11/Shift F11等断点操作中的快捷键,即可进行调试,Command Windows输入dbquit即可退出。 - dbstop in file at location if expression
# S% m% c/ q% L% S
比如有myprogram.m, 如下: - clear all;
- close all
- clc;
- x = ones(1,10);
- for n = 1:10
- x(n) = x(n) + 1;
- end% ]* c% O6 h# F) a) \! k+ {
& x: m+ M/ _% s+ |8 P( \
! j# j; t& Y5 ?( k$ D" R设置一个断点在 n >= 4时(对应程序位置为第6行),然后再运行程序: - dbstop in myprogram at 6 if n>=4;
- myprogram;8 a" x! Y$ Q! s
% X" K; f: j& J3 M+ g5 ]& b; d" [; ^( x' {$ C
这时有: - 6 x(n) = x(n) + 1;
- K>>
- Type dbquit to exit debug mode.
7 ~& [/ e' q/ Z( `/ f1 F( b
" S" c0 _" i# g [, O- o/ B% S* f* F0 m" A
可见,dbstop比断点设置更加智能,控制起来更为方便。补充一句: - dbstop in file at location %在指定行设置断点' }, Y3 P" }' E' l
4 M0 @. Y* p- r- v6 n
9 F7 e8 {% ^8 L; g) b' `/ E
此时与F12等价。 所有dbstop,可配合return或者dbstop使用;
& A0 _" ~$ X# J return:返回;
& j: O2 p6 p4 G1 x( s& ~; ^0 P dbstop:停止
) j4 m" L8 o, e: h7 a2 @% m( A. }+ ^( n. N+ I, s7 d3 V* i% L8 p |4 \
调试完成,需要清除所有断点: - 清除所有M文件的所有断点! |/ J* x. k( C, _
在Command Windows输入: - dbclear all) K* I4 ^9 t4 g* C7 [( x
9 L* t3 e" X) Y8 W5 p c& X( |
/ ]$ W/ l0 ^* h. p# o$ J" ?% O& @- 清除文件名为mfile的文件的所有断点
" w9 [8 P( U1 V5 r2 Q( U2 f
在Command Windows输入: - dbclear all in mfile:
. }+ Y+ n$ M* ^. J ! L0 R5 X1 |' w: y
( ^+ f& B: u/ w) I$ K- 其他dbstop相关(前文所述,已满足基本Debug,此处列出其他操作,不再展开介绍,供感兴趣的朋友阅读):
; w+ h: U) s2 S) |: S
(1)设置断点: * dbstop in mfile:在文件名为mfile的M文件第一个可执行语句前设断点;
: q: b6 P q+ O- I: F* dbstop in mfile at lineno:在mfile的第lineno行设断点;
; ?3 e& }) I/ e% v9 [* dbstop in mfile at subfun:当程序执行到子程序subfun时,暂时中止执行,并设断点;
3 O4 Z/ t' W3 R1 H1 L* dbstop if error:遇到错误时,终止M文件运行,并停在错误行(不包括try...catch语句中检测到的的错误,不能在错误后重新开始运行);
( \$ Q1 Z4 q' q5 t0 }1 i* dbstop if all error:遇到任何类型错误均停止(包括try...catch语句中检测到的的错误);
( I0 F* F2 w1 A# D4 _& r N: ]8 O* dbstop if warning:程序可恢复运行;
/ A5 i) D1 {% j+ c* dbstop if caught error:当try...catch检测到运行时间错误是,停止M文件执行,可恢复运行;1 F% b6 ^1 H1 U0 V# K/ B
* dbstop if naninf 或 dbstop if infnan (2)断点清除: * dbclear all:清除所有M文件中的所有断点;
+ q8 G/ d* p- q) `* dbclear all in mfile:清除文件名为mfile的文件中的所有断点;( U7 Q9 m- r- ~& W
* dbclear in mfile:清除文件名为mfile中第一个可执行语句前的断点;
3 A+ c: d5 P7 }* i5 n* dbclear in mfile at lineno:
p" `6 _5 G9 w [* dbclear in mfile at subfun:
2 F% w6 i2 g0 b5 Q( i6 |* dbclear if error/warning/naninf/infnan: (3)恢复运行: * dbcount:从断点处恢复程序的执行,直到下一个断点或错误后返回Matlab基本工作空间; (4)执行一行或多行语句: * dbstep:执行下一个可执行语句;/ v6 @9 k8 o# N6 x2 ]+ `5 ]7 L2 H
* dbstep nlines:执行下nlines行可执行语句;
) }$ l% v5 @9 w# F! t1 I' @* dbstep in:执行下一行可执行语句,如有子函数,进入;
^/ T, }9 @& H" P$ Y; F F* dbstep out:执行函数剩余部分,离开函数时停止;
f9 C$ X+ H8 z) m6 E* 注:这四种都返回调试模式,如遇断点,中止; |
' J" q4 c! D6 v) @, S; S
|