2009-04-28 14 views
7

Ich habe eine Funktion in MATLAB, die eine andere Funktion als Argument übernimmt. Ich möchte irgendwie eine stückweise Inline-Funktion definieren, die übergeben werden kann. Ist das in MATLAB irgendwie möglich?Wie kann ich eine stückweise Inline-Funktion in MATLAB erstellen?

Edit: Die Funktion möchte ich darstellen möchte, ist:

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

where 0.0 <= x <= 1.0 

Antwort

12

Sie haben eine stückweise Funktion mit drei Knickpunkten definiert, dh mit [0, 0,5, 1]. Sie haben den Wert der Funktion jedoch nicht außerhalb der Pausen definiert. (Übrigens habe ich hier den Begriff "Pause" verwendet, weil wir wirklich eine einfache Form von Spline definieren, einen stückweise konstanten Spline. Ich hätte vielleicht auch den Begriff "knot" verwenden können, ein anderes gebräuchliches Wort in der Welt der Splines.)

Wenn Sie absolut wissen, dass Sie die Funktion außerhalb von [0,1] nie bewerten werden, dann gibt es kein Problem. Definieren Sie also einfach eine stückweise Funktion mit EINEM Unterbrechungspunkt bei x = 0,5. Die einfache Möglichkeit, eine stückweise konstante Funktion wie Ihre zu definieren, besteht darin, einen logischen Operator zu verwenden. Daher gibt der Test (x> 0,5) eine Konstante zurück, entweder 0 oder 1. Durch Skalierung und Umsetzung dieses Ergebnisses ist es einfach, eine Funktion zu erzeugen, die das tut, was Sie wollen.

Eine Inline-Funktion macht eine ähnliche Sache, aber Inline-Funktionen sind sehr langsam im Vergleich zu einer anonymen Funktion. Ich würde dringend die Verwendung des anonymen Formulars empfehlen. Als Test, versuchen Sie dies:

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. 

Ja, nahm die Inline-Funktion mehr Zeit wild auszuführen als die anonyme Form haben.

Ein Problem mit der einfachen stückweise konstanten Form, die ich hier verwendet habe, ist es schwierig zu erweitern, wenn Sie mehr Breakpoints haben. Angenommen, Sie möchten eine Funktion definieren, die drei verschiedene Werte annimmt, abhängig davon, in welchem ​​Intervall der Punkt liegt? Während dies auch mit kreativer Verwendung von Tests getan werden kann, die sorgfältig verschoben und skaliert werden, kann es unangenehm werden. Zum Beispiel, wie könnte man die Funktion definieren, die abschnittsweise

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

Eine Lösung zurückgibt, ist eine Einheit Heaviside Funktion zu verwenden. Definieren Sie zunächst eine Basiseinheit Heaviside-Funktion.

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

Unsere stückweise Funktion wird nun von H (x) abgeleitet.

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

Siehe, dass es drei Stücke zu P (x) gibt. Der erste Term ist, was für x unter dem ersten Breakpoint passiert. Dann fügen wir ein Stück hinzu, das über Null wirkt. Schließlich fügt das dritte Stück einen weiteren Versatz in oben x == 1 hinzu. Es ist leicht genug geplottet.

ezplot(P,[-3,3]) 

Aus diesem Anfang werden einfachere Splines generiert. Se, dass ich dieses Konstrukt wieder einen Spline genannt habe. Wirklich, hier könnten wir führen. In der Tat, das ist, wo dies führt. Ein Spline ist eine stückweise Funktion, die sorgfältig an einer Liste von Knoten oder Knickpunkten zusammengehalten wird. Insbesondere bei Splines gibt es oft festgelegte Kontinuitätsreihenfolgen, so wird beispielsweise ein kubischer Spline in den Pausen zweimal differenzierbar (C2). Es gibt auch stückweise kubische Funktionen, die nur C1-Funktionen sind. Mein Punkt in all dem ist, dass ich einen einfachen Anfangspunkt beschrieben habe, um jede stückweise Funktion zu bilden. Es funktioniert ziemlich gut für Polynom-Splines, obwohl es ein kleines bisschen Mathematik benötigt, um die Koeffizienten dieser Funktionen zu wählen.

Eine weitere Möglichkeit, diese Funktion zu erstellen, ist ein explizites stückweises Polynom. In MATLAB haben wir die wenig bekannte Funktion mkpp. Probieren Sie dies aus ...

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

Haben Ihnen die Splines Toolbox, dann wird fnplt dieses Grundstück direkt für Sie. Unter der Annahme, dass Sie dies nicht, dass die TB haben, tun:

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

zurück am mkpp Anruf Sehen, es doch recht einfach ist. Das erste Argument ist die Liste der Breakpoints in der Kurve (als ROW-Vektor). Das zweite Argument ist ein COLUMN-Vektor mit den stückweise konstanten Werten, die die Kurve in diesen beiden definierten Abständen zwischen den Pausen annehmen wird.

Vor einigen Jahren habe ich eine andere Option, piecewise_eval. Es kann vom MATLAB Central-Dateiaustausch heruntergeladen werden. Dies ist eine Funktion, die es einem Benutzer ermöglicht, eine stückweise Funktion rein als eine Liste von Unterbrechungspunkten zusammen mit funktionalen Teilen zwischen diesen Unterbrechungen zu spezifizieren. Somit kann für eine Funktion mit einer einzigen Pause bei x = 0,5, würden wir dies tun:

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

Sehen Sie, dass das dritte Argument den Wert in jedem Segment verwendet wird, liefert, obwohl diese Stücke nicht rein konstante Funktionen zu sein brauchen. Wenn Sie möchten, dass die Funktion vielleicht ein NaN außerhalb des interessierenden Intervalls zurückgibt, ist dies ebenfalls problemlos möglich.

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

Mein Punkt in all diesen recht langen Ausflug zu verstehen, was eine weise definierte Funktion ist, und mehrere Möglichkeiten, einen in MATLAB zu bauen.

+0

Thank Sie! Ich habe einige Erfahrungen mit Interpolation und stückweisen Polynomen. Ich wusste nicht, dass es eine Funktion gab, sie in Matlab zu machen (ich bin ziemlich neu dazu).), noch hatte ich an meine stückweise Funktion als Wirbelsäule mit Polynomen vom Grad Null gedacht. Danke für alles! Ich sollte darauf hinweisen, dass Ihre anonyme Funktion die in meinem Beispiel angegebenen Werte umkehrt, aber ich verstehe die Logik dennoch. Vielen Dank! – Scott

4

Wenn Sie wirklich eine Inline-Funktion machen wollen (im Gegensatz zu einem anonymous function Gegensatz), dann wahrscheinlich die folgenden wäre der einfachste Weg sein:

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

jedoch, wie in den anderen Antworten erwähnt, sind anonyme Funktionen häufiger verwendet und sind effizienter:

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

Leider hat MATLAB keinen ternären Operator hat, die diese Art der Sache machen würden einfacher, aber leicht auf gnovice Ansatz zu erweitern, können Sie eine anonyme Funktion wie so erstellen:

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

Im Allgemeinen anonym Funktionen sind leistungsfähiger als Inlinefunktionsobjekte und ermöglichen das Erstellen von Schließungen usw.

1

Ich musste nur dieses Problem lösen, und ich denke, das einfachste ist, anonyme Funktionen zu verwenden. Sagen Sie, dass Sie eine weise definierte Funktion haben:

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

Ich würde zuerst definieren logische Masken für jede stückweise Region:

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

Dann würde ich sie alle zusammen:

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))