Sie sind auf Seite 1von 18

Introducción

Los métodos más sencillos como el de Euler o las mejoras de este procedimiento, tienen
dos defectos esenciales: la exactitud es pequeña y los errores crecen sistemáticamente.

El procedimiento de Runge-Kutta se puede programar fácilmente en los ordenadores, y


además se emplea mucho en la práctica, debido a la su exactitud relativamente elevada de
la solución aproximada de la ecuación diferencial. La justificación del procedimiento de
Runge-Kutta no es sencilla, el lector interesado puede consultar algún libro de métodos
numéricos de análisis que como el que se cita en la bibliografía.

Ecuaciones diferenciales de primer orden


Sea una ecuación diferencial de primer orden, con la condición inicial

Se elige una anchura de paso h, y se calculan cuatro números k1, k2, k3, k4 de acuerdo con el
procedimiento esquematizado en la tabla adjunta. Según el procedimiento ordinario de
Runge-Kutta, a partir del valor de x en el instante t se determina el valor de x en el instante
t+h mediante la fórmula que figura en la última fila de dicha tabla.
La jerarquía de clases

Definimos una clase base abstracta denomina RungeKutta, cuya función miembro resolver
nos calcule la solución aproximada de la ecuación diferencial x en el instante final tf,
cuando le pasamos el estado inicial, es decir, el valor de x0 en el instante inicial t0. La
función devuelve el estado del sistema que puede ser la posición del móvil, la intensidad de
la corriente eléctrica en un circuito, etc., es decir, el valor de x, en el instante t.

public abstract class RungeKutta {


public double resolver(double tf, double t0, double x, double h){
double k1, k2, k3, k4;
for(double t=t0; t<tf; t+=h){
k1=h*f(x, t);
k2=h*f(x+k1/2, t+h/2);
k3=h*f(x+k2/2, t+h/2);
k4=h*f(x+k3, t+h);
x+=(k1+2*k2+2*k3+k4)/6;
}
return x;
}
abstract public double f(double x, double t);
}

En la clase Funcion derivada de RungeKutta describimos el modelo físico particular,


redefiniendo la función f(x, t). Consideremos la ecuación diferencial que describe la
desintegración de una sustancia radioactiva en otra estable.

Donde a es la constante de desintegración radioactiva. A la izquierda tenemos la ecuación


diferencial y a la drecha su solución analítica.

La definición de la clase Funcion define la función f(x), tomando el valor de la constante de


desintegración a igual a 0.1

public class Funcion extends RungeKutta{


public double f(double x, double t){
return (-0.1*x);
}
}

La llamada a la función resolver se efectuará desde un objeto de la clase derivada Funcion.


Se nos pedirá los siguientes datos: el estado inicial, es decir, el número de núcleos x0 en el
instante inicial t0, el instante final t en el que queremos calcular el nuevo estado del sistema
x, y el paso h para resolver numéricamente la ecuación diferencial. La función miembro
resolver devuelve el número de núcleos quedan sin desintegrar en dicho instante t.
double h=0.5; //paso

double x0=5000; //número inicial de núcleos en el instante


t=0
double t=20.0; //resolver la e. d. hasta este instante

double x=new Funcion().resolver(t, 0, x0, h);


System.out.println("valor aprox. de x "+(int)x);

Comparamos el valor exacto y el valor aproximado, tomando como paso h el valor 0.5, el
número inicial de núcleos, 5000, y el instante t, 20. Se obtiene para el resultado aproximado
676 y para el resultado exacto 676, lo que nos confirma la exactitud del procedimiento de
Runge-Kutta.

// valor exacto
x=(int)(x0*Math.exp(-0.1*t));
System.out.println("valor exacto de x "+(int)x);
Sistema de ecuaciones diferenciales de primer orden
El procedimiento de Runge-Kutta es igualmente efectivo en la resolución de ecuaciones
diferenciales de primer orden. Sea el sistema

El procedimiento de aplicación del método de Runge-Kutta a cada una de las ecuaciones


diferenciales, con las condiciones iniciales

se esquematiza en la tabla adjunta. Como vemos además de los cuatro números k1, k2, k3, k4
para la primera ecuación diferencial precisamos otros cuatro números l1, l2, l3, l4 para la
segunda ecuación diferencial. A partir del valor de x en el instante t, se determina el valor
de x en el instante t+h, y a partir del valor de y en el instante t se determina el valor de y en
el instante t+h mediante las fórmulas de la última fila de la tabla.

