next up previous contents
Next: 4.5 スレッドの利用 Up: 4 アプレットでシミュレーション・プログラムを作る Previous: 4.3 1 変数関数のグラフを描く

4.4 常微分方程式の力学系

定数係数1階線形常微分方程式

$\displaystyle \frac{\D}{\D t}
\begin{pmatrix}
x  y
\end{pmatrix}=
\begin{pmatrix}
a & b \\
c & d
\end{pmatrix}\begin{pmatrix}
x  y
\end{pmatrix}$

を解いて相図を描くためのプログラム ODE1.java (実行は http://nalab.mind.meiji.ac.jp/~mk/labo/java/sample/ODE1.html) は次のようにすればよい。


   1 // <APPLET code="ODE1.class" width=500 height=500> </APPLET>
   2 
   3 import java.applet.*;
   4 import java.awt.*;
   5 import java.awt.event.*;
   6 
   7 class GraphCanvas extends Canvas {
   8 
   9   static final boolean DEBUG = false; // true;
  10   private static final String message = "graph of a function with 1 variable";
  11   // 問題に取って基本的なパラメーター
  12   // 係数行列
  13   private double a, b, c, d;
  14   // 描画範囲
  15   private double x_max =   1.0;
  16   private double x_min = - 1.0;
  17   private double x_margin = (x_max - x_min) / 10;
  18   private double y_max =   1.0;
  19   private double y_min = - 1.0;
  20   private double y_margin = (y_max - y_min) / 10;
  21 
  22   // 座標系の変換のためのパラメーター
  23   private int CanvasX = 400, CanvasY = 400;
  24   private double ratiox, ratioy, X0, Y0;
  25 
  26   // コンストラクター
  27   public GraphCanvas() {
  28     super();
  29   }
  30   public GraphCanvas(int cx, int cy) {
  31     super();
  32     CanvasX = cx; CanvasY = cy;
  33   }
  34 
  35   public void compute(double A, double B, double C, double D) {
  36     a = A; b = B; c = C; d = D;
  37     repaint();
  38   }
  39 
  40   private boolean IsIn(double x, double y) {
  41     return (x_min <= x && x <= x_max && y_min <= y && y <= y_max);
  42   }
  43   // 座標変換の準備
  44   private void space(double x0, double y0, double x1, double y1) {
  45     X0 = x0; Y0 = y0;
  46     ratiox = CanvasX / (x1 - x0);
  47     ratioy = CanvasY / (y1 - y0);
  48   }
  49   // ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系)
  50   private int wx(double x) {
  51     return (int)(ratiox * (x - X0));
  52   }
  53   // ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系)
  54   private int wy(double y) {
  55     return CanvasY - (int)(ratioy * (y - Y0));
  56   }
  57   // 力学系の右辺 f=(fx, fy)
  58   private double fx(double x, double y) {
  59     return a * x + b * y;
  60   }
  61   private double fy(double x, double y) {
  62     return c * x + d * y;
  63   }
  64   // x[], y[] の内容をグラフにする
  65   private void drawGraph(Graphics g, double x0, double y0, double T) {
  66     double h = 0.01 / Math.sqrt(a * a + b * b + c * c + d * d);
  67     if (T < 0.0)
  68       h = - h;
  69     int iter = (int)Math.rint(Math.abs(T / h));
  70     double x = x0;
  71     double y = y0;
  72     double new_x, new_y;
  73     for (int i = 0; i <= iter; i++) {
  74       double k1x = h * fx(x, y);
  75       double k1y = h * fy(x, y);
  76       double k2x = h * fx(x + k1x / 2, y + k1y / 2);
  77       double k2y = h * fy(x + k1x / 2, y + k1y / 2);
  78       double k3x = h * fx(x + k2x / 2, y + k2y / 2);
  79       double k3y = h * fy(x + k2x / 2, y + k2y / 2);
  80       double k4x = h * fx(x + k3x, y + k3y);
  81       double k4y = h * fy(x + k3x, y + k3y);
  82       new_x = x + (k1x + 2 * k2x + 2 * k3x + k4x) / 6;
  83       new_y = y + (k1y + 2 * k2y + 2 * k3y + k4y) / 6;
  84       if (IsIn(x, y) && IsIn(new_x, new_y))
  85           g.drawLine(wx(x), wy(y), wx(new_x), wy(new_y));
  86       x = new_x; y = new_y;
  87     }
  88   }
  89 
  90   public void paint(Graphics g) {
  91     //
  92     space(x_min - x_margin, y_min - y_margin,
  93           x_max + x_margin, y_max + y_margin);
  94     //
  95     setBackground(Color.blue);
  96     //
  97     g.setColor(Color.black);
  98     g.drawLine(wx(x_min), wy(0.0), wx(x_max), wy(0.0));
  99     g.drawLine(wx(0.0), wy(y_min), wx(0.0), wy(y_max));
 100     //
 101     g.setColor(Color.yellow);
 102     int n = 36;
 103     double dt = 2 * Math.PI / n;
 104     double Time = 10.0 / Math.sqrt(a * a + b * b + c * c + d * d);
 105     for (int i = 0; i < n; i++) {
 106       double t = i * dt;
 107       drawGraph(g, Math.cos(t), Math.sin(t),   Time);
 108       drawGraph(g, Math.cos(t), Math.sin(t), - Time);
 109     }
 110   }
 111 }
 112 
 113 public class ODE1 extends Applet implements ActionListener {
 114 
 115   private int N = 20;
 116   private double lambda = 0.5;
 117   private double Tmax = 0.5;
 118   // ユーザーとのインターフェイス (パラメーターの入力)
 119   private Label label_a, label_b, label_c, label_d;
 120   private TextField input_a, input_b, input_c, input_d;
 121   private double a, b, c, d;
 122   private Button startB;
 123   //
 124   private GraphCanvas gc;
 125 
 126   private void ReadFields() {
 127     a = Double.valueOf(input_a.getText()).doubleValue();
 128     b = Double.valueOf(input_b.getText()).doubleValue();
 129     c = Double.valueOf(input_c.getText()).doubleValue();
 130     d = Double.valueOf(input_d.getText()).doubleValue();
 131   }
 132   // 準備 (変数の用意と座標系の初期化など)
 133   public void init() {
 134     // ナル・レイアウト
 135     setLayout(null);
 136     // a, b, c, d を入力するためのテキスト・フィールド
 137     add(label_a = new Label("a=")); label_a.setBounds(100, 30, 40, 30);
 138     add(label_b = new Label("b=")); label_b.setBounds(250, 30, 40, 30);
 139     add(label_c = new Label("c=")); label_c.setBounds(100, 70, 40, 30);
 140     add(label_d = new Label("d=")); label_d.setBounds(250, 70, 40, 30);
 141     add(input_a = new TextField("" + 1)); input_a.setBounds(150, 30, 100, 30);
 142     add(input_b = new TextField("" + 0)); input_b.setBounds(300, 30, 100, 30);
 143     add(input_c = new TextField("" + 0)); input_c.setBounds(150, 70, 100, 30);
 144     add(input_d = new TextField("" + 1)); input_d.setBounds(300, 70, 100, 30);
 145     // 再計算ボタン
 146     startB = new Button("Restart");
 147     add(startB);
 148     startB.setBounds(420, 45, 50, 30);
 149     startB.addActionListener(this);
 150 
 151     // キャンバス
 152     gc = new GraphCanvas();
 153     add(gc);
 154     gc.setBounds(50, 100, 400, 400);
 155     ReadFields();
 156     gc.compute(a, b, c, d);
 157   }
 158 
 159   // ボタンを押されたら、テキスト・フィールドの内容を読み取って、再描画
 160   public void actionPerformed(ActionEvent e) {
 161     if (e.getSource() == startB) {
 162       ReadFields();
 163       gc.compute(a, b, c, d);
 164     }
 165   }
 166 }

Java をサポートしたブラウザーで次のページにアクセスすると実行できる。

http://nalab.mind.meiji.ac.jp/~mk/labo/members/java/ODE1.html


next up previous contents
Next: 4.5 スレッドの利用 Up: 4 アプレットでシミュレーション・プログラムを作る Previous: 4.3 1 変数関数のグラフを描く
Masashi Katsurada
平成20年2月28日