2009-04-28 17 views
7

J'ai une fonction dans MATLAB qui prend une autre fonction en argument. Je voudrais en quelque sorte définir une fonction inline par morceaux qui peut être transmise. Est-ce que c'est en quelque sorte possible dans MATLAB?Comment créer une fonction en ligne par morceaux dans MATLAB?

Edit: La fonction que je voudrais représenter est:

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

where 0.0 <= x <= 1.0 

Répondre

12

Vous avez vraiment défini une fonction par morceaux avec trois points de rupture, c'est-à-dire à [0, 0.5, 1]. Cependant, vous n'avez pas défini la valeur de la fonction en dehors des ruptures. (Au fait, j'ai utilisé ici le terme "break", car nous définissons vraiment une forme simple de spline, une spline constante par morceaux, et j'aurais aussi utilisé le terme knot, un autre mot courant dans le monde des splines.

Si vous savez que vous n'évaluez jamais la fonction en dehors de [0,1], il n'y a pas de problème. Il suffit donc de définir une fonction par morceaux avec UN point de rupture, à x = 0.5. La manière simple de définir une fonction constante par morceaux comme la vôtre est d'utiliser un opérateur logique. Ainsi, le test (x> 0.5) renvoie une constante, soit 0 soit 1. En mettant à l'échelle et en traduisant ce résultat, il est facile de générer une fonction qui fait ce que vous souhaitez.

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

Une fonction en ligne fait une chose semblable, mais les fonctions en ligne sont très lent par rapport à une fonction anonyme. Je recommande fortement l'utilisation de la forme anonyme. En guise de test, essayez ceci:

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. 

Oui, la fonction en ligne a pris énormément plus de temps à exécuter que fait la forme anonyme.

Un problème avec la forme de constante par morceaux simple que j'ai utilisée ici est qu'il est difficile d'étendre à quand vous avez plus de points de rupture. Par exemple, supposons que vous vouliez définir une fonction qui prenait trois valeurs différentes en fonction de l'intervalle dans lequel le point est tombé? Bien que cela puisse être fait aussi avec l'utilisation créative des tests, en les déplaçant et en les redimensionnant avec soin, cela peut devenir désagréable. Par exemple, comment peut-on définir la fonction définie par qui retourne

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

Une solution consiste à utiliser une unité Heaviside fonction. Donc d'abord, définissez une unité de base Heaviside.

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

Notre fonction par morceaux est maintenant dérivée de H (x).

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

Voir qu'il y a trois pièces à P (x). Le premier terme est ce qui se passe pour x en dessous du premier point de rupture. Ensuite, nous ajoutons une pièce qui prend effet au-dessus de zéro. Enfin, le troisième morceau ajoute dans un autre offset au-dessus de x == 1. Il est assez facilement tracé.

ezplot(P,[-3,3]) 

Des splines plus sophistiquées sont facilement générées à partir de ce début. Soit que j'ai appelé cette construction une spline à nouveau. Vraiment, c'est là que nous pourrions diriger. En fait, c'est là que cela mène. Une spline est une fonction par morceaux, soigneusement attachée ensemble à une liste de nœuds ou de points de rupture. Les splines en particulier ont souvent des ordres de continuité spécifiés, par exemple, une spline cubique sera deux fois différentiable (C2) à travers les cassures. Il y a aussi des fonctions cubiques par morceaux qui ne sont que des fonctions C1. Mon point dans tout cela est que j'ai décrit un point de départ simple pour former une fonction par morceaux. Cela fonctionne assez bien pour les splines polynomiales, bien qu'il puisse y avoir un peu de mathématique nécessaire pour choisir les coefficients de ces fonctions.

Une autre façon de créer cette fonction est un polynôme explicite par morceaux. Dans MATLAB, nous avons la fonction peu connue mkpp. Essayez ceci ...

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

vous aviez la boîte à outils de splines, puis fnplt tracera ceci directement pour vous. En supposant que vous n'avez pas que la tuberculose, faites ceci:

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

Revenant sur l'appel mkpp, il est assez simple, après tout. Le premier argument est la liste des points de rupture dans la courbe (en tant que vecteur ROW). Le deuxième argument est un vecteur COLUMN, avec les valeurs constantes par morceaux que la courbe prendra dans ces deux intervalles définis entre les ruptures.

Il y a plusieurs années j'ai posté une autre option, piecewise_eval. Il peut être téléchargé à partir de l'échange de fichiers MATLAB Central. C'est une fonction qui permet à un utilisateur de spécifier une fonction par morceaux uniquement comme une liste de points de rupture, ainsi que des éléments fonctionnels entre ces coupures. Ainsi, pour une fonction avec une simple coupure à x = 0,5, nous faisons ceci:

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

Voir que le troisième argument fournit la valeur utilisée dans chaque segment, bien que ces pièces ne soient pas nécessairement des fonctions purement constantes. Si vous souhaitez que la fonction retourne peut-être un NaN en dehors de l'intervalle d'intérêt, cela aussi est facilement accompli.

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

Mon point dans toute cette excursion assez longue est de comprendre ce qu'est une fonction définie par est, et plusieurs façons de construire un dans Matlab.

+0

Remerciez toi! J'ai une certaine expérience de l'interpolation et des polynômes par morceaux. Je ne savais pas qu'il y avait une fonction pour les faire dans Matlab (je suis assez nouveau pour ça.), et je n'avais pas non plus pensé à ma fonction par morceaux comme une colonne vertébrale avec des polynômes de degré zéro. Merci pour tout cela! Je dois préciser que votre fonction anonyme change les valeurs affichées dans mon exemple, mais je comprends quand même la logique. Merci! – Scott

4

Si vous voulez vraiment faire une fonction en ligne (par opposition à un anonymous function), alors ce qui suit serait probablement la façon la plus simple:

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

Cependant, comme l'a souligné dans les autres réponses, les fonctions anonymes sont plus couramment utilisées et sont plus efficaces:

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

Malheureusement, Matlab n'a pas un opérateur ternaire qui rendrait ce genre de chose plus facile, mais d'élargir légèrement l'approche de gnovice, vous pouvez créer une fonction anonyme comme ceci:

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

En général, anonyme les fonctions sont plus puissantes que les objets de fonction inline, et vous permettent de créer des fermetures, etc.

1

J'ai juste dû résoudre ce problème, et je pense que la chose la plus facile à faire est d'utiliser des fonctions anonymes. Dites que vous avez une fonction définie par:

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

Je voudrais tout d'abord définir des masques logiques pour chaque région piecewise:

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

Puis je les mettre tous ensemble:

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