定数係数1階線形常微分方程式
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 をサポートしたブラウザーで次のページにアクセスすると実行できる。