找回密码
 注册
关于网站域名变更的通知
查看: 431|回复: 2
打印 上一主题 下一主题

MATLAB程序调试基本方法分享

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-4-16 10:06 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
MATLAB程序调试基本方法分享' r8 M  z5 {7 j4 s4 W
前言5 W7 g) o( m9 _) N/ Y/ H9 F  U
    本文主要是对MATLAB程序调试中的一般方法进行总结,也是自己学习的记录。全文大致分为三个段落:+ Y+ z8 r( s. B4 J- |. s
8 p) T7 T1 Y9 z4 x  f& B- _
  1)代码内调试;( a2 h* g2 ?' p% k8 B) R+ P' h5 T

5 D5 z4 K2 Q* d2 c+ E2 o/ J  2)断点调试方法;# U+ \1 z6 Q) M# V" v0 q# v4 J
. m( d8 W; B) m3 i8 x: h2 G
  3)指令调试方法;* K) @' u. X: e7 O3 v
6 N  V1 L! n$ I" l$ Z
本文主要为个人学习总结,并借鉴了前人的经验,相应链接在最后一并附上。
$ {6 N1 s9 C0 D) u
0 ]% W/ u# _, m
* t; C* j: ~' b
一、代码内调试
" M' p2 d6 j+ ~8 H    A-打印变量
- N' c6 b& e: Z, i$ Z$ p
  • z=hilbert(testdata');                   % 希尔伯特变换
  • a=abs(z)                                    % 包络线
  • fnor=instfreq(z);                       % 瞬时频率
    8 d  J0 M8 T6 z3 J

. m, ~; d, A1 |5 v

$ b4 L5 K7 g/ a( L3 j# P$ w7 w% H: l上面的代码,如果希望检查a是否正常:去掉末尾的分号;,即可在Command Window查看到对应的输出信息,特别是当变量出现在function时,如果不输出,则在Workspace中无法直接查看,此时该操作较方便。
1 F2 A- [8 f2 i% t  D, z    B-局部执行
( _+ L8 C2 K' t1 i% P* t
  • z=hilbert(testdata');                   % 希尔伯特变换
  • a=abs(z);                               % 包络线
  • fnor=instfreq(z);                       % 瞬时频率# i) y: U8 v! y( X; @, k) _
4 V% p* m/ P# ?) |3 O

- }5 s* T* r: e3 G$ b如果希望对某一部分代码,进行调试,则完全没有必要每次都从头运行,这时局部执行较方便。仍是这段代码,如果希望仅仅执行高亮部分,则箭头选中并按F9,此时程序仅仅运行高亮部分,可利用这个方法调试局部代码。
( ]3 W! ]& |$ g6 k( g0 D    C-配合绘图(该操作可以配合以下各类方法使用)+ Z: A4 o+ x. E2 m( u
图形比数据更易于观察,在调试过程中打开Workspace中的变量(快捷键:Crtl + D),然后选择plot,即可根据需求对数据进行绘图,便于观察特性:
3 s$ G# @, [% x% m+ A2 n6 p
/ a" D0 i, z: R5 z9 m  f( T
例如选择需要观察的数据,分别选择bar以及suRF指令,即可绘制对应图形:

0 L0 t4 \' f" i0 w- W

4 a& J8 y& N5 i8 |7 U. ~1 l
是不是也算方便?

( P# [* o/ u" W
2 n+ K5 G) a/ L
) f! f4 K+ Y. n0 s
二、断点调试方法

7 V. e$ v) R, g
调试代码最经典的就是利用设置断点的方法,此处给出对应快捷键:
5 C/ P% V, ~$ O0 H
  • F12:设置/取消 断点
  • F10:单步执行
  • F11:单步执行,且碰到function跳入函数内执行,F10则不会跳入,这是二者的明显区别
  • Shift + F11:跳入function之后,通过该指令推出function
  • F5:执行相邻两次断点见的所有指令,如:断点在for循环中,则F5一次,循环执行一次
  • Shift + F5:退出断点调试
    " Q& r; L  g9 D0 X' u8 w
, |/ i; }7 ?% z

* t5 R( j0 \7 ~# d6 S1 ~
三、指令调试方法
+ F  K2 L! m- k( R- M  C
    A-keyboard + (return)" A+ y# G# w! o

经常碰到一些情况,如:矩阵相乘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);! j( _3 Y' l# j4 w

! w0 y8 E, B* \
' n4 l$ X7 e6 A; ]) G6 Y

但难以确定G还是G’,利用keyboard则可以修改为:

  • keyboard
  • P_tmp = real(m+1 - max_eig);8 |: L% L/ x/ [" ^6 o4 C

9 \1 [4 l" k& j' r0 K8 c

. q8 R2 G) ~' W+ i
: B; G$ Z2 F7 K8 J

在进入K>> 之后,此时已经可以观察F、G的size,因此在Command Windows输入:

  • max_eig = max( eig(G'*pinv(F)*G) );
  • return;
    ( E- x9 W  ~$ {4 S0 _/ N1 _
& K1 _* i+ b; N% W3 n0 S' Z) F

1 c3 m. q8 t7 y- P# D' l; J

即可保证程序顺利执行。

    B- try + (catch) + end

我们知道,matlab的代码是按行执行的,如果碰到错误行,则程序中断。try..catch可以使得可能出错的代码不影响后面代码的继续执行,也可以检查,排查,解决程序的一些错误,增强代码的鲁棒性和可靠性。

  • try ... end
    6 ^. Y: c8 C3 c: B3 R
try...end用于尝试运行一段也许可能出错的代码,比如:
  • m = rand(3,4);
  • n = magic(5);
  • try
  •     a = m*n;
  •     disp(a)
  • end
  • disp(m)
    ; U$ t. [! |3 |7 j0 u
$ C1 M' l4 n8 h6 p
0 S4 j3 m6 `) _% w
这段代码里面,a = m*n运行会出错,不满足矩阵乘法的原则。所以,a = m*n和disp(a)不执行,但后面的disp(m)亦然会执行。' L  z& E9 S& @' T* X
  • try...catch...end. l* v: t3 V5 ?: q9 X. A$ a

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)9 d7 F9 R. F8 e0 r/ z; y8 M

2 p1 W9 x: Y  p+ U. v/ z* a
5 a; z3 O! B1 u) x; l( z

这里面,当程序碰到 a = m*n;错误后,就会跳转到catch里面的语句,继续执行,有点类似于if...else...end。

    C-dbstop

  • dbstop if error9 f5 Y, Q& Z7 ?5 K, f

在程序执行前输入:

  • dbstop if error
  • %================以下为main部分=================
  • ....%略
    - D' S5 I% \1 c* `, j

' b; \9 r( x! P1 b9 w; E

  a3 C: H0 a  H7 H) L( |- [" ?

 如果运行出现错误,matlab会自动停在出错的那行,并且保存所有相关变量。真心好用。

  • dbstop in file
    , k' W2 p( C2 Z

  在.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);
    . r' e7 l' V) Q7 N# w8 K6 `- g' w" H
6 `: G; w3 ]! M
, T) g8 h( X3 O0 F# @

效果如下:


, {9 }4 b6 e5 T, D& \2 z6 F

即设置断点并运行至VMD程序内部,此时通过F10/F11/Shift F11等断点操作中的快捷键,即可进行调试,Command Windows输入dbquit即可退出。

  • dbstop in file at location if expression
    ) w. R9 D# E$ @$ m3 L' X  @

比如有myprogram.m, 如下:

  • clear all;
  • close all
  • clc;
  • x = ones(1,10);
  • for n = 1:10
  •   x(n) = x(n) + 1;
  • end0 Y: {7 l2 b9 z( p5 k+ _% M: _" \
, `; g7 Y3 ~9 l3 z- q

6 i4 X, N( y' k$ p( g& d4 k5 J

设置一个断点在 n >= 4时(对应程序位置为第6行),然后再运行程序:

  • dbstop in myprogram at 6 if n>=4;
  • myprogram;: t% c+ ]3 o( R; l5 A

* \5 |. e, |: g

3 ^1 _! Y7 t& P2 T+ |

  这时有:

  • 6   x(n) = x(n) + 1;
  • K>>
  • Type dbquit to exit debug mode.
    & K& b, h$ P7 M0 g

4 [3 P3 U. l; T$ N, T7 N
* i4 l( c. ~! {1 H6 u

可见,dbstop比断点设置更加智能,控制起来更为方便。补充一句:

  • dbstop in file at location   %在指定行设置断点
    # G5 m( w- Z! w

! E) d! c, J. K8 u+ f1 s: O6 ?' b) e
6 f+ G- U; o4 P2 r' p! f3 x' I

此时与F12等价。

所有dbstop,可配合return或者dbstop使用;! C6 u7 ?" [0 S, b& v9 T8 L
  return:返回;: j- V3 X. }2 N8 e% B0 u+ w
  dbstop:停止

" F$ }0 _, X9 Q8 O  C  k0 j) Z" x; M

调试完成,需要清除所有断点:

  • 清除所有M文件的所有断点, x! G* n% H- z4 [0 L7 E- H

在Command Windows输入:

  • dbclear all
    & N1 P: O: f; l* {) J

) i1 O& O& D* O5 y

% `& b. w# X% n  t, s1 D4 z
  • 清除文件名为mfile的文件的所有断点
    7 t# X  c- P3 i' w% q5 F

在Command Windows输入:

  • dbclear all in mfile:
    8 B; [* r  r& B0 I0 v* T( M

* l) H8 {- E) b, Y; E
' m% \% A' i, g5 ?
  • 其他dbstop相关(前文所述,已满足基本Debug,此处列出其他操作,不再展开介绍,供感兴趣的朋友阅读):
    % m, G9 O$ x# Q4 p) C3 G5 @8 r
(1)设置断点:

* dbstop in mfile:在文件名为mfile的M文件第一个可执行语句前设断点;  
$ a* \' o2 z' g5 l8 V( x5 j* dbstop in mfile at lineno:在mfile的第lineno行设断点;
% k3 O" e6 C& |2 L) X7 I0 C9 _* dbstop in mfile at subfun:当程序执行到子程序subfun时,暂时中止执行,并设断点;
, o1 ~( z. z9 r" D4 ~3 l* dbstop if error:遇到错误时,终止M文件运行,并停在错误行(不包括try...catch语句中检测到的的错误,不能在错误后重新开始运行);' J$ w' K% b6 C9 ]# p' E# ^
* dbstop if all error:遇到任何类型错误均停止(包括try...catch语句中检测到的的错误);
$ P6 ]$ J' V# J* i4 |' n$ a* dbstop if warning:程序可恢复运行;
1 F; H- k: V! T2 N3 F* dbstop if caught error:当try...catch检测到运行时间错误是,停止M文件执行,可恢复运行;
! F) k  i, L5 T3 i* dbstop if naninf 或 dbstop if infnan

(2)断点清除:

* dbclear all:清除所有M文件中的所有断点;: n9 U- W* \4 J4 v- |, p  e
* dbclear all in mfile:清除文件名为mfile的文件中的所有断点;
& ^) |! w0 s/ Z4 j+ t& D7 s9 u* dbclear in mfile:清除文件名为mfile中第一个可执行语句前的断点;; X7 X  I3 C* K3 L
* dbclear in mfile at lineno:% n" ^5 C  e, v' t6 _2 ^
* dbclear in mfile at subfun:: C5 k9 w3 R1 H0 U* ~" W
* dbclear if error/warning/naninf/infnan:

(3)恢复运行:

* dbcount:从断点处恢复程序的执行,直到下一个断点或错误后返回Matlab基本工作空间;

(4)执行一行或多行语句:

* dbstep:执行下一个可执行语句;6 [: [0 @! S. M
* dbstep nlines:执行下nlines行可执行语句;
! U( @6 ^+ M% N+ L9 E. q  a  l+ d7 M7 Z* dbstep in:执行下一行可执行语句,如有子函数,进入;3 G1 [6 o0 Y" y, `* j+ \$ d
* dbstep out:执行函数剩余部分,离开函数时停止;2 r# t4 F& c% O2 P& e5 l# \- X
* 注:这四种都返回调试模式,如遇断点,中止;


& _8 e6 b: o7 ^; P9 U. d& H5 Y

该用户从未签到

2#
发表于 2020-4-16 18:22 | 只看该作者
楼主分享的MATLAB程序调试基本方法都是些很实用的方法。

该用户从未签到

3#
发表于 2020-4-20 15:57 | 只看该作者
很实用啊,楼主好人,谢谢分享。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-7-22 15:58 , Processed in 0.125000 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表