La jerarquía de clases

De modo similar, definimos la clase base abstracta denominada RungeKutta cuya función
miembro resolver nos calcule la solución aproximada del sistema de ecuaciones
diferenciales de primer orden (x, y) en el instante final tf, cuando le pasamos el estado
inicial, es decir, el valor x0 e y0 en el instante inicial t0
public abstract class RungeKutta {
public void resolver(double tf, Estado e, double h){
//variables auxiliares
double k1, k2, k3, k4;
double l1, l2, l3, l4;
//estado inicial
double x=e.x;
double y=e.y;
double t0=e.t;

for(double t=t0; t<tf; t+=h){


k1=h*f(x, y, t);
l1=h*g(x, y, t);
k2=h*f(x+k1/2, y+l1/2, t+h/2);
l2=h*g(x+k1/2, y+l1/2, t+h/2);
k3=h*f(x+k2/2, y+l2/2, t+h/2);
l3=h*g(x+k2/2, y+l2/2, t+h/2);
k4=h*f(x+k3, y+l3, t+h);
l4=h*g(x+k3, y+l3, t+h);
x+=(k1+2*k2+2*k3+k4)/6;
y+=(l1+2*l2+2*l3+l4)/6;
}
//estado final
e.t=tf;
e.x=x;
e.y=y;
}
abstract public double f(double x, double y, double t);
abstract public double g(double x, double y, double t);
}

Una función solamente, puede devolver un valor, sin embargo, el estado del sistema en
cualquier instante t viene dado por dos números x e y. Para ello, definimos la clase
denominada Estado con tres miembros públicos x e y y el tiempo t.

La función resolver recibe en su segundo parámetro el estado inicial del sistema. Ya que los
objetos que se pasan a una función se pueden modificar en el curso de su llamada. La
función resolver modifica dicho objeto, devolviendo el estado final cuando se le pasa el
estado inicial.

public class Estado {


public double t;
public double x;
public double y;
public Estado(double t, double x, double y) {
this.t=t;
this.x=x;
this.y=y;
}
}

Para obtener el estado e (objeto de la clase Estado) accedemos a sus miembros dato
públicos t, x, y
System.out.println("t " +e.t);
System.out.println("x " +e.x);
System.out.println("y " +e.y);

Para crear el estado e a partir de los valores de t, x, e y, llamamos al constructor de la clase


Estado.

double t=0;
double x=1000;
double y=0;
Estado e=new Estado(t, x, y);

Ejemplo

Continuando con el ejemplo de la desintegración radioactiva consideremos ahora, una serie


radioactiva de tres elementos en la que, una sustancia radiactiva A se desintegra y se
transforma en otra sustancia radiactiva B, que a su vez se desintegra y se transforma en una
sustancia C estable. Las ecuaciones diferenciales que gobiernan el proceso y sus soluciones
analíticas son, respectivamente,

La solución analítica que aparece a la derecha, se ha obtenido con las condiciones iniciales
t=0, x=x0 e y=0. La segunda solución se obtiene siempre que a sea distinto de b. En el caso
de que a sea igual a b, la solución analítica para y es

La interpretación del sistema de ecuaciones diferenciales no es complicada. En la unidad de


tiempo, desaparecen ax núcleos de la sustancia A al desintegrarse (primera ecuación). En la
unidad de tiempo, se producen ax núcleos de la sustancia B, y a su vez desaparecen bx
núcleos de la sustancia B que al desintegrarse se transforman en núcleos de la sustancia C
estable (segunda ecuación).

Para codificar este ejemplo, primero se han de definir las funciones f, g en la clase derivada
Funcion de la clase abstracta RungeKutta.
public class Funcion extends RungeKutta{
public double f(double x, double y, double t){
return (-0.1*x);
}
public double g(double x, double y, double t){
return (0.1*x-0.2*y);
}
}

Definimos el estado inicial en el instante t0=0, el número de núcleos de la sustancia


radiactiva A, suponemos que no hay inicialmente núcleos de sustancia B. Establecemos el
instante t en el que deseamos conocer el número de núcleos que hay de la sustancia A, y el
número de núcleos de la sustancia B, llamando a la función resolver desde un objeto de la
clase Funcion.

double h=0.5; //paso

double x0=5000;
Estado es=new Estado(0, x0, 0);

double t=20.0; //resolver la e. d. hasta este instante


new Funcion().resolver(t, es, h);
System.out.println("valor aprox. de x "+(int)es.x);
System.out.println("valor aprox. de y "+(int)es.y);

