2009-04-28 92 views
7

我在MATLAB中有一個函數,它將另一個函數作爲參數。我想以某種方式定義一個可以傳入的分段內聯函數。這在MATLAB中有點可行嗎?如何在MATLAB中創建分段內聯函數?

編輯:我想代表的功能是:

f(x) = { 1.0, 0.0 <= x <= 0.5, 
     -1.0, 0.5 < x <= 1.0 

where 0.0 <= x <= 1.0 

回答

12

您確實已定義了具有三個斷點的分段函數,即在[0,0.5,1]處。但是,您尚未定義中斷之外的函數值。 (順便說一句,我在這裏使用了「break」這個術語,因爲我們確實定義了一個簡單形式的樣條,一個分段恆定的樣條。我也可能使用了knot這個詞,這是spline世界中另一個常用詞。 )

如果你絕對知道你永遠不會評估[0,1]之外的函數,那麼沒有問題。那麼就用x = 0.5定義一個具有一個斷點的分段函數。定義像你的分段常量函數的簡單方法是使用邏輯運算符。因此,測試(x> 0.5)返回一個常數,即0或1.通過縮放和翻譯結果,可以很容易地生成一個可以滿足您需要的函數。

constfun = @(x) (x > 0.5)*2 - 1; 

內聯函數做類似的事情,但內聯函數與匿名函數相比非常慢。我強烈建議使用匿名錶單。作爲一個測試,試試這個:

infun = inline('(x > 0.5)*2 - 1','x'); 
x = 0:.001:1; 

tic,y = constfun(x);toc 
Elapsed time is 0.002192 seconds. 

tic,y = infun(x);toc 
Elapsed time is 0.136311 seconds. 

是的,內聯函數比匿名錶單花費了更多的時間來執行。

我在這裏使用的簡單分段常數形式存在的一個問題是,當你有更多的斷點時很難展開。例如,假設你想定義一個函數,它取決於點落在哪個時間間隔內的三個不同的值。雖然這也可以通過創造性地使用測試來完成,但要小心地移動和縮放它們,它會變得很討厭。例如,一個可能如何定義返回

-1 when x < 0, 
2 when 0 <= x < 1, 
1 when 1 <= x 

一種解決方案是使用一個單元Heaviside函數的分段函數。首先,定義一個基本單位Heaviside函數。

H = @(x) (x >= 0); 

我們的分段函數現在是從H(x)導出的。

P = @(x) -1 + H(x)*3 + H(x-1)*(-1); 

看到有三件P(x)。第一項是x在第一個轉折點以下發生的情況。然後我們添加一個效果在零以上的作品。最後,第三部分在x == 1的上方加上另一個偏移量。它很容易被繪製出來。

ezplot(P,[-3,3]) 

從一開始就可以輕鬆生成更復雜的樣條曲線。 Se我再次調用這個構造樣條。真的,這是我們可能領先的地方。事實上,這是導致這種情況的原因。樣條線是一個分段函數,仔細連接在一個節點或斷點列表中。特別是樣條通常具有指定的連續性順序,所以例如,三次樣條在整個中斷處將是兩次可微的(C2)。也有分段立方函數只有C1函數。我的觀點是我已經描述了一個簡單的起點來形成任何分段函數。它對於多項式樣條很好,但可能需要一點點數學來選擇這些函數的係數。

創建此函數的另一種方法是作爲顯式分段多項式。在MATLAB中,我們有很少的已知函數mkpp。試試這個...

pp = mkpp([0 .5 1],[1;-1]); 

如果你有樣條工具箱,那麼fnplt會直接爲你繪製這個。假設你沒有那個TB,那麼這樣做:

ppfun = @(x) ppval(pp,x); 
ezplot(ppfun,[0 1]) 

回頭看看mkpp調用,畢竟它是相當簡單的。第一個參數是曲線中斷點的列表(作爲ROW向量)。第二個參數是一個COLUMN向量,曲線將在這兩個間隔之間定義的間隔中採用分段常量值。

幾年前我發佈了另一個選項piecewise_eval。它可以從MATLAB Central文件交換中下載。這是一個函數,它允許用戶將分段函數完全指定爲斷點列表,以及這些斷點之間的功能塊。因此,對於具有在x = 0.5的單一斷裂的功能,我們這樣做:

fun = @(x) piecewise_eval(x,0.5,{1,-1}); 

參見第三個參數用來提供在每個段中使用的值,儘管這些部分不必是純粹的恆定函數。如果你希望函數在感興趣的時間間隔之外返回NaN,這也很容易實現。

fun = @(x) piecewise_eval(x,[0 0.5 1],{NaN,1,-1,NaN}); 

我在這個相當漫長的遊覽中的觀點是理解什麼是分段函數,以及在MATLAB中建立一個函數的幾種方法。

+0

謝謝您!我有一些內插和分段多項式的經驗。我不知道在Matlab中有這樣一個功能(我對它很新穎。),也沒有將我的分段函數想象成具有零次多項式的脊柱。感謝所有這些!我應該指出,你的匿名函數觸發了我的例子中發佈的值,但我理解了邏輯。謝謝! – Scott 2009-04-30 08:11:07

4

如果你真的想打一個內聯函數(而不是一個anonymous function),那麼下面很可能是最簡單的方法:

f = inline('2.*(x <= 0.5)-1'); 

然而,在其他的答案中指出,匿名函數更常用,並且更高效:

f = @(x) (2.*(x <= 0.5)-1); 
5

不幸的是,MATLAB沒有三元操作符這將使這種容易的事情,但對gnovice的做法略有擴大,你可以創建一個像這樣的匿名函數:

fh = @(x) (2 .* (x <= 0.5) - 1) 

在一般情況下,匿名函數比內聯函數對象更強大,並允許您創建閉包等。

1

我只需要解決這個問題,我認爲最簡單的方法就是使用匿名函數。說,你有一個分段函數:

when x<0 : x^2 + 3x 
when 0<=x<=4: e^x 
when x>4 : log(x) 

我首先定義每個分段區域中進行邏輯口罩:

PIECE1 = @(x) x<0 
PIECE2 = @(x) x>=0 & x<=4 
PIECE3 = @(x) x>4 

然後,我把它們放在一起:

f = @(x) PIECE1(x).*(x.^2+3*x) + PIECE2(x).*exp(x) + PIECE3(x).*log(x) 

x = -10:.1:10 
figure; 
plot(x,f(x)) 
相關問題