我们最喜欢的MATLAB / Octave编程技巧是什么?
我想每个人都会同意MATLAB语言不是很漂亮,或者特别是一致。但是没关系!我们仍然必须使用它来完成工作。
我们最喜欢的使事情变得容易的窍门是什么?让我们为每个答案提供一个答案,以便人们在同意的情况下可以将其投票。另外,尝试通过示例来说明答案。
解决方案
这是一个简单的例子:
我发现用逗号分隔的列表语法对于构建函数调用非常有用:
% Build a list of args, like so: args = {'a', 1, 'b', 2}; % Then expand this into arguments: output = func(args{:})
从Matlab调用Java代码
使用单个冒号将矩阵转换为向量。
x = rand(4,4); x(:)
通过在帮助注释中添加"另请参阅"行,可以快速访问其他功能文档。首先,必须在所有大写字母中包含函数名称作为第一行注释。做通常的注释标题,然后用逗号分隔其他相关功能的列表放进去。
function y = transmog(x) %TRANSMOG Transmogrifies a matrix X using reverse orthogonal eigenvectors % % Usage: % y = transmog(x) % % SEE ALSO % UNTRANSMOG, TRANSMOG2
在命令行上输入" help transmog"时,我们将在此注释标题中看到所有注释,并带有指向列出的其他功能的注释标题的超链接。
cellfun和arrayfun用于自动for循环。
用于数组操作的冒号运算符。
@ ScottieT812,提到了一个:展平数组,但是还有其他所有选择数组位的变体:
x=rand(10,10); flattened=x(:); Acolumn=x(:,10); Arow=x(10,:); y=rand(100); firstSix=y(1:6); lastSix=y(end-5:end); alternate=y(1:2:end);
使用nargin设置可选参数的默认值,并使用nargout设置可选输出参数。快速示例
function hLine=myplot(x,y,plotColor,markerType) % set defaults for optional paramters if nargin<4, markerType='none'; end if nargin<3, plotColor='k'; end hL = plot(x,y,'linetype','-', ... 'color',plotColor, ... 'marker',markerType, ... 'markerFaceColor',plotColor,'markerEdgeColor',plotColor); % return handle of plot object if required if nargout>0, hLine = hL; end
使用逻辑数组直接提取满足特定条件的矩阵元素:
x = rand(1,50) .* 100; xpart = x( x > 20 & x < 35);
现在,xpart仅包含x处于指定范围内的那些元素。
使用内置的探查器查看我的代码的热门部分在哪里:
profile on % some lines of code profile off profile viewer
或者仅使用内置的tic和toc来获得快速计时:
tic; % some lines of code toc;
使用ismember()合并由文本标识符组织的数据。当我们分析不同的条目(以公司符号为例)来回走动时,很有用。
%Merge B into A based on Text identifiers UniverseA = {'A','B','C','D'}; UniverseB = {'A','C','D'}; DataA = [20 40 60 80]; DataB = [30 50 70]; MergeData = NaN(length(UniverseA),2); MergeData(:,1) = DataA; [tf, loc] = ismember(UniverseA, UniverseB); MergeData(tf,2) = DataB(loc(tf)); MergeData = 20 30 40 NaN 60 50 80 70
哦,反转数组
v = 1:10; v_reverse = v(length(v):-1:1);
向量化循环。有很多方法可以做到这一点,并且在代码中寻找循环并查看如何将其向量化非常有趣。向量运算的性能惊人地快!
向量化:
function iNeedle = findClosest(hay,needle) %FINDCLOSEST find the indicies of the closest elements in an array. % Given two vectors [A,B], findClosest will find the indicies of the values % in vector A closest to the values in vector B. [hay iOrgHay] = sort(hay(:)'); %#ok must have row vector % Use histogram to find indices of elements in hay closest to elements in % needle. The bins are centered on values in hay, with the edges on the % midpoint between elements. [iNeedle iNeedle] = histc(needle,[-inf hay+[diff(hay)/2 inf]]); %#ok % Reversing the sorting. iNeedle = iOrgHay(iNeedle);
以下是一些不明显的函数,这些函数会不时有用:
mfilename
(返回当前正在运行的MATLAB脚本的名称)- dbstack(允许我们访问matlab函数堆栈的名称和行号)
- 键盘(停止执行并将控制权交给调试提示;这就是为什么在调试提示中出现K的原因。
- dbstop error(自动使我们进入调试模式,停止在触发错误的行)
图形中公式的LaTeX模式:在最新版本(R2006?)之一中,我们在函数调用的末尾添加了添加参数,'Interpreter','latex'
,它将使用LaTeX渲染。这是一个例子:
t=(0:0.001:1); plot(t,sin(2*pi*[t ; t+0.25])); xlabel('t'); ylabel('$\hat{y}_k=sin 2\pi (t+{k \over 4})$','Interpreter','latex'); legend({'$\hat{y}_0$','$\hat{y}_1$'},'Interpreter','latex');
不知道他们何时添加它,但是它可以在text(),title(),xlabel(),ylabel(),zlabel()甚至legend()函数中与R2006b一起使用。只要确保我们使用的语法没有歧义即可(因此,对于legend(),我们需要将字符串指定为单元格数组)。
使用sim
命令直接从脚本(而不是交互地)执行Simulink模型。我们可以执行以下操作,例如从工作空间变量中获取参数,然后在循环中反复运行" sim"以模拟某些事物,同时更改参数以查看行为如何变化,并使用所需的任何图形命令绘制结果图形。比尝试以交互方式进行操作要容易得多,并且在可视化结果时,它比Simulink"示波器"模块为我们提供了更大的灵活性。 (尽管我们不能使用它来实时查看模拟运行过程中发生的情况)
要知道的一个非常重要的事情是Simset命令的DstWorkspace和SrcWorkspace选项。这些控件控制"到工作区"和"来自工作区"块的获取和放置结果的位置。 " Dstworkspace"默认为当前工作空间(例如,如果我们从函数内部调用" sim",则" To Workspace"块将显示为可从同一函数访问的变量),但" SrcWorkspace"默认为基本工作空间,并且想要封装对sim的调用,我们需要将SrcWorkspace设置为current,因此提供了一个干净的接口来提供/获取仿真输入参数和输出。例如:
function Y=run_my_sim(t,input1,params) % runs "my_sim.mdl" % with a From Workspace block referencing I1 as an input signal % and parameters referenced as fields of the "params" structure % and output retrieved from a To Workspace block with name O1. opt = simset('SrcWorkspace','current','DstWorkspace','current'); I1 = struct('time',t,'signals',struct('values',input1,'dimensions',1)); Y = struct; Y.t = sim('my_sim',t,opt); Y.output1 = O1.signals.values;
具有[[c,h] = contour和
clabel(c,h,'fontsize',fontsize)的轮廓图。我通常使用
fontsize`参数来减小字体大小,以使数字不会相互碰到。这对于查看2D函数的值非常有用,而无需弄乱3D图形。
匿名函数,原因如下:
- 快速完成一次性功能,例如3x ^ 2 + 2x + 7. (请参见下面的清单)这对于将quad和fminbnd之类的函数作为参数的函数很有用。在脚本(不以函数头开头的.m文件)中,它也很方便,因为与真实函数不同,我们不能包含子函数。
- 用于闭包-尽管匿名函数有一些限制,因为似乎没有一种在其中进行赋值以改变状态的方法。
。
% quick functions f = @(x) 3*x.^2 + 2*x + 7; t = (0:0.001:1); plot(t,f(t),t,f(2*t),t,f(3*t)); % closures (linfunc below is a function that returns a function, % and the outer functions arguments are held for the lifetime % of the returned function. linfunc = @(m,b) @(x) m*x+b; C2F = linfunc(9/5, 32); F2C = linfunc(5/9, -32*5/9);
赋值左侧的条件参数:
t = (0:0.005:10)'; x = sin(2*pi*t); x(x>0.5 & t<5) = 0.5; % This limits all values of x to a maximum of 0.5, where t<5 plot(t,x);
我出于很多原因喜欢使用函数句柄。首先,它们是我在MATLAB中找到的最接近指针的东西,因此我们可以为对象创建类似引用的行为。我们也可以使用它们进行一些简单(更简单)的操作。例如,替换switch语句:
switch number, case 1, outargs = fcn1(inargs); case 2, outargs = fcn2(inargs); ... end % %can be turned into % fcnArray = {@fcn1, @fcn2, ...}; outargs = fcnArray{number}(inargs);
我只是认为这样的小事很酷。
了解轴属性!我们可以设置各种方法来调整默认的绘图属性以执行所需的操作:
set(gca,'fontsize',8,'linestyleorder','-','linewidth',0.3,'xtick',1:2:9);
(例如,将fontsize设置为8pt,将所有新行的线型都设置为纯色,宽度设置为0.3pt,xtick点设置为[1 3 5 7 9])
线和图形属性也很有用,但是我发现自己最常使用轴属性。
Matlab的bsxfun,arrayfun,cellfun和structfun非常有趣,并且经常保存一个循环。
M = rand(1000, 1000); v = rand(1000, 1); c = bsxfun(@plus, M, v);
例如,此代码将列向量v添加到矩阵M的每一列。
但是,在应用程序的性能至关重要的部分中,我们应该将这些功能与普通的for循环进行基准比较,因为通常循环仍会更快。
使用最小,最大,均值,差异,总和,任意,全部,...等聚合函数时,请严格指定尺寸
例如,该行:
reldiff = diff(a) ./ a(1:end-1)
计算向量中元素的相对差异可能会很好,但是如果向量退化为一个元素,则计算将失败:
>> a=rand(1,7); >> diff(a) ./ a(1:end-1) ans = -0.5822 -0.9935 224.2015 0.2708 -0.3328 0.0458 >> a=1; >> diff(a) ./ a(1:end-1) ??? Error using ==> rdivide Matrix dimensions must agree.
如果为函数指定了正确的尺寸,则此行将返回一个空的1×0矩阵,这是正确的:
>> diff(a, [], 2) ./ a(1, 1:end-1) ans = Empty matrix: 1-by-0 >>
最小值函数的情况也一样,通常在矩阵的各列上计算最小值,直到矩阵仅由一行组成。然后,它将返回该行中的最小值,除非Dimension参数另有说明,这可能会破坏应用程序。
我几乎可以保证,因此设置这些聚合函数的尺寸将为我们节省大量的调试工作。
至少对我来说就是这种情况。 :)
令人惊讶的是,尽管人们提到了索引数组的逻辑数组方法,但没有人提及find命令。
例如如果x是NxMxO数组
x(x> 20)通过生成一个NxMxO逻辑数组并将其用于索引x来工作(如果我们有大数组并且正在寻找一个小子集,这可能会很糟糕
x(find(x> 20))的工作方式是生成满足x> 20的x的索引列表(即1xwhatever),并以此索引x。根据我的经验,应该多使用"查找"。
我称之为"技巧"的更多内容
如果我们不知道所需的大小,则可以使用end + 1来增长/追加到数组和单元格数组(只要切片的大小匹配,也可以使用更大的尺寸,因此,在这种情况下,将x初始化为[]以外的其他值)。对数字不利,但对事物(或者单元格数组)的小型动态列表不利,例如解析文件。
例如
>> x=[1,2,3] x = 1 2 3 >> x(end+1)=4 x = 1 2 3 4
另一个认为很多人不知道的是,对于在任何暗1阵列上的作品,因此继续该示例
>> for n = x;disp(n);end 1 2 3 4
这意味着,如果我们需要的只是x的成员,则无需为它们建立索引。
这也适用于单元格数组,但是有点令人讨厌,因为在遍历它们时,元素仍然包裹在单元格中:
>> for el = {1,2,3,4};disp(el);end [1] [2] [3] [4]
因此,要获取元素,我们必须将其下标
>> for el = {1,2,3,4};disp(el{1});end 1 2 3 4
我不记得有没有更好的办法解决这个问题。
-我们可以创建Matlab快捷方式到名为startup.m的初始化文件。在这里,我定义了Matlab会话的格式,输出精度和绘图参数(例如,我使用了较大的绘图轴/字体大小,以便在演示文稿时可以清晰地看到.fig。)一位开发人员关于此的博客文章http://blogs.mathworks.com/loren/2009/03/03/whats-in-your-startupm/。
-我们可以使用"加载"功能加载整个数字ascii文件。这不是特别快,但是可以快速完成原型制作工作(那不是Matlab的座右铭吗?)
-如前所述,冒号运算符和向量化是救命稻草。螺丝环。
使用xlim和ylim绘制垂直和水平线。例子:
- 在y = 10处画一条水平线:
line(xlim,[10 10])
- 在x = 5处绘制垂直线:
line([5 5],ylim)
为了能够快速测试功能,我使用nargin
像这样:
function result = multiply(a, b) if nargin == 0 %no inputs provided, run using defaults for a and b clc; disp('RUNNING IN TEST MODE') a = 1; b = 2; end result = a*b;
稍后,我添加了一个单元测试脚本来针对不同的输入条件测试该功能。
x=repmat([1:10],3,1); % say, x is an example array of data l=x>=3; % l is a logical vector (1s/0s) to highlight those elements in the array that would meet a certain condition. N=sum(sum(l));% N is the number of elements that meet that given condition.
欢呼声-脚本编写愉快!