Como en el apartado anterior fijamos el número de núcleos de la sustancia A en 5000, y el


de la B ningún núcleo. El valor del paso h lo tomamos como 0.5. Los resultados
aproximados para el instante t=20 están en concordancia con los obtenidos a partir del
resultado exacto, como queda reflejado en la tabla adjunta

t=20 Aproximado Exacto


A 676 676
B 585 585
Ecuación diferencial de segundo orden
Vamos a aplicar el procedimiento de Runge-Kutta a una ecuación diferencial de segundo
orden.

con las condiciones iniciales

Una ecuación diferencial de segundo orden es equivalente a un sistema de dos ecuaciones


diferenciales de primer orden, por lo que aplicaremos el mismo esquema.

Comparando esta tabla con la de un sistema de dos ecuaciones diferenciales de primer


orden, vemos que la segunda columna es la misma, excepto por cambio de nombre de la
función, f en vez de g, y de la variable, v en vez de y. En la primera columna, las variables
k1, k2, k3, k4 pueden calcularse directamente sin efectuar llamadas a una función.
La jerarquía de clases

La definición de la clase abstracta RungeKutta con la función miembro resolver es, la


siguiente.

public abstract class RungeKutta {


public void resolver(double tf, Estado e, double h){
//variables auxiliares
double k1, k2, k3, k4;
double l1, l2, l3, l4;
//estado inicial
double x=e.x;
double v=e.v;
double t0=e.t;

for(double t=t0; t<tf; t+=h){


k1=h*v;
l1=h*f(x, v, t);
k2=h*(v+l1/2);
l2=h*f(x+k1/2, v+l1/2, t+h/2);
k3=h*(v+l2/2);
l3=h*f(x+k2/2, v+l2/2, t+h/2);
k4=h*(v+l3);
l4=h*f(x+k3, v+l3, t+h);
x+=(k1+2*k2+2*k3+k4)/6;
v+=(l1+2*l2+2*l3+l4)/6;
}
e.t=tf;
e.x=x;
e.v=v;
}
abstract public double f(double x, double y, double t);
}

La definición de la clase cuyos miembros dato nos sirven para guardar el estado del sistema
es similar a la clase definida en el apartado sistema de dos ecuaciones diferenciales de
primer orden con el mismo propósito, cambiando el miembro y por la derivada de x, que
hemos llamado v.

public class Estado {


public double t;
public double x;
public double v;
public Estado(double t, double x, double v) {
this.t=t;
this.x=x;
this.v=v;
}
}
Ejemplos

• Oscilaciones libres

La ecuación diferencial que describe un oscilador armónico y su solución para unas


condiciones iniciales fijadas es

donde ω0 es la frecuencia angular, y el periodo del movimiento es P=2π/ω0.

La clase denominada Oscilador que describirá un oscilador armónico tendrá como


miembro dato, la frecuencia angular, y derivará de la clase base RungeKutta, ya que el
comportamiento de un oscilador armónico viene descrito por una ecuación diferencial de
segundo orden. La clase Oscilador definirá la función f declarada abstracta en la clase base.

public class Oscilador extends RungeKutta{


protected double w0; //frecuencia angular
public Oscilador(double w0){
this.w0=w0;
}
public double f(double x, double v, double t){
return (-w0*w0*x);
}
}

Examinemos el comportamiento de un oscilador que en el instante inicial t=0, se encuentra


en la posición de máximo desplazamiento x=A, y se suelta con velocidad inicial cero v=0.
La amplitud A y la fase inicial ϕ se calculan, a partir de las condiciones iniciales
especificadas, que pueden ser distintas de las señaladas.

Podemos experimentar con un oscilador de frecuencia angularω0 de 2 rad/s, lo que


corresponde a un periodo P=2π/ω de π s, calculemos la posición y la velocidad del
oscilador en el instante t= 2s, tomando como paso h el valor de 0.01.

double h=0.01; //paso


double w0=2.0; //frecuencia propia oscilaciones libres
double t=2.0; //resolver la e. d. hasta este instante
//Situación inicial
double x0=1.5; //posición inicial
double v0=0.0; //velocidad inicial
Estado es=new Estado(0.0, x0, v0);

