2014-11-24 86 views
1

我注意到matlab內置函數可以處理標量或矢量參數。例如:如何在MATLAB中矢量化分段周期函數?

sin(pi/2) 
ans = 
    1 

sin([0:pi/5:pi]) 
ans = 
     0 0.5878 0.9511 0.9511 0.5878 0.0000 

如果我寫我自己的函數,例如,分段周期函數:

[foo(0.1) foo(0.15) foo(0.2)] 
ans = 
     0 0.5000 1.0000 

但是,如果:

function v = foo(t) 
t = mod(t, 2) ; 

if (t < 0.1) 
    v = 0 ; 
elseif (t < 0.2) 
    v = 10 * t - 1 ; 
else 
    v = 1 ; 
end 

我可以在各個值調用此該函數的輸入是一個向量,它不像內置函數那樣自動向量化:

foo([0.1:0.05:0.2]) 
ans = 
    1 

在函數的定義中是否有可用的語法,指示如果提供了矢量,應該生成矢量?或者像sin,cos等內建函數檢查它們的輸入類型,如果輸入是矢量,則產生相同的結果?

回答

3

你需要稍微改變你的語法,以便能夠處理任何大小的數據。我通常使用邏輯過濾器來引導if語句,正如你試圖做的那樣:

function v = foo(t) 

v = zeros(size(t)); 
t = mod(t, 2) ; 

filt1 = t<0.1; 
filt2 = ~filt1 & t<0.2; 
filt3 = ~filt1 & ~filt2; 

v(filt1) = 0; 
v(filt2) = 10*t(filt2)-1; 
v(filt3) = 1; 

在這段代碼中,我們有三個邏輯過濾器。第一個挑選出所有元素,例如t<0.1。第二個挑選出所有不在第一個過濾器中的元素,例如t<0.2。最後的過濾器得到了其他一切。

然後我們用它來設置矢量v。我們將v中與第一個過濾器匹配的所有元素設置爲0。我們將v中與第二個過濾器匹配的所有內容設置爲10*t-1。我們將v中匹配第三個過濾器的所有元素設置爲1

要獲得更全面的矢量化覆蓋,請檢查其上的MATLAB help page

0

一個簡單的方法,最大限度地減少操作的次數爲:

function v = foo(t) 
t = mod(t, 2); 
v = ones(size(t)) .* (t > 0.1); 
v(t < 0.2) = 10*t(t < 0.2) - 1; 
end 

如果向量很大,它可能會更快做ind = t < 0.2,和使用,在最後一行。這樣你只能搜索一次數組。另外,乘法可能會被一個帶有邏輯索引的額外行代替。

0

我反覆打了同樣的問題,所以我一直在尋找一個更通用的解決方案以及與此想出了:

%your function definition 
c={@(t)(mod(t,2))<0.1,0,... 
@(t)(mod(t,2))<0.2,@(t)(10 * t - 1),... 
true,1}; 
%call pw which returns the function 
foo=pw(c{:}); 
%example evaluation 
foo([0.1:0.05:0.2]) 

現在的代碼,PW

function f=pw(varargin) 
for ip=1:numel(varargin) 
    switch class(varargin{ip}) 
     case {'double','logical'} 
      varargin{ip}[email protected](x)(repmat(varargin{ip},size(x))); 
     case 'function_handle' 
      %do nothing 
     otherwise 
      error('wrong input class') 
    end 
end 
c=struct('cnd',varargin(1:2:end),'fcn',varargin(2:2:end)); 
[email protected](x)pweval(x,c); 

end 

function y=pweval(x,p) 
todo=true(size(x)); 
y=x.*0; 
for segment=1:numel(p) 
    mask=todo; 
    mask(mask)=logical(p(segment).cnd(x(mask))); 
    y(mask)=p(segment).fcn(x(mask)); 
    todo(mask)=false; 
end 
assert(~any(todo)); 
end