2009-04-28 20 views
7

Tengo una función en MATLAB que toma otra función como argumento. Me gustaría definir de alguna manera una función en línea por partes que se pueda pasar. ¿Es esto de alguna manera posible en MATLAB?¿Cómo puedo crear una función en línea por partes en MATLAB?

Editar: La función me gustaría representar es:

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

where 0.0 <= x <= 1.0 

Respuesta

12

Realmente ha definido una función por partes con tres puntos de interrupción, es decir, en [0, 0.5, 1]. Sin embargo, no ha definido el valor de la función fuera de los descansos. (Por cierto, he usado el término "break" aquí, porque realmente estamos definiendo una forma simple de spline, una spline constante a trozos. También podría haber usado el término nudo, otra palabra común en el mundo de splines.)

Si está seguro de que nunca evaluará la función fuera de [0,1], entonces no hay ningún problema. Entonces, simplemente defina una función por partes con UN punto de interrupción, en x = 0.5. La forma simple de definir una función constante por partes como la tuya es usar un operador lógico. Por lo tanto, la prueba (x> 0.5) devuelve una constante, ya sea 0 o 1. Al escalar y traducir ese resultado, es fácil generar una función que haga lo que desee.

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

una función en línea hace una cosa similar, pero las funciones en línea son muy lentos en comparación con una función anónima. Recomiendo encarecidamente el uso del formulario anónimo. Como prueba, intente esto:

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. 

Sí, la función en línea tomaron violentamente más tiempo para ejecutar que hizo la forma anónima.

Un problema con la forma constante por partes que he usado aquí es que es difícil ampliarlo cuando tiene más puntos de quiebre. Por ejemplo, supongamos que desea definir una función que tomara tres valores diferentes según el intervalo en que cayera el punto. Si bien esto se puede hacer también con el uso creativo de pruebas, cambiándolas y escalando cuidadosamente, puede volverse desagradable. Por ejemplo, ¿cómo puede una definir la función a trozos que devuelve

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

Una solución es utilizar una unidad de Heaviside función. Entonces, primero, defina una función Heaviside de unidad básica.

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

Nuestra función por partes ahora se deriva de H (x).

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

Ver que haya tres piezas en P (x). El primer término es lo que sucede para x debajo del primer punto de quiebre. Luego agregamos una pieza que tiene efecto por encima de cero. Finalmente, la tercera pieza agrega otra compensación en la parte superior x == 1. Es bastante fácil de trazar.

ezplot(P,[-3,3]) 

Las estrías más sofisticadas se generan fácilmente desde este comienzo. Se que he llamado a esta construcción una spline nuevamente. Realmente, aquí es donde podríamos estar liderando. De hecho, aquí es donde esto lleva. Una spline es una función por partes, cuidadosamente unida en una lista de nudos o puntos de quiebre. Las Splines, en particular, a menudo tienen órdenes de continuidad especificadas, por lo que, por ejemplo, una spline cúbica será dos veces diferenciable (C2) a través de las rupturas. También hay funciones cúbicas a trozos que son solo funciones C1. Mi punto en todo esto es que he descrito un punto de inicio simple para formar cualquier función por partes. Funciona bastante bien para splines polinomiales, aunque puede ser necesario un poquito de matemática para elegir los coeficientes de estas funciones.

Otra forma de crear esta función es como un polinomio por partes explícito. En MATLAB, tenemos la pequeña función conocida mkpp. Trate de hacer esto ...

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

tenías la caja de herramientas estrías, a continuación, se fnplt trazar esto directamente para usted. Suponiendo que usted no tiene que la tuberculosis, hacer esto:

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

Mirando hacia atrás en la llamada mkpp, es bastante simple, después de todo. El primer argumento es la lista de puntos de quiebre en la curva (como un vector ROW). El segundo argumento es un vector COLUMNA, con los valores constantes a trozos que tomará la curva en estos dos intervalos definidos entre los descansos.

Hace varios años publiqué otra opción, piecewise_eval. Se puede descargar desde el intercambio de archivos central de MATLAB. Esta es una función que le permitirá al usuario especificar una función por partes puramente como una lista de puntos de quiebre, junto con piezas funcionales entre esas rupturas. Por lo tanto, para una función con una sola interrupción en x = 0,5, que podría hacer esto:

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

ver que el tercer argumento proporciona el valor utilizado en cada segmento, aunque esas piezas no tienen que ser funciones puramente constantes. Si desea que la función devuelva quizás un NaN fuera del intervalo de interés, esto también se logra fácilmente.

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

Mi punto en todo esto bastante larga excursión es entender lo que es una función a trozos, y varias maneras de construir una en MATLAB.

+0

Gracias ¡tú! Tengo cierta experiencia con interpolación y polinomios por partes. No sabía que había una función para hacerlos en Matlab (soy bastante nuevo en eso).), ni había pensado en mi función por partes como una columna vertebral con polinomios de grado cero. ¡Gracias por todo esto! Debo señalar que su función anónima cambia los valores publicados en mi ejemplo, pero comprendo la lógica, no obstante. ¡Gracias! – Scott

4

Si usted realmente desea hacer una función en línea (en contraposición a un anonymous function), entonces lo siguiente sería probablemente la forma más sencilla:

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

Sin embargo, como se señala en las otras respuestas, funciones anónimas se utilizan con mayor frecuencia y son más eficientes:

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

Desafortunadamente, MATLAB no tiene un operador ternario que haría que este tipo de cosas más fácil, pero para expandir ligeramente sobre el enfoque de gnovice, puede crear una función anónima, así:

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

En general, anónimo las funciones son más potentes que los objetos de función en línea, y le permiten crear cierres, etc.

1

Solo tuve que resolver ese problema, y ​​creo que lo más fácil es usar funciones anónimas. Decir que usted tiene una función a trozos:

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

Me defino primero máscaras lógicas para cada región a trozos:

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

Entonces me gustaría poner a todos juntos:

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