//oscilaciones libres
System.out.println("Oscilaciones libres");
Oscilador os=new Oscilador(w0);
os.resolver(t, es, h);
System.out.println("posición aprox. "+es.x);
System.out.println("velocidad aprox. "+es.v);
// valor exacto
double fi=Math.atan(w0*x0/v0);
double A=x0/Math.sin(fi);
double x=A*Math.sin(w0*t+fi);
double v=A*w0*Math.cos(w0*t+fi);
System.out.println("posición exacta "+x);
System.out.println("velocidad exacta "+v);

Oscilaciones amortiguadas

Si además consideramos que existe un rozamiento que se describe en términos de una


fuerza proporcional a la velocidad, la ecuación diferencial del oscilador amortiguado se
escribe.

En vez de crear una nueva clase Amortiguado que sustituya a la clase Oscilador, podemos
pensar que un oscilador amortiguado, es una clase especial de oscilador, y por tanto la clase
que lo describe, derivará de Oscilador, le añadirá el miembro dato g (por γ), que da cuenta
de la intensidad de las fuerzas de rozamiento, y además, redefine la función f.

public class Amortiguado extends Oscilador{


protected double g;
public Amortiguado(double g, double w0){
super(w0);
this.g=g;
}
public double f(double x, double v, double t){
return (-2*g*v-w0*w0*x);
}
}

En la figura, se muestra la jerarquía de clases.


Sea por ejemplo, un oscilador armónico amortiguado que tiene los datos ω0=2, γ=0.5, y las
condiciones iniciales en el instante son t=0, x=1.5, y v=0. Tomando un paso h de anchura
0.1, se puede comparar la posición del móvil en el instante t, con la deducida a partir de la
solución analítica de la ecuación diferencial

La amplitud A y la fase inicial ϕ se calculan a partir de las condiciones iniciales


especificadas.

double h=0.01; //paso


double w0=2.0; //frecuencia propia oscilaciones libres
double g=0.5; //cte de amortiguamiento
double t=2.0; //resolver la e. d. hasta este instante
//Situación inicial
double x0=1.5; //posición inicial
double v0=0.0; //velocidad inicial
Estado es=new Estado(0.0, x0, v0);
//oscilaciones amortiguadas
System.out.println("Oscilaciones amortiguadas");
es=new Estado(0.0, x0, v0);
new Amortiguado(g, w0).resolver(t, es, h);
System.out.println("posición aprox. "+es.x);
System.out.println("velocidad aprox. "+es.v);
// valor exacto
double w=Math.sqrt(w0*w0-g*g);
fi=Math.atan(w*x0/(v0+g*x0));
A=x0/Math.sin(fi);
x=A*Math.exp(-g*t)*Math.sin(w*t+fi);
System.out.println("posición exacta "+x);
v=A*Math.exp(-g*t)*(-g*Math.sin(w*t+fi)+w*Math.cos(w*t+fi));
System.out.println("velocidad exacta "+v);
Sistema de dos ecuaciones diferenciales de segundo orden
Sea el sistema de dos ecuaciones diferenciales de segundo orden

con las condiciones iniciales

Este sistema, se puede transformar en un sistema equivalente formado por cuatro


ecuaciones diferenciales de primer orden. Aplicando dos veces el esquema descrito para
una ecuación diferencial de segundo orden, obtenemos el esquema descrito en las
siguientes tablas
La codificación de la función que resuelve el sistema de dos ecuaciones diferenciales de
segundo orden, repite dos veces, el código de la función resolver correspondiente a una
ecuación diferencial de segundo orden, ya que hay que calcular cuatro pares de parámetros
más, los correspondientes a la segunda ecuación diferencial de segundo orden.

La jerarquía de clases

De modo análogo a los apartados anteriores, estableceremos una jerarquía de clases, la


clase base abstracta define el procedimiento numérico y la clase derivada define el sistema
físico particular.

