|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
MATLAB程序调试基本方法分享
; G0 z1 Q( k+ n7 o/ ^3 b* l8 c$ c$ P前言
7 K( z' W5 r2 W4 S* z, R$ W0 d: N 本文主要是对MATLAB程序调试中的一般方法进行总结,也是自己学习的记录。全文大致分为三个段落:
- c% F/ _9 g5 A" }2 }, N n* M9 G" ]7 Y3 H& V$ A2 v! ?
1)代码内调试;
7 v9 D2 ?7 Y$ ~8 e! V2 c
2 B# a* _: I! r6 i+ T) H$ Y 2)断点调试方法;) n+ u+ j( c! E# n& k# s; ~# v
! {* R1 s0 |) |/ t: g! z# ~
3)指令调试方法;. w( V6 B& S9 X1 ^4 b& [
( R( w" @5 f1 a: U ~2 _0 z+ u1 K% m本文主要为个人学习总结,并借鉴了前人的经验,相应链接在最后一并附上。, u/ g" O& I& Z' e5 q- K: _: _
S2 k. R0 Q4 l, U1 J; |
9 ^+ `- p) v" h: \5 k: ?$ m一、代码内调试& @( c! b5 [8 n$ _% i
A-打印变量
O/ J$ b" _7 _/ L- z=hilbert(testdata'); % 希尔伯特变换
- a=abs(z) % 包络线
- fnor=instfreq(z); % 瞬时频率
/ T4 m, g5 v8 }; l/ M0 a P 1 E7 W. j. Z4 V$ @9 s
, R8 |! \ p3 F8 k5 H1 r" f
上面的代码,如果希望检查a是否正常:去掉末尾的分号;,即可在Command Window查看到对应的输出信息,特别是当变量出现在function时,如果不输出,则在Workspace中无法直接查看,此时该操作较方便。9 {' o# o6 X" _/ \* P8 t
B-局部执行; ^& W; l) _: ]% A
- z=hilbert(testdata'); % 希尔伯特变换
- a=abs(z); % 包络线
- fnor=instfreq(z); % 瞬时频率4 _5 v. u3 Z, F
5 M. H( g# \3 @/ v, o: P
' u' o: ?) [' l# q% e$ q/ c3 W如果希望对某一部分代码,进行调试,则完全没有必要每次都从头运行,这时局部执行较方便。仍是这段代码,如果希望仅仅执行高亮部分,则箭头选中并按F9,此时程序仅仅运行高亮部分,可利用这个方法调试局部代码。: ?4 x/ h! }1 Z* f
C-配合绘图(该操作可以配合以下各类方法使用)
& i. j, }% A( b- u图形比数据更易于观察,在调试过程中打开Workspace中的变量(快捷键:Crtl + D),然后选择plot,即可根据需求对数据进行绘图,便于观察特性:
( g* x# I2 Y+ V* y1 U* E0 z" g
- K3 ], ]# @: B4 [$ t8 o; }% ?. h例如选择需要观察的数据,分别选择bar以及suRF指令,即可绘制对应图形:
: j2 k- M# F& K- l9 b/ K2 b/ b; _" y* ]" u( F- c
是不是也算方便?
' r3 H% c3 i! o9 I6 F& E
: G5 W% `" I! Q v 7 {& g2 b, g2 B" c- {. F
二、断点调试方法 ) \6 W8 D J- W c+ W9 q+ h# L# d2 `# ]
调试代码最经典的就是利用设置断点的方法,此处给出对应快捷键: & r# t- ^4 `2 Z+ m3 x# q
- F12:设置/取消 断点
- F10:单步执行
- F11:单步执行,且碰到function跳入函数内执行,F10则不会跳入,这是二者的明显区别
- Shift + F11:跳入function之后,通过该指令推出function
- F5:执行相邻两次断点见的所有指令,如:断点在for循环中,则F5一次,循环执行一次
- Shift + F5:退出断点调试2 m: A- @; C, E+ J
! @4 |0 a2 B# T! ]9 x
4 q( K: S X. N+ v
三、指令调试方法
) u' q0 f4 M4 n' I0 V, S A-keyboard + (return)6 S8 S/ @ m- Y1 o7 g' {6 J+ y3 B
经常碰到一些情况,如:矩阵相乘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);) b9 `4 y' {: \. X/ V( B
) S( X2 @' V, w5 ]7 @8 h: h/ [
6 v# w6 H7 k5 u* N; E" S但难以确定G还是G’,利用keyboard则可以修改为: - keyboard
- P_tmp = real(m+1 - max_eig);
% j# V) B: ~3 U' G, q# m7 ?
" B7 V5 K: a, U7 u a! L" P1 Q
# N" B' }: g0 o4 o1 @
. K: Q' q G8 o3 W0 e2 g7 \/ R: y1 Q在进入K>> 之后,此时已经可以观察F、G的size,因此在Command Windows输入: - max_eig = max( eig(G'*pinv(F)*G) );
- return;$ g$ J. S) d4 M+ \% E
7 t- _4 y O; G- Q& T; i9 u. j8 v1 D$ B# T0 w) X
即可保证程序顺利执行。 B- try + (catch) + end 我们知道,matlab的代码是按行执行的,如果碰到错误行,则程序中断。try..catch可以使得可能出错的代码不影响后面代码的继续执行,也可以检查,排查,解决程序的一些错误,增强代码的鲁棒性和可靠性。 - try ... end
+ m5 K0 j1 H1 s* K" I8 D/ M, \ try...end用于尝试运行一段也许可能出错的代码,比如:- m = rand(3,4);
- n = magic(5);
- try
- a = m*n;
- disp(a)
- end
- disp(m)8 y# P. B1 Q; r5 O
6 d3 m, h+ X$ h: }- Y! [
% _5 V+ t5 @7 |# D6 Q9 L6 p7 {这段代码里面,a = m*n运行会出错,不满足矩阵乘法的原则。所以,a = m*n和disp(a)不执行,但后面的disp(m)亦然会执行。
/ l6 H4 \* P ?- try...catch...end
- C9 a1 \. s! _3 f7 ~
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)" q3 k4 `1 o1 _( |
7 Z$ N& r' ^6 n/ I& J2 n9 n W# d
9 U% z- B- b5 G- T
这里面,当程序碰到 a = m*n;错误后,就会跳转到catch里面的语句,继续执行,有点类似于if...else...end。 C-dbstop - dbstop if error
. K% B" i6 [8 }. b
在程序执行前输入: - dbstop if error
- %================以下为main部分=================
- ....%略
- K) |: a5 J3 n# M2 y - \5 c& e9 m1 X& n0 d1 X
& M2 D6 u' M* z8 J2 T' v; X
如果运行出现错误,matlab会自动停在出错的那行,并且保存所有相关变量。真心好用。 - dbstop in file
i8 c7 D; a, r5 Z0 [) f& D 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);! j4 W& d2 X, i) J) D
, o# [! v3 }! {2 k i
7 b! c/ p8 d; J效果如下:
" X) }0 G5 x3 s% K0 N
即设置断点并运行至VMD程序内部,此时通过F10/F11/Shift F11等断点操作中的快捷键,即可进行调试,Command Windows输入dbquit即可退出。 - dbstop in file at location if expression
7 P; H" q# C) m/ E1 [
比如有myprogram.m, 如下: - clear all;
- close all
- clc;
- x = ones(1,10);
- for n = 1:10
- x(n) = x(n) + 1;
- end
- N1 f, M& |# i, W# S
. B$ X8 d1 U. @. u6 j, ? x+ n: Y
* N1 ]1 w; H& Y- A1 I+ P" u5 d设置一个断点在 n >= 4时(对应程序位置为第6行),然后再运行程序: - dbstop in myprogram at 6 if n>=4;
- myprogram;
8 H) a) p" l# f8 I- V% T , e% V8 V7 s, g; s0 \; x( j! d& d5 w
& ~; x/ y- _8 x) a6 G6 ?. W( O5 D: u
这时有: - 6 x(n) = x(n) + 1;
- K>>
- Type dbquit to exit debug mode.4 C5 @8 p4 j; O7 y
# V& I, q9 k4 l9 d
/ d' a$ C2 U; U; ]可见,dbstop比断点设置更加智能,控制起来更为方便。补充一句: - dbstop in file at location %在指定行设置断点: [- k$ X c+ |( o# ?+ K0 \! D
' n$ H2 n! P, |. `: C2 D
( e( E6 F- y" g此时与F12等价。 所有dbstop,可配合return或者dbstop使用;
# j7 v) ?9 R; ]% \5 \ return:返回;
) R1 o) v* y. V7 r dbstop:停止
0 k/ B7 F5 \# W& g9 P' M" a. f! T6 K7 W" U
调试完成,需要清除所有断点: - 清除所有M文件的所有断点
$ O* ]1 B3 c! ]; b4 ?8 z
在Command Windows输入: - dbclear all& H) L4 r" t7 y9 s* c$ `( y2 }
% y0 c$ a4 _- ~5 t1 X3 @: _
5 p/ S! q( G6 r! L0 i! Z6 I6 y" u
- 清除文件名为mfile的文件的所有断点
! M' _7 g+ h2 @" n3 |' t
在Command Windows输入: - dbclear all in mfile:4 X# G, ?9 i% I
- G \; a3 t# ~" e% o2 P. \
/ J: l- M! I; y( V, E7 z
- 其他dbstop相关(前文所述,已满足基本Debug,此处列出其他操作,不再展开介绍,供感兴趣的朋友阅读):
7 A7 v' o& ]8 y( j8 i, I5 y, @
| (1)设置断点: * dbstop in mfile:在文件名为mfile的M文件第一个可执行语句前设断点;
7 Z& v+ G) i" p2 X0 F* dbstop in mfile at lineno:在mfile的第lineno行设断点;
) z7 u1 p5 I1 P* dbstop in mfile at subfun:当程序执行到子程序subfun时,暂时中止执行,并设断点;& {# H* W# K* t& Q
* dbstop if error:遇到错误时,终止M文件运行,并停在错误行(不包括try...catch语句中检测到的的错误,不能在错误后重新开始运行);- c4 ~# i- ~; n$ _
* dbstop if all error:遇到任何类型错误均停止(包括try...catch语句中检测到的的错误);3 d/ f5 B( A2 k
* dbstop if warning:程序可恢复运行;
* e7 F6 y2 a3 q* a9 d' h' M* dbstop if caught error:当try...catch检测到运行时间错误是,停止M文件执行,可恢复运行;
6 Z- Q3 I0 ^! O& A* dbstop if naninf 或 dbstop if infnan (2)断点清除: * dbclear all:清除所有M文件中的所有断点;1 [( I( T# i$ f8 [5 o' n+ U3 M3 J
* dbclear all in mfile:清除文件名为mfile的文件中的所有断点;
6 p6 x {7 m1 m3 x/ R' A+ A" p1 O* dbclear in mfile:清除文件名为mfile中第一个可执行语句前的断点;
, b d/ O/ x1 X! b3 P* dbclear in mfile at lineno:
: p7 }) ~8 c5 V8 Y# M* dbclear in mfile at subfun:
- u/ H# X2 ?5 s# q, @* dbclear if error/warning/naninf/infnan: (3)恢复运行: * dbcount:从断点处恢复程序的执行,直到下一个断点或错误后返回Matlab基本工作空间; (4)执行一行或多行语句: * dbstep:执行下一个可执行语句;) P9 |4 q% ^1 u$ t! h) G
* dbstep nlines:执行下nlines行可执行语句;& D% K' K) i( _7 {6 h
* dbstep in:执行下一行可执行语句,如有子函数,进入;& |1 c: B( B1 e7 M
* dbstep out:执行函数剩余部分,离开函数时停止;' J7 V E% s+ P; p$ L# S( N
* 注:这四种都返回调试模式,如遇断点,中止; |
$ K- {$ M" _( |; I# e- d |
|