public abstract class RungeKutta {


public void resolver(double tf, Estado e, double h){
//variables auxiliares
double k1, k2, k3, k4;
double l1, l2, l3, l4;
double q1, q2, q3, q4;
double m1, m2, m3, m4;
//estado inicial
double x=e.x;
double y=e.y;
double vx=e.vx;
double vy=e.vy;
double t0=e.t;

for(double t=t0; t<tf; t+=h){


k1=h*vx;
l1=h*f(x, y, vx, vy, t);
q1=h*vy;
m1=h*g(x, y, vx, vy, t);

k2=h*(vx+l1/2);
l2=h*f(x+k1/2, y+q1/2, vx+l1/2, vy+m1/2, t+h/2);
q2=h*(vy+m1/2);
m2=h*g(x+k1/2, y+q1/2, vx+l1/2, vy+m1/2, t+h/2);

k3=h*(vx+l2/2);
l3=h*f(x+k2/2, y+q2/2, vx+l2/2, vy+m2/2, t+h/2);
q3=h*(vy+m2/2);
m3=h*g(x+k2/2, y+q2/2, vx+l2/2, vy+m2/2, t+h/2);

k4=h*(vx+l3);
l4=h*f(x+k3, y+q3, vx+l3, vy+m3, t+h);
q4=h*(vy+m3);
m4=h*g(x+k3, y+q3, vx+l3, vy+m3, t+h);
x+=(k1+2*k2+2*k3+k4)/6;
vx+=(l1+2*l2+2*l3+l4)/6;
y+=(q1+2*q2+2*q3+q4)/6;
vy+=(m1+2*m2+2*m3+m4)/6;
}
//estado final
e.x=x;
e.y=y;
e.vx=vx;
e.vy=vy;
e.t=tf;
}
abstract public double f(double x, double y, double vx, double vy,
double t);
abstract public double g(double x, double y, double vx, double vy,
double t);
}

El estado del sistema vendrá dado por cuatro números x, y, vx, vy y t, miembros dato de la
clase que hemos denominado Estado.

public class Estado {


public double t;
public double x;
public double y;
public double vx;
public double vy;
public Estado(double t, double x, double y, double vx, double vy) {
this.t=t;
this.x=x;
this.y=y;
this.vx=vx;
this.vy=vy;
}
}
Ejemplo

Uno de los ejemplos más interesantes de resolución de un sistema de ecuaciones


diferenciales de segundo orden es la descripción del movimiento de los planetas, el cual
tiene una solución analítica sencilla en coordenadas polares. La trayectoria seguida por un
planeta es una cónica, una elipse en particular, en uno de cuyos focos está el centro fijo de
fuerzas, el Sol. En la figura, se muestra la fuerza que ejerce el Sol sobre un planeta,
inversamente proporcional al cuadrado de las distancias que separan sus centros, y también
se muestran sus componentes rectangulares

Teniendo en cuenta que la fuerza que ejerce el sol sobre un planeta viene descrita por la ley
de la Gravitación Universal

donde M es la masa del Sol, m la masa del planeta y r la distancia entre el centro del Sol y
del planeta. Las componentes de la aceleración del planeta serán

Uno de los problemas del tratamiento numérico con ordenador, es la de reducir el problema
a números simples e inteligibles por el usuario de un vistazo. Las masa de los planetas y del
Sol son números muy grandes: la masa de la Tierra es 5.98 1024 kg., y 1.98 1030 kg. la del
Sol. La distancia media entre la Tierra y el Sol es también muy grande 1.49 1011 m. y la
constante G es muy pequeña 6.67 10-11 en el Sistema Internacional de Unidades. Podemos
simplificar el problema numérico, refiriéndonos a un hipotético Sol cuya masa sea tal que
el producto GM=1 o bien, que se ha cambiado la escala de los tiempos de modo que se
cumpla esta condición. Teniendo en cuenta que la aceleración es la derivada segunda de la
posición, el sistema de dos ecuaciones diferenciales de segundo orden quedará

En la clase derivada Planeta redefinimos las funciones f y g.

public class Planeta extends RungeKutta{


public double f(double x, double y, double vx, double vy, double t){
double r=Math.sqrt(x*x+y*y);
return (-x/(r*r*r));
}
public double g(double x, double y, double vx, double vy, double t){
double r=Math.sqrt(x*x+y*y);
return (-y/(r*r*r));
}
}

Los pasos para usar la clase Planeta son los siguientes

• Establecer la magnitud del paso h


• Introducir el estado inicial de la partícula (su posición y su
velocidad inicial)
• Establecer el tiempo final t, en el que deseamos calcular el
nuevo estado del planeta.
• Crear un objeto de la clase Planeta y llamar a la función
miembro resolver.
• Mostrar la posición y velocidad final del planeta.

double h=0.1; //paso

//Situación inicial
double x0=1.0;
double vy0=1.2;
Estado es=new Estado(0.0, x0, 0.0, 0.0, vy0);

double t=10.0; //resolver la e. d. hasta este instante


new Planeta().resolver(t, es, h);
System.out.println("posición aprox. x "+es.x);
System.out.println("posición aprox. y "+es.y);
System.out.println("velocidad aprox. vx "+es.vx);
System.out.println("velocidad aprox. vy "+es.vy);

Das könnte Ihnen auch gefallen