伝達関数(ゲインと位相の計算)

ーーーーーーー AWT を利用した場合 ーーーーーーーー
/********************************/
/* 伝達関数のゲインと位相の計算 */
/*      coded by Y.Suganuma     */
/********************************/
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.text.*;

public class Test {
	public static void main (String[] args)
	{
		BodePlot bd = new BodePlot("ボード線図");
	}
}

class BodePlot extends Frame implements ActionListener, TextListener
{
	double fl, fu, si[][], bo[][];
	int k, m[], n[], n_g = -1;
	TextField fl_t, fu_t, k_t, n_g_t, ex[];
	TextArea ta;
	Button bt;
	Coef bunsi[], bunbo[];
	ScrollPane sp;

	/******************/
	/* コンストラクタ */
	/******************/
	BodePlot(String name)
	{
					// Frameクラスのコンストラクタ(Windowのタイトルを引き渡す)
		super(name);
					// Windowの大きさ
		setSize(790, 590);
					// レイアウト,背景色,フォント
		setLayout(new BorderLayout(5, 10));
		setBackground(new Color(225, 255, 225));
		Font f = new Font("TimesRoman", Font.BOLD, 20);
		setFont(f);
					// 上のパネル
		Panel pn1 = new Panel();
		pn1.setLayout(new GridLayout(2, 1, 10, 10));
		add(pn1, BorderLayout.NORTH);
		Panel pn11 = new Panel();
		pn1.add(pn11);
		pn11.add(new Label("式の数(グラフの数)"));
		n_g_t = new TextField(3);
		n_g_t.addTextListener(this);
		pn11.add(n_g_t);
		pn11.add(new Label(" "));
		bt = new Button("実行");
		bt.setBackground(Color.pink);
		bt.addActionListener(this);
		pn11.add(bt);

		Panel pn12 = new Panel();
		pn1.add(pn12);
		pn12.add(new Label("周波数下限"));
		fl = 0.01;
		fl_t = new TextField("0.01", 3);
		fl_t.addTextListener(this);
		pn12.add(fl_t);
		pn12.add(new Label(" 周波数上限"));
		fu = 100.0;
		fu_t = new TextField("100", 3);
		fu_t.addTextListener(this);
		pn12.add(fu_t);
		pn12.add(new Label(" データ数"));
		k = 100;
		k_t = new TextField("100", 3);
		k_t.addTextListener(this);
		pn12.add(k_t);
					// 中央のパネル
		sp = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
		add(sp, BorderLayout.CENTER);
					// 下のパネル
		Panel pn6 = new Panel();
		add(pn6, BorderLayout.SOUTH);
		ta = new TextArea(5, 50);
		pn6.add(ta);
					// ウィンドウを表示
		setVisible(true);
					// イベントアダプタ
		addWindowListener(new WinEnd());
	}

	/************/
	/* log10(x) */
	/************/
	static double log10(double x)
	{
		return Math.log(x) / Math.log(10.0);
	}

	/****************************************/
	/* 伝達関数のsにjωを代入した値の計算 */
	/*      ff : ω(周波数)               */
	/*      m : 分子の次数                  */
	/*      si : 分子多項式の係数           */
	/*      n : 分母の次数                  */
	/*      bo : 分母多項式の係数           */
	/*      return : 結果                   */
	/****************************************/
	static Complex G_s(double ff, int m, double si[], int n, double bo[])
	{
		Complex f, x, y;
					// 周波数を複素数に変換
		f = new Complex (0.0, ff);
					// 分子
		x = value(f, m, si);
					// 分母
		y = value(f, n, bo);

		return Complex.dev(x, y);
	}

	/**************************************/
	/* 多項式のsにjωを代入した値の計算 */
	/*      f : jω(周波数,複素数)    */
	/*      n : 多項式の次数              */
	/*      a : 多項式の係数              */
	/*      return : 結果                 */
	/**************************************/
	static Complex value(Complex f, int n, double a[])
	{
		int i1, k1;
		Complex x;

		x = new Complex (0.0, 0.0);
		for (i1 = 0; i1 <= n; i1++)
			x = Complex.add(x, Complex.mul(new Complex(a[i1]), Complex.pow(f, i1)));

		return x;
	}

	/******************************/
	/* 上,左,下,右の余白の設定 */
	/******************************/
	public Insets getInsets()
	{
		return new Insets(70, 20, 20, 20);
	}

	/******************************/
	/* ボタンが押されたときの処理 */
	/******************************/
	public void actionPerformed(ActionEvent e)
	{
		double x, h, f, ff, g_min, g_max, p_min, p_max, uc = 90.0 / Math.asin(1.0);
		int i1, i2, k1, p, sw = 0;
		String g_title[] = null;
		Complex g;

		ta.setForeground(Color.black);
		ta.setText("");
					// エラーの判定
		if (n_g < 0) {
			sw = 1;
			ta.setForeground(Color.red);
			ta.append(" 式の数を入力してください\n");
		}
		else {
			g_title = new String [n_g];
			for (i1 = 0; i1 < n_g; i1++) {
				if (ex[i1].getText().length() <= 0) {
					sw = 1;
					ta.setForeground(Color.red);
					ta.append(" " + (i1+1) + " 番目の式の説明(凡例)を入力してください\n");
				}
				else
					g_title[i1] = ex[i1].getText();
			}

			for (i1 = 0; i1 < n_g; i1++) {
				if (m[i1] < 0) {
					sw = 1;
					ta.setForeground(Color.red);
					ta.append(" " + (i1+1) + " 番目の式の分子の次数を入力してください\n");
				}
				else {
					for (i2 = 0; i2 <= m[i1]; i2++) {
						if (bunsi[i1].bun_t[i2].getText().length() <= 0) {
							sw = 1;
							ta.setForeground(Color.red);
							ta.append(" " + (i1+1) + " 番目の式の分子の s の " + i2 + " 次の係数を入力してください\n");
						}
						else
							si[i1][i2] = Double.parseDouble(bunsi[i1].bun_t[i2].getText());
					}
				}
			}

			for (i1 = 0; i1 < n_g; i1++) {
				if (n[i1] < 0) {
					sw = 1;
					ta.setForeground(Color.red);
					ta.append(" " + (i1+1) + " 番目の式の分母の次数を入力してください\n");
				}
				else {
					for (i2 = 0; i2 <= n[i1]; i2++) {
						if (bunbo[i1].bun_t[i2].getText().length() <= 0) {
							sw = 1;
							ta.setForeground(Color.red);
							ta.append(" " + (i1+1) + " 番目の式の分母の s の " + i2 + " 次の係数を入力してください\n");
						}
						else
							bo[i1][i2] = Double.parseDouble(bunbo[i1].bun_t[i2].getText());
					}
				}
			}
		}
					// ゲインと位相の計算
		if (sw == 0) {
						// 下限と上限の再設定
			if (fl < 1.0) {
				x = 0.1;
				while (fl < x-1.0e-10)
					x /= 10.0;
				fl = x;
			}
			else {
				x = 1.0;
				while (fl > x-1.0e-10)
					x *= 10.0;
				fl = x;
			}
			if (fu < 1.0) {
				x = 0.1;
				while (fu < x+1.0e-10)
					x /= 10.0;
				fu = 10.0 * x;
			}
			else {
				x = 1.0;
				while (fu > x+1.0e-10)
					x *= 10.0;
				fu = x;
			}
						// 初期設定
			double freq1[][] = new double [n_g][k+1];
			double freq2[][] = new double [n_g][k+1];
			double gain[][] = new double [n_g][k+1];
			double phase[][] = new double [n_g][k+1];
			h     = (log10(fu) - log10(fl)) / k;
			g_min = 0.0;
			g_max = 0.0;
			p_min = 0.0;
			p_max = 0.0;
			ta.setText(" 角周波数 ゲイン(dB) 位相(度)\n");

			for (i1 = 0; i1 < n_g; i1++) {
				ff = log10(fl);
				ta.append(g_title[i1] + "\n");
				for (i2 = 0; i2 <= k; i2++) {
						// 周波数の対数を元に戻す
					f             = Math.pow(10.0, ff);
					freq1[i1][i2] = f;
					freq2[i1][i2] = f;
					ta.append(" " + f);
						// 値の計算
					g = G_s(f, m[i1], si[i1], n[i1], bo[i1]);
						// ゲインと位相の計算
					gain[i1][i2] = 20.0 * log10(Complex.abs(g));
					ta.append(" " + gain[i1][i2]);
					if (i1 == 0 && i2 == 0) {
						g_min = gain[i1][i2];
						g_max = gain[i1][i2];
					}
					else {
						if (gain[i1][i2] > g_max)
							g_max = gain[i1][i2];
						else if (gain[i1][i2] < g_min)
							g_min = gain[i1][i2];
					}
					x = Complex.angle(g) * uc;
					if (i2 > 0) {
						while (Math.abs(phase[i1][i2-1]-x) > 180.0) {
							if (x-phase[i1][i2-1] > 180.0)
								x -= 360.0;
							else {
								if (x-phase[i1][i2-1] < -180.0)
									x += 360.0;
							}
						}
					}
					phase[i1][i2] = x;
					ta.append(" " + x + "\n");
					if (i1 == 0 && i2 == 0) {
						p_min = phase[i1][i2];
						p_max = phase[i1][i2];
					}
					else {
						if (phase[i1][i2] > p_max)
							p_max = phase[i1][i2];
						else if (phase[i1][i2] < p_min)
							p_min = phase[i1][i2];
					}
						// 次の周波数
					ff += h;
				}
			}
					// グラフの描画
						// グラフ,x軸,及び,y軸のタイトル
			String title1[] = new String [3];
			title1[0] = "ゲイン線図";
			title1[1] = "角周波数";
			title1[2] = "ゲイン(dB)";
						// ゲイン線図
							// x軸目盛り
			double x_scale1[] = new double[3];
			x_scale1[0] = fl;   // 最小値
			x_scale1[1] = fu;   // 最大値
			x_scale1[2] = 1.0;   // 最大値
							// y軸目盛り
			double y_scale1[] = new double[3];
			if ((g_max-g_min) < 1.0e-5) {
				if (g_min > 0.0) {
					k1 = (int)Math.round(g_min / 20);
					y_scale1[0] = 20.0 * k1 - 20.0;   // 最小値
					y_scale1[1] = 20.0 * k1 + 20.0;   // 最大値
				}
				else {
					k1 = (int)Math.round(-g_min / 20);
					y_scale1[0] = -20.0 * k1 - 20.0;   // 最小値
					y_scale1[1] = -20.0 * k1 + 20.0;   // 最大値
				}
			}
			else {
				if (g_min > 0.0) {
					k1 = (int)(g_min / 20);
					y_scale1[0] = 20.0 * k1;   // 最小値
				}
				else {
					k1 = (int)(-g_min / 20);
					if (Math.abs(-20.0*k1-g_min) > 1.0e-5)
						k1++;
					y_scale1[0] = -20.0 * k1;   // 最小値
				}
				if (g_max > 0.0) {
					k1 = (int)(g_max / 20);
					if (Math.abs(20.0*k1-g_max) > 1.0e-5)
						k1++;
					y_scale1[1] = 20.0 * k1;   // 最大値
				}
				else {
					k1 = (int)(-g_max / 20);
					y_scale1[1] = -20.0 * k1;   // 最大値
				}
			}
			y_scale1[2] = 20.0;   // 刻み幅
							// x軸の小数点以下桁数
			p = 0;
			if (fl < 1.0) {
				p = 1;
				x = 0.1;
				while (fl < x-1.0e-10) {
					x /= 10.0;
					p++;
				}
			}

			Bode gp1 = new Bode(title1, g_title, x_scale1, p, y_scale1, 0, freq1, gain, true, true);
						// 位相線図
							// グラフ,x軸,及び,y軸のタイトル
			String title2[] = new String [3];
			title2[0] = "位相線図";
			title2[1] = "角周波数";
			title2[2] = "位相(度)";
							// x軸目盛り
			double x_scale2[] = new double[3];
			x_scale2[0] = fl;   // 最小値
			x_scale2[1] = fu;   // 最大値
			x_scale2[2] = 1.0;   // 最大値
							// y軸目盛り
			double y_scale2[] = new double[3];
			if ((p_max-p_min) < 1.0e-5) {
				if (p_min > 0.0) {
					k1 = (int)Math.round(p_min / 90);
					y_scale2[0] = 90.0 * k1 - 90.0;   // 最小値
					y_scale2[1] = 90.0 * k1 + 90.0;   // 最大値
				}
				else {
					k1 = (int)Math.round(-p_min / 90);
					y_scale2[0] = -90.0 * k1 - 90.0;   // 最小値
					y_scale2[1] = -90.0 * k1 + 90.0;   // 最大値
				}
			}
			else {
				if (p_min > 0.0) {
					k1 = (int)(p_min / 90);
					y_scale2[0] = 90.0 * k1;   // 最小値
				}
				else {
					k1 = (int)(-p_min / 90);
					if (Math.abs(-90.0*k1-p_min) > 1.0e-5)
						k1++;
					y_scale2[0] = -90.0 * k1;   // 最小値
				}
				if (p_max > 0.0) {
					k1 = (int)(p_max / 90);
					if (Math.abs(90.0*k1-p_max) > 1.0e-5)
						k1++;
					y_scale2[1] = 90.0 * k1;   // 最大値
				}
				else {
					k1 = (int)(-p_max / 90);
					y_scale2[1] = -90.0 * k1;   // 最大値
				}
			}
			y_scale2[2] = 90.0;   // 刻み幅

			Bode gp2 = new Bode(title2, g_title, x_scale2, p, y_scale2, 0, freq2, phase, true, true);
		}
	}

	/************************************/
	/* パラメータが変更されたときの処理 */
	/************************************/
	public void textValueChanged(TextEvent e)
	{
		int i1;

		try {
			if (e.getSource() == n_g_t) {
				n_g = Integer.parseInt(n_g_t.getText());
				ta.setForeground(Color.black);
				ta.setText("");
				if (n_g <= 0) {
					ta.setForeground(Color.red);
					ta.setText(" 0 より大きい数値を入力してください");
				}
				else {
					si = new double [n_g][];
					bo = new double [n_g][];
					m  = new int [n_g];
					n  = new int [n_g];
					for (i1 = 0; i1 < n_g; i1++) {
						m[i1] = -1;
						n[i1] = -1;
					}
					remove(sp);
					sp = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
					add(sp, BorderLayout.CENTER);
					Panel pn2 = new Panel();
					pn2.setLayout(new GridLayout(n_g, 1, 10, 10));
					sp.add(pn2);
					ScrollPane sp1[] = new ScrollPane [n_g];
					ScrollPane sp2[] = new ScrollPane [n_g];
					Panel pn3[] = new Panel [n_g];
					Panel pn4[] = new Panel [n_g];
					Panel pn5[] = new Panel [n_g];
					ex    = new TextField [n_g];
					bunsi = new Coef [n_g];
					bunbo = new Coef [n_g];
					for (i1 = 0; i1 < n_g; i1++) {
						pn3[i1] = new Panel();
						pn3[i1].setBackground(new Color(255, 255, 225));
						pn3[i1].setLayout(new BorderLayout(5, 10));
						pn2.add(pn3[i1]);
						pn4[i1] = new Panel();
						pn4[i1].add(new Label((i1+1) + "番目の式の説明:"));
						ex[i1] = new TextField(10);
						pn4[i1].add(ex[i1]);
						pn3[i1].add(pn4[i1], BorderLayout.NORTH);
						pn5[i1] = new Panel();
						pn5[i1].setLayout(new GridLayout(1, 2, 10, 10));
						pn3[i1].add(pn5[i1], BorderLayout.CENTER);
						sp1[i1] = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
						pn5[i1].add(sp1[i1]);
						bunsi[i1] = new Coef(0, this, i1);
						sp1[i1].add(bunsi[i1]);
						sp2[i1] = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
						pn5[i1].add(sp2[i1]);
						bunbo[i1] = new Coef(1, this, i1);
						sp2[i1].add(bunbo[i1]);
					}
					validate();
				}
			}
			else if (e.getSource() == fl_t) {
				fl = Double.parseDouble(fl_t.getText());
				fu = Double.parseDouble(fu_t.getText());
				ta.setForeground(Color.black);
				ta.setText("");
				if (fl <= 0.0) {
					ta.setForeground(Color.red);
					ta.setText(" 0 より大きい数値を入力してください");
				}
				else if (fu <= fl) {
					ta.setForeground(Color.red);
					ta.setText(" 上限より小さい数値を入力してください");
				}
			}
			else if (e.getSource() == fu_t) {
				fl = Double.parseDouble(fl_t.getText());
				fu = Double.parseDouble(fu_t.getText());
				ta.setForeground(Color.black);
				ta.setText("");
				if (fu <= 0.0) {
					ta.setForeground(Color.red);
					ta.setText(" 0 より大きい数値を入力してください");
				}
				else if (fu <= fl) {
					ta.setForeground(Color.red);
					ta.setText(" 下限より大きい数値を入力してください");
				}
			}
			else if (e.getSource() == k_t) {
				k = Integer.parseInt(k_t.getText());
				ta.setForeground(Color.black);
				ta.setText("");
				if (k <= 0) {
					ta.setForeground(Color.red);
					ta.setText(" 0 より大きい数値を入力してください");
				}
			}
		}
		catch (NumberFormatException em) {}
	}

	/************/
	/* 終了処理 */
	/************/
	class WinEnd extends WindowAdapter
	{
		public void windowClosing(WindowEvent e) {
			System.exit(0);
		}
	}
}

/****************************/
/* ボード線図の描画         */
/*      coded by Y.Suganuma */
/****************************/
class Bode extends Frame {

	String title[];   // グラフのタイトル
	String g_title[];   // 凡例(グラフの内容)
	double xx_scale[];   // y軸目盛り
	double x_scale[];   // 元のy軸目盛り
	double y_scale[];   // y軸目盛り
	double data_x[][];   // 元のデータ
	double data_xx[][], data_y[][];   // データ
	boolean d_t;   // タイトル表示の有無
	boolean d_g;   // 凡例表示の有無
	boolean log_c = false;   // 対数に変換したか否か
	int place_x;   // 小数点以下の桁数(x軸)
	int place_y;   // 小数点以下の桁数(y軸)
	int width = 900, height = 600;   // Windowの大きさ(初期サイズ)
	int bx1, bx2, by1, by2;   // 表示切り替えボタンの位置
	String change = " 色 ";   // 表示切り替えボタン
	float line_w = 1.0f;   // 折れ線グラフ等の線の太さ
	Color cl[] = {Color.black, Color.magenta, Color.blue, Color.orange, Color.cyan,
	              Color.pink, Color.green, Color.yellow, Color.darkGray, Color.red};   // グラフの色
	int n_g;   // グラフの数

	/*********************************************************/
	/* コンストラクタ                                        */
	/*      title_i : グラフ,x軸,及び,y軸のタイトル     */
	/*      g_title_i : 凡例                                 */
	/*      x_scale_i : データの最小値,最大値,目盛幅(y) */
	/*      place_x_i : 小数点以下の桁数(x軸)             */
	/*      y_scale_i : データの最小値,最大値,目盛幅(y) */
	/*      place_y_i : 小数点以下の桁数(y軸)             */
	/*      data_x_i : グラフのデータ(x軸)                */
	/*      data_y_i : グラフのデータ(y軸)                */
	/*      d_t_i : タイトル表示の有無                       */
	/*      d_g_i : 凡例表示の有無                           */
	/*********************************************************/
	Bode(String title_i[], String g_title_i[], double x_scale_i[],
              int place_x_i, double y_scale_i[], int place_y_i,
              double data_x_i[][], double data_y_i[][], boolean d_t_i,
              boolean d_g_i)
	{
					// Frameクラスのコンストラクタの呼び出し
		super("ボード線図");
					// テーブルデータの保存
		title   = title_i;
		g_title = g_title_i;
		x_scale = x_scale_i;
		place_x = place_x_i;
		y_scale = y_scale_i;
		place_y = place_y_i;
		data_x  = data_x_i;
		data_y  = data_y_i;
		d_t     = d_t_i;
		d_g     = d_g_i;

		int i1, i2;
		int n_g = g_title.length;
		int n_p = data_x[0].length;
		xx_scale  = new double [3];
		data_xx   = new double [n_g][n_p];
		xx_scale[0] = x_scale[0];
		xx_scale[1] = x_scale[1];
		for (i1 = 0; i1 < n_g; i1++) {
			for (i2 = 0; i2 < n_p; i2++)
				data_xx[i1][i2] = data_x[i1][i2];
		}
					// Windowサイズと表示位置を設定
		setSize(width, height);
		Toolkit tool = getToolkit();
		Dimension d  = tool.getScreenSize();
		setLocation(d.width / 2 - width / 2, d.height / 2 - height / 2);
					// ウィンドウを表示
		setVisible(true);
					// イベントアダプタ
		addWindowListener(new WinEnd());
		addComponentListener(new ComponentResize());
		addMouseListener(new ClickMouse(this));
	}

	/********/
	/* 描画 */
	/********/
	public void paint (Graphics g)
	{
		double r, x1, y1, y2, sp, x_scale_org = 0.0;
		int i1, i2, cr, k, k_x, k_y, k1, k2, kx, kx1, ky, ky1, han, len;
		int x_l, x_r, y_u, y_d;   // 描画領域
		int f_size;   // フォントサイズ
		int n_p;   // データの数
		String s1;
		Font f;
		FontMetrics fm;
		Graphics2D g2 = (Graphics2D)g;
					//
					// Windowサイズの取得
					//
		Insets insets = getInsets();
		Dimension d = getSize();
		width  = d.width - (insets.left + insets.right);
		height = d.height - (insets.top + insets.bottom);
		x_l    = insets.left + 10;
		x_r    = d.width - insets.right - 10;
		y_u    = insets.top + 20;
		y_d    = d.height - insets.bottom;
					//
					// グラフタイトルの表示
					//
		r      = 0.05;   // タイトル領域の割合
		f_size = ((y_d - y_u) < (x_r - x_l)) ? (int)((y_d - y_u) * r) : (int)((x_r - x_l) * r);
		if (f_size < 5)
			f_size = 5;
		if (d_t) {
			f = new Font("TimesRoman", Font.BOLD, f_size);
			g.setFont(f);
			fm  = g.getFontMetrics(f);
			len = fm.stringWidth(title[0]);
			g.drawString(title[0], (x_l+x_r)/2-len/2, y_d-f_size/2);
			y_d -= f_size;
		}
					//
					// 表示切り替えボタンの設置
					//
		f_size = (int)(0.8 * f_size);
		if (f_size < 5)
			f_size = 5;
		f  = new Font("TimesRoman", Font.PLAIN, f_size);
		fm = g.getFontMetrics(f);
		g.setFont(f);
		g.setColor(Color.yellow);
		len = fm.stringWidth(change);
		bx1 = x_r - len - 7 * f_size / 10;
		by1 = y_u - f_size / 2;
		bx2 = bx1 + len + f_size / 2;
		by2 = by1 + 6 * f_size / 5;
		g.fill3DRect(bx1, by1, len+f_size/2, 6*f_size/5, true);
		g.setColor(Color.black);
		g.drawString(change, x_r-len-f_size/2, y_u+f_size/2);
					//
					// 凡例の表示
					//
		n_g = g_title.length;
		if (d_g) {
			han = 0;
			for (i1 = 0; i1 < n_g; i1++) {
				len = fm.stringWidth(g_title[i1]);
				if (len > han)
					han = len;
			}
			han += 15;
			r    = 0.2;   // 凡例領域の割合
			k1   = (int)((x_r - x_l) * r);
			if (han > k1)
				han = k1;
			kx = x_r - han;
			ky = y_u + 3 * f_size / 2;
			k  = 0;
			g2.setStroke(new BasicStroke(7.0f));
			for (i1 = 0; i1 < n_g; i1++) {
				g.setColor(cl[k]);
				g.drawLine(kx, ky, kx+10, ky);
				g.setColor(Color.black);
				g.drawString(g_title[i1], kx+15, ky+2*f_size/5);
				k++;
				if (k >= cl.length)
					k = 0;
				ky += f_size;
			}
			g2.setStroke(new BasicStroke(1.0f));
			x_r -= (han + 10);
		}
		else
			x_r -= (int)(0.03 * (x_r - x_l));
					//
					// x軸の対数
					//
		n_p         = data_x[0].length;
		x_scale_org = x_scale[0];
		xx_scale[0] = Math.log(x_scale[0]) / Math.log(10.0);
		xx_scale[1] = Math.log(x_scale[1]) / Math.log(10.0);
		xx_scale[2] = 1.0;
		for (i1 = 0; i1 < n_g; i1++) {
			for (i2 = 0; i2 < n_p; i2++)
				data_xx[i1][i2] = Math.log(data_x[i1][i2]) / Math.log(10.0);
		}
					//
					// x軸及びy軸のタイトルの表示
					//
		if (title[1].length() > 0 && !title[1].equals("-")) {
			len = fm.stringWidth(title[1]);
			g.drawString(title[1], (x_l+x_r)/2-len/2, y_d-4*f_size/5);
			y_d -= 7 * f_size / 4;
		}
		else
			y_d -= f_size / 2;
		if (title[2].length() > 0 && !title[2].equals("-")) {
			g.drawString(title[2], x_l, y_u+f_size/2);
			y_u += f_size;
		}
					//
					// x軸,y軸,及び,各軸の目盛り
					//
		f_size = (int)(0.8 * f_size);
		if (f_size < 5)
			f_size = 5;
		f    = new Font("TimesRoman", Font.PLAIN, f_size);
		fm   = g.getFontMetrics(f);
		y_d -= 3 * f_size / 2;
		k_y  = (int)((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
		k_x  = (int)((xx_scale[1] - xx_scale[0]) / (0.99 * xx_scale[2]));
		g.setFont(f);

		DecimalFormat df_x, df_y;
		df_x = new DecimalFormat("#");
		df_y = new DecimalFormat("#");
		if (place_x != 0) {
			s1 = "0.";
			for (i1 = 0; i1 < place_x; i1++)
				s1 += "0";
			df_x = new DecimalFormat(s1);
		}
		if (place_y != 0) {
			s1 = "#.";
			for (i1 = 0; i1 < place_y; i1++)
				s1 += "0";
			df_y = new DecimalFormat(s1);
		}
						// y軸
		y1  = y_scale[0];
		len = 0;
		for (i1 = 0; i1 < k_y+1; i1++) {
			s1 = df_y.format(y1);
			k1 = fm.stringWidth(s1);
			if (k1 > len)
				len = k1;
			y1 += y_scale[2];
		}
		g.drawLine(x_l+len+5, y_u, x_l+len+5, y_d);
		g.drawLine(x_r, y_u, x_r, y_d);
		y1 = y_scale[0];
		x1 = y_d;
		sp = (double)(y_d - y_u) / k_y;
		for (i1 = 0; i1 < k_y+1; i1++) {
			ky = (int)Math.round(x1);
			s1 = df_y.format(y1);
			k1 = fm.stringWidth(s1);
			g.drawString(s1, x_l+len-k1, ky+f_size/2);
			g.drawLine(x_l+len+5, ky, x_r, ky);
			y1 += y_scale[2];
			x1 -= sp;
		}
		x_l += (len + 5);
						// x軸
		x1 = x_scale_org;
		y1 = x_l;
		sp = (double)(x_r - x_l) / k_x;
		for (i1 = 0; i1 < k_x+1; i1++) {
			kx = (int)Math.round(y1);
			s1 = df_x.format(x1);
			k1 = fm.stringWidth(s1);
			g.drawString(s1, kx-k1/2, y_d+6*f_size/5);
			g.drawLine(kx, y_d, kx, y_u);
			if (i1 != k_x) {
				g.setColor(Color.darkGray);
				for (i2 = 2; i2 <= 9; i2++) {
					y2 = Math.log(x1 * i2) / Math.log(10.0);
					kx = x_l + (int)Math.round(((x_r - x_l) * (y2 - xx_scale[0]) / (xx_scale[1] - xx_scale[0])));
					g.drawLine(kx, y_d, kx, y_u);
				}
				g.setColor(Color.black);
			}
			x1 *= 10.0;
			y1 += sp;
		}
					//
					// グラフの表示
					//
		g2.setStroke(new BasicStroke(line_w));
		k1  = 0;
		for (i1 = 0; i1 < n_g; i1++) {
			g.setColor(cl[k1]);
			kx1 = 0;
			ky1 = 0;
			for (i2 = 0; i2 < n_p; i2++) {
				kx = x_l + (int)((x_r - x_l) * (data_xx[i1][i2] - xx_scale[0]) / (xx_scale[1] - xx_scale[0]));
				ky = y_d - (int)((y_d - y_u) * (data_y[i1][i2] - y_scale[0]) / (y_scale[1] - y_scale[0]));
				if (i2 > 0)
					g.drawLine(kx1, ky1, kx, ky);
				kx1 = kx;
				ky1 = ky;
			}
			k1++;
			if (k1 >= cl.length)
				k1 = 0;
		}
		g2.setStroke(new BasicStroke(1.0f));
	}

	/**********************/
	/* Windowのサイズ変化 */
	/**********************/
	class ComponentResize extends ComponentAdapter
	{
		public void componentResized(ComponentEvent e)
		{
			repaint();
		}
	}

	/************/
	/* 終了処理 */
	/************/
	class WinEnd extends WindowAdapter
	{
		public void windowClosing(WindowEvent e) {
			setVisible(false);
		}
	}

	/************************************/
	/* マウスがクリックされたときの処理 */
	/************************************/
	class ClickMouse extends MouseAdapter
	{
		Bode dd;

		ClickMouse(Bode dd1)
		{
			dd = dd1;
		}

		public void mouseClicked(MouseEvent e)
		{
			int xp = e.getX();
			int yp = e.getY();
					// グラフの色,線の太さ等
			if (xp > bx1 && xp < bx2 && yp > by1 && yp < by2) {
				Modify md = new Modify(dd);
				md.setVisible(true);
			}
		}
	}
}

/****************************/
/* 色及び線の太さの変更     */
/*      coded by Y.Suganuma */
/****************************/
class Modify extends Dialog implements ActionListener, TextListener {
	Bode dd;   // ボード線図
	Button bt_dd;
	TextField rgb[];
	TextField r[];
	TextField g[];
	TextField b[];
	TextField tx;
	Checkbox r1, r2;
	float line_w = 1.0f;   // 折れ線グラフ等の線の太さ
	Color cl[];   // グラフの色
	int n_g;   // グラフの数
	int wd;   // 線の太さを変更するか
	int n;
	Panel jp[];
					// ボード線図
	Modify(Bode dd1)
	{
		super(dd1, "色と線の変更", true);
							// 初期設定
		Font f = new Font("TimesRoman", Font.BOLD, 20);
		setFont(f);
		dd  = dd1;
		wd  = 1;
		n_g = dd.n_g;
		if (n_g > 10)
			n_g = 10;
		n      = n_g + 2;
		line_w = dd.line_w;
		cl     = new Color[n_g];
		for (int i1 = 0; i1 < n_g; i1++)
			cl[i1] = dd.cl[i1];
		set();
							// ボタン
		bt_dd = new Button("OK");
		bt_dd.addActionListener(this);
		jp[n-1].add(bt_dd);
	}
					// 設定
	void set()
	{
		setSize(450, 60*(n));
		setBackground(Color.white);
		setLayout(new GridLayout(n, 1, 5, 5));
		jp = new Panel[n];
		for (int i1 = 0; i1 < n; i1++) {
			jp[i1] = new Panel();
			add(jp[i1]);
		}
							// 色の変更
		Label lb[][] = new Label[n_g][3];
		rgb = new TextField[n_g];
		r = new TextField[n_g];
		g = new TextField[n_g];
		b = new TextField[n_g];
		for (int i1 = 0; i1 < n_g; i1++) {
			rgb[i1] = new TextField(3);
			rgb[i1].setBackground(new Color(cl[i1].getRed(), cl[i1].getGreen(), cl[i1].getBlue()));
			jp[i1].add(rgb[i1]);
			lb[i1][0] = new Label(" 赤");
			jp[i1].add(lb[i1][0]);
			r[i1] = new TextField(3);
			r[i1].setBackground(Color.white);
			r[i1].setText(Integer.toString(cl[i1].getRed()));
			r[i1].addTextListener(this);
			jp[i1].add(r[i1]);
			lb[i1][1] = new Label("緑");
			jp[i1].add(lb[i1][1]);
			g[i1] = new TextField(3);
			g[i1].setBackground(Color.white);
			g[i1].setText(Integer.toString(cl[i1].getGreen()));
			g[i1].addTextListener(this);
			jp[i1].add(g[i1]);
			lb[i1][2] = new Label("青");
			jp[i1].add(lb[i1][2]);
			b[i1] = new TextField(3);
			b[i1].setBackground(Color.white);
			b[i1].setText(Integer.toString(cl[i1].getBlue()));
			b[i1].addTextListener(this);
			jp[i1].add(b[i1]);
		}
							// 線の変更
		if (wd > 0) {
			Label lb1 = new Label("線の太さ:");
			jp[n_g].add(lb1);
			tx = new TextField(2);
			tx.setBackground(Color.white);
			tx.setText(Integer.toString((int)line_w));
			jp[n_g].add(tx);
		}
	}
					// TextFieldの内容が変更されたときの処理
	public void textValueChanged(TextEvent e)
	{
		for (int i1 = 0; i1 < n_g; i1++) {
			if (e.getSource() == r[i1] || e.getSource() == g[i1] || e.getSource() == b[i1]) {
				String str = r[i1].getText();
				int rc = str.length()>0 ? Integer.parseInt(str) : 0;
				str = g[i1].getText();
				int gc = str.length()>0 ? Integer.parseInt(str) : 0;
				str = b[i1].getText();
				int bc = str.length()>0 ? Integer.parseInt(str) : 0;
				rgb[i1].setBackground(new Color(rc, gc, bc));
			}
		}
	}
					// 値の設定
	public void actionPerformed(ActionEvent e)
	{
		for (int i1 = 0; i1 < n_g; i1++) {
			String str = r[i1].getText();
			int rc = str.length()>0 ? Integer.parseInt(str) : 0;
			str = g[i1].getText();
			int gc = str.length()>0 ? Integer.parseInt(str) : 0;
			str = b[i1].getText();
			int bc = str.length()>0 ? Integer.parseInt(str) : 0;
			dd.cl[i1] = new Color(rc, gc, bc);
		}
		dd.line_w = Integer.parseInt(tx.getText());
		dd.repaint();

		setVisible(false);
	}
}

/****************************/
/* クラスCoef               */
/*      coded by Y.Suganuma */
/****************************/
class Coef extends Panel implements TextListener
{
	int type, no;
	BodePlot ba;
	TextField n_t;
	TextField bun_t[];
	Label lb[];
	Panel pn;

	/***************************/
	/* コンストラクタ          */
	/*      type_i : =0 : 分子 */
	/*               =1 : 分母 */
	/*      ba_i : BodePlot    */
	/*      no_i : 式番号      */
	/***************************/
	Coef(int type_i, BodePlot ba_i, int no_i)
	{
		int i1;

		type = type_i;
		ba   = ba_i;
		no   = no_i;
					// 次数
		setLayout(new BorderLayout(5, 10));
		Panel pn1 = new Panel();
		add(pn1, BorderLayout.NORTH);
		if (type == 0)
			pn1.add(new Label((no+1)+".分子の次数"));
		else
			pn1.add(new Label((no+1)+".分母の次数"));
		n_t = new TextField(2);
		n_t.addTextListener(this);
		pn1.add(n_t);
					// 係数
		pn = new Panel();
		add(pn, BorderLayout.CENTER);
	}

	/************************************/
	/* パラメータが変更されたときの処理 */
	/************************************/
	public void textValueChanged(TextEvent e)
	{
		int i1, n;

		ba.ta.setForeground(Color.black);
		ba.ta.setText("");

		try {
			n = Integer.parseInt(n_t.getText());
			if (n < 0) {
				n_t.setText("0");
				n = 0;
			}
			if (type == 0) {
				ba.m[no]  = n;
				ba.si[no] = new double [n+1];
			}
			else {
				ba.n[no]  = n;
				ba.bo[no] = new double [n+1];
			}
			remove(pn);
			pn = new Panel();
			add(pn, BorderLayout.CENTER);
			pn.setLayout(new GridLayout(n+1, 1, 10, 0));
			Panel pnx[] = new Panel [n+1];
			bun_t  = new TextField [n+1];
			lb     = new Label [n+1];
			pnx[0] = new Panel();
			pn.add(pnx[0]);
			lb[0] = new Label("定数項");
			pnx[0].add(lb[0]);
			bun_t[0] = new TextField(3);
			pnx[0].add(bun_t[0]);
			for (i1 = 1; i1 <= n; i1++) {
				pnx[i1] = new Panel();
				pn.add(pnx[i1]);
				lb[i1] = new Label("s の "+i1+" 次の項");
				pnx[i1].add(lb[i1]);
				bun_t[i1] = new TextField(3);
				pnx[i1].add(bun_t[i1]);
			}
			getParent().validate();
		}
		catch (NumberFormatException em) {}
	}
}

/****************************/
/* クラスComplex            */
/*      coded by Y.Suganuma */
/****************************/
class Complex {
	private double r;   // 実部
	private double i;   // 虚部

	/******************/
	/* コンストラクタ */
	/*      a : 実部  */
	/*      b : 虚部  */
	/******************/
	Complex(double a, double b)
	{
		r = a;
		i = b;
	}

	/******************/
	/* コンストラクタ */
	/*      a : 実部  */
	/******************/
	Complex(double a)
	{
		r = a;
		i = 0.0;
	}

	/******************/
	/* コンストラクタ */
	/******************/
	Complex()
	{
		r = 0.0;
		i = 0.0;
	}

	/********/
	/* 出力 */
	/********/
	void output(PrintStream out, Complex a)
	{
		out.print("(" + a.r + ", " + a.i + ")");
	}

	/******************/
	/* 複素数の絶対値 */
	/******************/
	static double abs(Complex a)
	{
		double x;
		x = Math.sqrt(a.r * a.r + a.i * a.i);
		return x;
	}

	/****************/
	/* 複素数の角度 */
	/****************/
	static double angle(Complex a)
	{
		double x;
		if (a.r == 0.0 && a.i == 0.0)
			x = 0.0;
		else
			x = Math.atan2(a.i, a.r);
		return x;
	}

	/****************/
	/* 複素数のn乗 */
	/****************/
	static Complex pow(Complex a, int n)
	{
		int i1;
		Complex c = new Complex (1);
		if (n >= 0) {
			for (i1 = 0; i1 < n; i1++)
				c = Complex.mul(c, a);
		}
		else {
			for (i1 = 0; i1 < -n; i1++)
				c = Complex.mul(c, a);
			c = Complex.dev(new Complex(1.0), c);
		}
		return c;
	}

	/****************/
	/* 複素数の加算 */
	/****************/
	static Complex add(Complex a, Complex b)
	{
		Complex c = new Complex();
		c.r = a.r + b.r;
		c.i = a.i + b.i;
		return c;
	}

	/****************/
	/* 複素数の減算 */
	/****************/
	static Complex sub(Complex a, Complex b)
	{
		Complex c = new Complex();
		c.r = a.r - b.r;
		c.i = a.i - b.i;
		return c;
	}

	/****************/
	/* 複素数の乗算 */
	/****************/
	static Complex mul(Complex a, Complex b)
	{
		Complex c = new Complex();
		c.r = a.r * b.r - a.i * b.i;
		c.i = a.i * b.r + a.r * b.i;
		return c;
	}

	/****************/
	/* 複素数の除算 */
	/****************/
	static Complex dev(Complex a, Complex b)
	{
		double x;
		Complex c = new Complex();
		x   = 1.0 / (b.r * b.r + b.i * b.i);
		c.r = (a.r * b.r + a.i * b.i) * x;
		c.i = (a.i * b.r - a.r * b.i) * x;
		return c;
	}
}
		
ーーーーーーー Swing を利用した場合 ーーーーーーーー
/*****************************************/
/* 伝達関数のゲインと位相の計算(Swing) */
/*      coded by Y.Suganuma              */
/*****************************************/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
import java.text.*;

public class Test {
	public static void main (String[] args)
	{
		BodePlot_s bd = new BodePlot_s("ボード線図");
	}
}

class BodePlot_s extends JFrame implements ActionListener, DocumentListener
{
	double fl, fu, si[][], bo[][];
	int k, m[], n[], n_g = -1;
	JTextField fl_t, fu_t, k_t, n_g_t, ex[];
	JTextArea ta;
	JButton bt;
	Coef bunsi[], bunbo[];
	Container cp;
	JScrollPane sp;
	Font f = new Font("TimesRoman", Font.BOLD, 20);

	/******************/
	/* コンストラクタ */
	/******************/
	BodePlot_s(String name)
	{
					// Frameクラスのコンストラクタ(Windowのタイトルを引き渡す)
		super(name);
					// Windowの大きさ
		setSize(790, 590);
					// レイアウト,背景色,フォント
		cp = getContentPane();
		cp.setLayout(new BorderLayout(5, 5));
		cp.setBackground(new Color(225, 255, 225));
					// 上のパネル
		JPanel pn1 = new JPanel();
		pn1.setBackground(new Color(225, 255, 225));
		pn1.setLayout(new GridLayout(2, 1, 5, 5));
		cp.add(pn1, BorderLayout.NORTH);
		JPanel pn11 = new JPanel();
		pn11.setBackground(new Color(225, 255, 225));
		pn1.add(pn11);
		JLabel lb1 = new JLabel("式の数(グラフの数)");
		lb1.setFont(f);
		pn11.add(lb1);
		n_g_t = new JTextField(3);
		n_g_t.setFont(f);
		n_g_t.getDocument().putProperty("name", "no");
		n_g_t.getDocument().addDocumentListener(this);
		pn11.add(n_g_t);
		pn11.add(new JLabel(" "));
		bt = new JButton("実行");
		bt.setBackground(Color.pink);
		bt.setFont(f);
		bt.addActionListener(this);
		pn11.add(bt);

		JPanel pn12 = new JPanel();
		pn12.setBackground(new Color(225, 255, 225));
		pn1.add(pn12);
		JLabel lb2 = new JLabel("周波数下限");
		lb2.setFont(f);
		pn12.add(lb2);
		fl = 0.01;
		fl_t = new JTextField("0.01", 3);
		fl_t.setFont(f);
		fl_t.getDocument().putProperty("name", "lower");
		fl_t.getDocument().addDocumentListener(this);
		pn12.add(fl_t);
		JLabel lb3 = new JLabel(" 周波数上限");
		lb3.setFont(f);
		pn12.add(lb3);
		fu = 100.0;
		fu_t = new JTextField("100", 3);
		fu_t.setFont(f);
		fu_t.getDocument().putProperty("name", "upper");
		fu_t.getDocument().addDocumentListener(this);
		pn12.add(fu_t);
		JLabel lb4 = new JLabel(" データ数");
		lb4.setFont(f);
		pn12.add(lb4);
		k = 100;
		k_t = new JTextField("100", 3);
		k_t.setFont(f);
		k_t.getDocument().putProperty("name", "data");
		k_t.getDocument().addDocumentListener(this);
		pn12.add(k_t);
					// 中央のパネル
		sp = new JScrollPane();
		cp.add(sp, BorderLayout.CENTER);
					// 下のパネル
		JPanel pn6 = new JPanel();
		pn6.setBackground(new Color(225, 255, 225));
		cp.add(pn6, BorderLayout.SOUTH);
		ta = new JTextArea(5, 35);
		ta.setFont(f);
		JScrollPane scroll2 = new JScrollPane(ta);
		pn6.add(scroll2);
					// ウィンドウを表示
		setVisible(true);
					// イベントアダプタ
		addWindowListener(new WinEnd());
	}

	/************/
	/* log10(x) */
	/************/
	static double log10(double x)
	{
		return Math.log(x) / Math.log(10.0);
	}

	/****************************************/
	/* 伝達関数のsにjωを代入した値の計算 */
	/*      ff : ω(周波数)               */
	/*      m : 分子の次数                  */
	/*      si : 分子多項式の係数           */
	/*      n : 分母の次数                  */
	/*      bo : 分母多項式の係数           */
	/*      return : 結果                   */
	/****************************************/
	static Complex G_s(double ff, int m, double si[], int n, double bo[])
	{
		Complex f, x, y;
					// 周波数を複素数に変換
		f = new Complex (0.0, ff);
					// 分子
		x = value(f, m, si);
					// 分母
		y = value(f, n, bo);

		return Complex.dev(x, y);
	}

	/**************************************/
	/* 多項式のsにjωを代入した値の計算 */
	/*      f : jω(周波数,複素数)    */
	/*      n : 多項式の次数              */
	/*      a : 多項式の係数              */
	/*      return : 結果                 */
	/**************************************/
	static Complex value(Complex f, int n, double a[])
	{
		int i1, k1;
		Complex x;

		x = new Complex (0.0, 0.0);
		for (i1 = 0; i1 <= n; i1++)
			x = Complex.add(x, Complex.mul(new Complex(a[i1]), Complex.pow(f, i1)));

		return x;
	}

	/******************************/
	/* 上,左,下,右の余白の設定 */
	/******************************/
	public Insets getInsets()
	{
		return new Insets(70, 20, 20, 20);
	}

	/******************************/
	/* ボタンが押されたときの処理 */
	/******************************/
	public void actionPerformed(ActionEvent e)
	{
		double x, h, f, ff, g_min, g_max, p_min, p_max, uc = 90.0 / Math.asin(1.0);
		int i1, i2, k1, p, sw = 0;
		String g_title[] = null;
		Complex g;

		ta.setForeground(Color.black);
		ta.setText("");
					// エラーの判定
		if (n_g < 0) {
			sw = 1;
			ta.setForeground(Color.red);
			ta.append(" 式の数を入力してください\n");
		}
		else {
			g_title = new String [n_g];
			for (i1 = 0; i1 < n_g; i1++) {
				if (ex[i1].getText().length() <= 0) {
					sw = 1;
					ta.setForeground(Color.red);
					ta.append(" " + (i1+1) + " 番目の式の説明(凡例)を入力してください\n");
				}
				else
					g_title[i1] = ex[i1].getText();
			}

			for (i1 = 0; i1 < n_g; i1++) {
				if (m[i1] < 0) {
					sw = 1;
					ta.setForeground(Color.red);
					ta.append(" " + (i1+1) + " 番目の式の分子の次数を入力してください\n");
				}
				else {
					for (i2 = 0; i2 <= m[i1]; i2++) {
						if (bunsi[i1].bun_t[i2].getText().length() <= 0) {
							sw = 1;
							ta.setForeground(Color.red);
							ta.append(" " + (i1+1) + " 番目の式の分子の s の " + i2 + " 次の係数を入力してください\n");
						}
						else
							si[i1][i2] = Double.parseDouble(bunsi[i1].bun_t[i2].getText());
					}
				}
			}

			for (i1 = 0; i1 < n_g; i1++) {
				if (n[i1] < 0) {
					sw = 1;
					ta.setForeground(Color.red);
					ta.append(" " + (i1+1) + " 番目の式の分母の次数を入力してください\n");
				}
				else {
					for (i2 = 0; i2 <= n[i1]; i2++) {
						if (bunbo[i1].bun_t[i2].getText().length() <= 0) {
							sw = 1;
							ta.setForeground(Color.red);
							ta.append(" " + (i1+1) + " 番目の式の分母の s の " + i2 + " 次の係数を入力してください\n");
						}
						else
							bo[i1][i2] = Double.parseDouble(bunbo[i1].bun_t[i2].getText());
					}
				}
			}
		}
					// ゲインと位相の計算
		if (sw == 0) {
						// 下限と上限の再設定
			if (fl < 1.0) {
				x = 0.1;
				while (fl < x-1.0e-10)
					x /= 10.0;
				fl = x;
			}
			else {
				x = 1.0;
				while (fl > x-1.0e-10)
					x *= 10.0;
				fl = x;
			}
			if (fu < 1.0) {
				x = 0.1;
				while (fu < x+1.0e-10)
					x /= 10.0;
				fu = 10.0 * x;
			}
			else {
				x = 1.0;
				while (fu > x+1.0e-10)
					x *= 10.0;
				fu = x;
			}
						// 初期設定
			double freq1[][] = new double [n_g][k+1];
			double freq2[][] = new double [n_g][k+1];
			double gain[][] = new double [n_g][k+1];
			double phase[][] = new double [n_g][k+1];
			h     = (log10(fu) - log10(fl)) / k;
			g_min = 0.0;
			g_max = 0.0;
			p_min = 0.0;
			p_max = 0.0;
			ta.setText(" 角周波数 ゲイン(dB) 位相(度)\n");

			for (i1 = 0; i1 < n_g; i1++) {
				ff = log10(fl);
				ta.append(g_title[i1] + "\n");
				for (i2 = 0; i2 <= k; i2++) {
						// 周波数の対数を元に戻す
					f             = Math.pow(10.0, ff);
					freq1[i1][i2] = f;
					freq2[i1][i2] = f;
					ta.append(" " + f);
						// 値の計算
					g = G_s(f, m[i1], si[i1], n[i1], bo[i1]);
						// ゲインと位相の計算
					gain[i1][i2] = 20.0 * log10(Complex.abs(g));
					ta.append(" " + gain[i1][i2]);
					if (i1 == 0 && i2 == 0) {
						g_min = gain[i1][i2];
						g_max = gain[i1][i2];
					}
					else {
						if (gain[i1][i2] > g_max)
							g_max = gain[i1][i2];
						else if (gain[i1][i2] < g_min)
							g_min = gain[i1][i2];
					}
					x = Complex.angle(g) * uc;
					if (i2 > 0) {
						while (Math.abs(phase[i1][i2-1]-x) > 180.0) {
							if (x-phase[i1][i2-1] > 180.0)
								x -= 360.0;
							else {
								if (x-phase[i1][i2-1] < -180.0)
									x += 360.0;
							}
						}
					}
					phase[i1][i2] = x;
					ta.append(" " + x + "\n");
					if (i1 == 0 && i2 == 0) {
						p_min = phase[i1][i2];
						p_max = phase[i1][i2];
					}
					else {
						if (phase[i1][i2] > p_max)
							p_max = phase[i1][i2];
						else if (phase[i1][i2] < p_min)
							p_min = phase[i1][i2];
					}
						// 次の周波数
					ff += h;
				}
			}
					// グラフの描画
						// グラフ,x軸,及び,y軸のタイトル
			String title1[] = new String [3];
			title1[0] = "ゲイン線図";
			title1[1] = "角周波数";
			title1[2] = "ゲイン(dB)";
						// ゲイン線図
							// x軸目盛り
			double x_scale1[] = new double[3];
			x_scale1[0] = fl;   // 最小値
			x_scale1[1] = fu;   // 最大値
			x_scale1[2] = 1.0;   // 最大値
							// y軸目盛り
			double y_scale1[] = new double[3];
			if ((g_max-g_min) < 1.0e-5) {
				if (g_min > 0.0) {
					k1 = (int)Math.round(g_min / 20);
					y_scale1[0] = 20.0 * k1 - 20.0;   // 最小値
					y_scale1[1] = 20.0 * k1 + 20.0;   // 最大値
				}
				else {
					k1 = (int)Math.round(-g_min / 20);
					y_scale1[0] = -20.0 * k1 - 20.0;   // 最小値
					y_scale1[1] = -20.0 * k1 + 20.0;   // 最大値
				}
			}
			else {
				if (g_min > 0.0) {
					k1 = (int)(g_min / 20);
					y_scale1[0] = 20.0 * k1;   // 最小値
				}
				else {
					k1 = (int)(-g_min / 20);
					if (Math.abs(-20.0*k1-g_min) > 1.0e-5)
						k1++;
					y_scale1[0] = -20.0 * k1;   // 最小値
				}
				if (g_max > 0.0) {
					k1 = (int)(g_max / 20);
					if (Math.abs(20.0*k1-g_max) > 1.0e-5)
						k1++;
					y_scale1[1] = 20.0 * k1;   // 最大値
				}
				else {
					k1 = (int)(-g_max / 20);
					y_scale1[1] = -20.0 * k1;   // 最大値
				}
			}
			y_scale1[2] = 20.0;   // 刻み幅
							// x軸の小数点以下桁数
			p = 0;
			if (fl < 1.0) {
				p = 1;
				x = 0.1;
				while (fl < x-1.0e-10) {
					x /= 10.0;
					p++;
				}
			}

			Bode gp1 = new Bode(title1, g_title, x_scale1, p, y_scale1, 0, freq1, gain, true, true);
						// 位相線図
							// グラフ,x軸,及び,y軸のタイトル
			String title2[] = new String [3];
			title2[0] = "位相線図";
			title2[1] = "角周波数";
			title2[2] = "位相(度)";
							// x軸目盛り
			double x_scale2[] = new double[3];
			x_scale2[0] = fl;   // 最小値
			x_scale2[1] = fu;   // 最大値
			x_scale2[2] = 1.0;   // 最大値
							// y軸目盛り
			double y_scale2[] = new double[3];
			if ((p_max-p_min) < 1.0e-5) {
				if (p_min > 0.0) {
					k1 = (int)Math.round(p_min / 90);
					y_scale2[0] = 90.0 * k1 - 90.0;   // 最小値
					y_scale2[1] = 90.0 * k1 + 90.0;   // 最大値
				}
				else {
					k1 = (int)Math.round(-p_min / 90);
					y_scale2[0] = -90.0 * k1 - 90.0;   // 最小値
					y_scale2[1] = -90.0 * k1 + 90.0;   // 最大値
				}
			}
			else {
				if (p_min > 0.0) {
					k1 = (int)(p_min / 90);
					y_scale2[0] = 90.0 * k1;   // 最小値
				}
				else {
					k1 = (int)(-p_min / 90);
					if (Math.abs(-90.0*k1-p_min) > 1.0e-5)
						k1++;
					y_scale2[0] = -90.0 * k1;   // 最小値
				}
				if (p_max > 0.0) {
					k1 = (int)(p_max / 90);
					if (Math.abs(90.0*k1-p_max) > 1.0e-5)
						k1++;
					y_scale2[1] = 90.0 * k1;   // 最大値
				}
				else {
					k1 = (int)(-p_max / 90);
					y_scale2[1] = -90.0 * k1;   // 最大値
				}
			}
			y_scale2[2] = 90.0;   // 刻み幅

			Bode gp2 = new Bode(title2, g_title, x_scale2, p, y_scale2, 0, freq2, phase, true, true);
		}
	}

	/************************************/
	/* パラメータが変更されたときの処理 */
	/************************************/
	public void changedUpdate(DocumentEvent e) {}
	public void removeUpdate(DocumentEvent e) {}
	public void insertUpdate(DocumentEvent e)
	{
		int i1;
		String key = e.getDocument().getProperty("name").toString();

		try {
			if (key.equals("no")) {

				n_g = Integer.parseInt(n_g_t.getText());
				ta.setForeground(Color.black);
				ta.setText("");
				if (n_g <= 0) {
					ta.setForeground(Color.red);
					ta.setText(" 0 より大きい数値を入力してください");
				}

				else {

					remove(sp);

					si = new double [n_g][];
					bo = new double [n_g][];
					m  = new int [n_g];
					n  = new int [n_g];
					for (i1 = 0; i1 < n_g; i1++) {
						m[i1] = -1;
						n[i1] = -1;
					}

					JPanel pn2 = new JPanel();
					pn2.setBackground(new Color(225, 255, 225));
					pn2.setLayout(new GridLayout(n_g, 1, 5, 5));
					sp = new JScrollPane(pn2);

					JScrollPane sp1[] = new JScrollPane [n_g];
					JScrollPane sp2[] = new JScrollPane [n_g];
					JPanel pn3[] = new JPanel [n_g];
					JPanel pn4[] = new JPanel [n_g];
					JPanel pn5[] = new JPanel [n_g];
					JLabel lb[]  = new JLabel [n_g];
					ex    = new JTextField [n_g];
					bunsi = new Coef [n_g];
					bunbo = new Coef [n_g];

					for (i1 = 0; i1 < n_g; i1++) {
						pn3[i1] = new JPanel();
						pn3[i1].setBackground(new Color(255, 255, 225));
						pn3[i1].setLayout(new BorderLayout(5, 5));
						pn2.add(pn3[i1]);

						pn4[i1] = new JPanel();
						pn4[i1].setBackground(Color.white);
						lb[i1]  = new JLabel((i1+1) + "番目の式の説明:");
						lb[i1].setFont(f);
						pn4[i1].add(lb[i1]);
						ex[i1] = new JTextField(10);
						ex[i1].setFont(f);
						pn4[i1].add(ex[i1]);
						pn3[i1].add(pn4[i1], BorderLayout.NORTH);

						pn5[i1] = new JPanel();
						pn5[i1].setBackground(Color.white);
						pn5[i1].setLayout(new GridLayout(1, 2, 5, 5));
						bunsi[i1] = new Coef(0, this, i1);
						sp1[i1] = new JScrollPane(bunsi[i1]);
						pn5[i1].add(sp1[i1]);
						bunbo[i1] = new Coef(1, this, i1);
						sp2[i1] = new JScrollPane(bunbo[i1]);
						pn5[i1].add(sp2[i1]);
						pn3[i1].add(pn5[i1], BorderLayout.CENTER);
					}
					cp.add(sp, BorderLayout.CENTER);

					validate();
				}
			}
			else if (key.equals("lower")) {
				fl = Double.parseDouble(fl_t.getText());
				fu = Double.parseDouble(fu_t.getText());
				ta.setForeground(Color.black);
				ta.setText("");
				if (fl <= 0.0) {
					ta.setForeground(Color.red);
					ta.setText(" 0 より大きい数値を入力してください");
				}
				else if (fu <= fl) {
					ta.setForeground(Color.red);
					ta.setText(" 上限より小さい数値を入力してください");
				}
			}
			else if (key.equals("upper")) {
				fl = Double.parseDouble(fl_t.getText());
				fu = Double.parseDouble(fu_t.getText());
				ta.setForeground(Color.black);
				ta.setText("");
				if (fu <= 0.0) {
					ta.setForeground(Color.red);
					ta.setText(" 0 より大きい数値を入力してください");
				}
				else if (fu <= fl) {
					ta.setForeground(Color.red);
					ta.setText(" 下限より大きい数値を入力してください");
				}
			}
			else if (key.equals("data")) {
				k = Integer.parseInt(k_t.getText());
				ta.setForeground(Color.black);
				ta.setText("");
				if (k <= 0) {
					ta.setForeground(Color.red);
					ta.setText(" 0 より大きい数値を入力してください");
				}
			}
		}
		catch (NumberFormatException em) {}
	}

	/************/
	/* 終了処理 */
	/************/
	class WinEnd extends WindowAdapter
	{
		public void windowClosing(WindowEvent e) {
			System.exit(0);
		}
	}
}

/****************************/
/* ボード線図の描画         */
/*      coded by Y.Suganuma */
/****************************/
class Bode extends JFrame {

	Draw_bode pn;

	/*********************************************************/
	/* コンストラクタ                                        */
	/*      title_i : グラフ,x軸,及び,y軸のタイトル     */
	/*      g_title_i : 凡例                                 */
	/*      x_scale_i : データの最小値,最大値,目盛幅(y) */
	/*      place_x_i : 小数点以下の桁数(x軸)             */
	/*      y_scale_i : データの最小値,最大値,目盛幅(y) */
	/*      place_y_i : 小数点以下の桁数(y軸)             */
	/*      data_x_i : グラフのデータ(x軸)                */
	/*      data_y_i : グラフのデータ(y軸)                */
	/*      d_t_i : タイトル表示の有無                       */
	/*      d_g_i : 凡例表示の有無                           */
	/*********************************************************/
	Bode(String title_i[], String g_title_i[], double x_scale_i[],
              int place_x_i, double y_scale_i[], int place_y_i,
              double data_x_i[][], double data_y_i[][], boolean d_t_i,
              boolean d_g_i)
	{
					// JFrameクラスのコンストラクタの呼び出し
		super("ボード線図");
					// Windowサイズと表示位置を設定
		int width = 900, height = 600;   // Windowの大きさ(初期サイズ)
		setSize(width, height);
		Toolkit tool = getToolkit();
		Dimension d  = tool.getScreenSize();
		setLocation(d.width / 2 - width / 2, d.height / 2 - height / 2);
					// 描画パネル
		Container cp = getContentPane();
		pn = new Draw_bode(title_i, g_title_i, x_scale_i, place_x_i, y_scale_i, place_y_i, data_x_i, data_y_i, d_t_i, d_g_i, this);
		cp.add(pn);
					// ウィンドウを表示
		setVisible(true);
					// イベントアダプタ
		addWindowListener(new WinEnd());
		addComponentListener(new ComponentResize());
	}

	/**********************/
	/* Windowのサイズ変化 */
	/**********************/
	class ComponentResize extends ComponentAdapter
	{
		public void componentResized(ComponentEvent e)
		{
			pn.repaint();
		}
	}

	/************/
	/* 終了処理 */
	/************/
	class WinEnd extends WindowAdapter
	{
		public void windowClosing(WindowEvent e) {
			setVisible(false);
		}
	}
}

class Draw_bode extends JPanel {

	String title[];   // グラフのタイトル
	String g_title[];   // 凡例(グラフの内容)
	double xx_scale[];   // y軸目盛り
	double x_scale[];   // 元のy軸目盛り
	double y_scale[];   // y軸目盛り
	double data_x[][];   // 元のデータ
	double data_xx[][], data_y[][];   // データ
	boolean d_t;   // タイトル表示の有無
	boolean d_g;   // 凡例表示の有無
	boolean log_c = false;   // 対数に変換したか否か
	int place_x;   // 小数点以下の桁数(x軸)
	int place_y;   // 小数点以下の桁数(y軸)
	int width = 900, height = 600;   // Windowの大きさ(初期サイズ)
	int bx1, bx2, by1, by2;   // 表示切り替えボタンの位置
	Bode bd;
	String change = " 色 ";   // 表示切り替えボタン
	float line_w = 1.0f;   // 折れ線グラフ等の線の太さ
	Color cl[] = {Color.black, Color.magenta, Color.blue, Color.orange, Color.cyan,
	              Color.pink, Color.green, Color.yellow, Color.darkGray, Color.red};   // グラフの色
	int n_g;   // グラフの数

	/******************/
	/* コンストラクタ */
	/******************/
	Draw_bode(String title_i[], String g_title_i[], double x_scale_i[],
              int place_x_i, double y_scale_i[], int place_y_i,
              double data_x_i[][], double data_y_i[][], boolean d_t_i,
              boolean d_g_i, Bode bd1) {
					// 背景色
		setBackground(Color.white);
					// テーブルデータの保存
		title   = title_i;
		g_title = g_title_i;
		x_scale = x_scale_i;
		place_x = place_x_i;
		y_scale = y_scale_i;
		place_y = place_y_i;
		data_x  = data_x_i;
		data_y  = data_y_i;
		d_t     = d_t_i;
		d_g     = d_g_i;
		bd      = bd1;

		int i1, i2;
		int n_g = g_title.length;
		int n_p = data_x[0].length;
		xx_scale  = new double [3];
		data_xx   = new double [n_g][n_p];
		xx_scale[0] = x_scale[0];
		xx_scale[1] = x_scale[1];
		for (i1 = 0; i1 < n_g; i1++) {
			for (i2 = 0; i2 < n_p; i2++)
				data_xx[i1][i2] = data_x[i1][i2];
		}
					// イベントアダプタ
		addMouseListener(new ClickMouse(this));
	}

	/********/
	/* 描画 */
	/********/
	public void paintComponent (Graphics g)
	{
		super.paintComponent(g);   // 親クラスの描画(必ず必要)

		double r, x1, y1, y2, sp, x_scale_org = 0.0;
		int i1, i2, k, k_x, k_y, k1, k2, kx, kx1, ky, ky1, han, len;
		int x_l, x_r, y_u, y_d;   // 描画領域
		int f_size;   // フォントサイズ
		int n_p;   // データの数
		String s1;
		Font f;
		FontMetrics fm;
		Graphics2D g2 = (Graphics2D)g;
					//
					// Windowサイズの取得
					//
		Insets insets = bd.getInsets();
		Dimension d = bd.getSize();
		width  = d.width - (insets.left + insets.right);
		height = d.height - (insets.top + insets.bottom);
		x_l    = insets.left + 10;
		x_r    = d.width - insets.right - 10;
		y_u    = 20;
		y_d    = d.height - insets.bottom - insets.top;
					//
					// グラフタイトルの表示
					//
		r      = 0.05;   // タイトル領域の割合
		f_size = ((y_d - y_u) < (x_r - x_l)) ? (int)((y_d - y_u) * r) : (int)((x_r - x_l) * r);
		if (f_size < 5)
			f_size = 5;
		if (d_t) {
			f = new Font("TimesRoman", Font.BOLD, f_size);
			g.setFont(f);
			fm  = g.getFontMetrics(f);
			len = fm.stringWidth(title[0]);
			g.drawString(title[0], (x_l+x_r)/2-len/2, y_d-f_size/2);
			y_d -= f_size;
		}
					//
					// 表示切り替えボタンの設置
					//
		f_size = (int)(0.8 * f_size);
		if (f_size < 5)
			f_size = 5;
		f  = new Font("TimesRoman", Font.PLAIN, f_size);
		fm = g.getFontMetrics(f);
		g.setFont(f);
		g.setColor(Color.yellow);
		len = fm.stringWidth(change);
		bx1 = x_r - len - 7 * f_size / 10;
		by1 = y_u - f_size / 2;
		bx2 = bx1 + len + f_size / 2;
		by2 = by1 + 6 * f_size / 5;
		g.fill3DRect(bx1, by1, len+f_size/2, 6*f_size/5, true);
		g.setColor(Color.black);
		g.drawString(change, x_r-len-f_size/2, y_u+f_size/2);
					//
					// 凡例の表示
					//
		n_g = g_title.length;
		if (d_g) {
			han = 0;
			for (i1 = 0; i1 < n_g; i1++) {
				len = fm.stringWidth(g_title[i1]);
				if (len > han)
					han = len;
			}
			han += 15;
			r    = 0.2;   // 凡例領域の割合
			k1   = (int)((x_r - x_l) * r);
			if (han > k1)
				han = k1;
			kx = x_r - han;
			ky = y_u + 3 * f_size / 2;
			k  = 0;
			g2.setStroke(new BasicStroke(7.0f));
			for (i1 = 0; i1 < n_g; i1++) {
				g.setColor(cl[k]);
				g.drawLine(kx, ky, kx+10, ky);
				g.setColor(Color.black);
				g.drawString(g_title[i1], kx+15, ky+2*f_size/5);
				k++;
				if (k >= cl.length)
					k = 0;
				ky += f_size;
			}
			g2.setStroke(new BasicStroke(1.0f));
			x_r -= (han + 10);
		}
		else
			x_r -= (int)(0.03 * (x_r - x_l));
					//
					// x軸の対数
					//
		n_p         = data_x[0].length;
		x_scale_org = x_scale[0];
		xx_scale[0] = Math.log(x_scale[0]) / Math.log(10.0);
		xx_scale[1] = Math.log(x_scale[1]) / Math.log(10.0);
		xx_scale[2] = 1.0;
		for (i1 = 0; i1 < n_g; i1++) {
			for (i2 = 0; i2 < n_p; i2++)
				data_xx[i1][i2] = Math.log(data_x[i1][i2]) / Math.log(10.0);
		}
					//
					// x軸及びy軸のタイトルの表示
					//
		if (title[1].length() > 0 && !title[1].equals("-")) {
			len = fm.stringWidth(title[1]);
			g.drawString(title[1], (x_l+x_r)/2-len/2, y_d-4*f_size/5);
			y_d -= 7 * f_size / 4;
		}
		else
			y_d -= f_size / 2;
		if (title[2].length() > 0 && !title[2].equals("-")) {
			g.drawString(title[2], x_l, y_u+f_size/2);
			y_u += f_size;
		}
					//
					// x軸,y軸,及び,各軸の目盛り
					//
		f_size = (int)(0.8 * f_size);
		if (f_size < 5)
			f_size = 5;
		f    = new Font("TimesRoman", Font.PLAIN, f_size);
		fm   = g.getFontMetrics(f);
		y_d -= 3 * f_size / 2;
		k_y  = (int)((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
		k_x  = (int)((xx_scale[1] - xx_scale[0]) / (0.99 * xx_scale[2]));
		g.setFont(f);

		DecimalFormat df_x, df_y;
		df_x = new DecimalFormat("#");
		df_y = new DecimalFormat("#");
		if (place_x != 0) {
			s1 = "0.";
			for (i1 = 0; i1 < place_x; i1++)
				s1 += "0";
			df_x = new DecimalFormat(s1);
		}
		if (place_y != 0) {
			s1 = "#.";
			for (i1 = 0; i1 < place_y; i1++)
				s1 += "0";
			df_y = new DecimalFormat(s1);
		}
						// y軸
		y1  = y_scale[0];
		len = 0;
		for (i1 = 0; i1 < k_y+1; i1++) {
			s1 = df_y.format(y1);
			k1 = fm.stringWidth(s1);
			if (k1 > len)
				len = k1;
			y1 += y_scale[2];
		}
		g.drawLine(x_l+len+5, y_u, x_l+len+5, y_d);
		g.drawLine(x_r, y_u, x_r, y_d);
		y1 = y_scale[0];
		x1 = y_d;
		sp = (double)(y_d - y_u) / k_y;
		for (i1 = 0; i1 < k_y+1; i1++) {
			ky = (int)Math.round(x1);
			s1 = df_y.format(y1);
			k1 = fm.stringWidth(s1);
			g.drawString(s1, x_l+len-k1, ky+f_size/2);
			g.drawLine(x_l+len+5, ky, x_r, ky);
			y1 += y_scale[2];
			x1 -= sp;
		}
		x_l += (len + 5);
						// x軸
		x1 = x_scale_org;
		y1 = x_l;
		sp = (double)(x_r - x_l) / k_x;
		for (i1 = 0; i1 < k_x+1; i1++) {
			kx = (int)Math.round(y1);
			s1 = df_x.format(x1);
			k1 = fm.stringWidth(s1);
			g.drawString(s1, kx-k1/2, y_d+6*f_size/5);
			g.drawLine(kx, y_d, kx, y_u);
			if (i1 != k_x) {
				g.setColor(Color.darkGray);
				for (i2 = 2; i2 <= 9; i2++) {
					y2 = Math.log(x1 * i2) / Math.log(10.0);
					kx = x_l + (int)Math.round(((x_r - x_l) * (y2 - xx_scale[0]) / (xx_scale[1] - xx_scale[0])));
					g.drawLine(kx, y_d, kx, y_u);
				}
				g.setColor(Color.black);
			}
			x1 *= 10.0;
			y1 += sp;
		}
					//
					// グラフの表示
					//
		g2.setStroke(new BasicStroke(line_w));
		k1  = 0;
		for (i1 = 0; i1 < n_g; i1++) {
			g.setColor(cl[k1]);
			kx1 = 0;
			ky1 = 0;
			for (i2 = 0; i2 < n_p; i2++) {
				kx = x_l + (int)((x_r - x_l) * (data_xx[i1][i2] - xx_scale[0]) / (xx_scale[1] - xx_scale[0]));
				ky = y_d - (int)((y_d - y_u) * (data_y[i1][i2] - y_scale[0]) / (y_scale[1] - y_scale[0]));
				if (i2 > 0)
					g.drawLine(kx1, ky1, kx, ky);
				kx1 = kx;
				ky1 = ky;
			}
			k1++;
			if (k1 >= cl.length)
				k1 = 0;
		}
		g2.setStroke(new BasicStroke(1.0f));
	}

	/************************************/
	/* マウスがクリックされたときの処理 */
	/************************************/
	class ClickMouse extends MouseAdapter
	{
		Draw_bode dd;

		ClickMouse(Draw_bode dd1)
		{
			dd = dd1;
		}

		public void mouseClicked(MouseEvent e)
		{
			int xp = e.getX();
			int yp = e.getY();
					// グラフの色,線の太さ等
			if (xp > bx1 && xp < bx2 && yp > by1 && yp < by2) {
				Modify md = new Modify(dd.bd, dd);
				md.setVisible(true);
			}
		}
	}
}

/****************************/
/* 色及び線の太さの変更     */
/*      coded by Y.Suganuma */
/****************************/
class Modify extends JDialog implements ActionListener, TextListener {
	Draw_bode dd;   // ボード線図
	JButton bt_dd;
	TextField rgb[];
	TextField r[];
	TextField g[];
	TextField b[];
	JTextField tx;
	JRadioButton r1, r2;
	float line_w = 1.0f;   // 折れ線グラフ等の線の太さ
	Color cl[];   // グラフの色
	int n_g;   // グラフの数
	int wd;   // 線の太さを変更するか
	int n;
	JPanel jp[];
					// ボード線図
	Modify(Frame host, Draw_bode dd1)
	{
		super(host, "色と線の変更", true);
							// 初期設定
		dd  = dd1;
		wd  = 1;
		n_g = dd.n_g;
		if (n_g > 10)
			n_g = 10;
		n      = n_g + 2;
		line_w = dd.line_w;
		cl     = new Color[n_g];
		for (int i1 = 0; i1 < n_g; i1++)
			cl[i1] = dd.cl[i1];
		set();
							// ボタン
		Font f = new Font("TimesRoman", Font.BOLD, 20);
		bt_dd = new JButton("OK");
		bt_dd.setFont(f);
		bt_dd.addActionListener(this);
		jp[n-1].add(bt_dd);
	}
					// 設定
	void set()
	{
		setSize(450, 60*(n));
		Container cp = getContentPane();
		cp.setBackground(Color.white);
		cp.setLayout(new GridLayout(n, 1, 5, 5));
		jp = new JPanel[n];
		for (int i1 = 0; i1 < n; i1++) {
			jp[i1] = new JPanel();
			cp.add(jp[i1]);
		}
		Font f = new Font("TimesRoman", Font.BOLD, 20);
							// 色の変更
		JLabel lb[][] = new JLabel[n_g][3];
		rgb = new TextField[n_g];
		r = new TextField[n_g];
		g = new TextField[n_g];
		b = new TextField[n_g];
		for (int i1 = 0; i1 < n_g; i1++) {
			rgb[i1] = new TextField(3);
			rgb[i1].setFont(f);
			rgb[i1].setBackground(new Color(cl[i1].getRed(), cl[i1].getGreen(), cl[i1].getBlue()));
			jp[i1].add(rgb[i1]);
			lb[i1][0] = new JLabel(" 赤");
			lb[i1][0].setFont(f);
			jp[i1].add(lb[i1][0]);
			r[i1] = new TextField(3);
			r[i1].setFont(f);
			r[i1].setBackground(Color.white);
			r[i1].setText(Integer.toString(cl[i1].getRed()));
			r[i1].addTextListener(this);
			jp[i1].add(r[i1]);
			lb[i1][1] = new JLabel("緑");
			lb[i1][1].setFont(f);
			jp[i1].add(lb[i1][1]);
			g[i1] = new TextField(3);
			g[i1].setFont(f);
			g[i1].setBackground(Color.white);
			g[i1].setText(Integer.toString(cl[i1].getGreen()));
			g[i1].addTextListener(this);
			jp[i1].add(g[i1]);
			lb[i1][2] = new JLabel("青");
			lb[i1][2].setFont(f);
			jp[i1].add(lb[i1][2]);
			b[i1] = new TextField(3);
			b[i1].setFont(f);
			b[i1].setBackground(Color.white);
			b[i1].setText(Integer.toString(cl[i1].getBlue()));
			b[i1].addTextListener(this);
			jp[i1].add(b[i1]);
		}
							// 線の変更
		if (wd > 0) {
			JLabel lb1 = new JLabel("線の太さ:");
			lb1.setFont(f);
			jp[n_g].add(lb1);
			tx = new JTextField(2);
			tx.setFont(f);
			tx.setBackground(Color.white);
			tx.setText(Integer.toString((int)line_w));
			jp[n_g].add(tx);
		}
	}
					// TextFieldの内容が変更されたときの処理
	public void textValueChanged(TextEvent e)
	{
		for (int i1 = 0; i1 < n_g; i1++) {
			if (e.getSource() == r[i1] || e.getSource() == g[i1] || e.getSource() == b[i1]) {
				String str = r[i1].getText();
				int rc = str.length()>0 ? Integer.parseInt(str) : 0;
				str = g[i1].getText();
				int gc = str.length()>0 ? Integer.parseInt(str) : 0;
				str = b[i1].getText();
				int bc = str.length()>0 ? Integer.parseInt(str) : 0;
				rgb[i1].setBackground(new Color(rc, gc, bc));
			}
		}
	}
					// 値の設定
	public void actionPerformed(ActionEvent e)
	{
		for (int i1 = 0; i1 < n_g; i1++) {
			String str = r[i1].getText();
			int rc = str.length()>0 ? Integer.parseInt(str) : 0;
			str = g[i1].getText();
			int gc = str.length()>0 ? Integer.parseInt(str) : 0;
			str = b[i1].getText();
			int bc = str.length()>0 ? Integer.parseInt(str) : 0;
			dd.cl[i1] = new Color(rc, gc, bc);
		}
		dd.line_w = Integer.parseInt(tx.getText());
		dd.repaint();

		setVisible(false);
	}
}

/****************************/
/* クラスCoef               */
/*      coded by Y.Suganuma */
/****************************/
class Coef extends JPanel implements DocumentListener
{
	int type, no;
	BodePlot_s ba;
	JTextField n_t;
	JTextField bun_t[];
	JLabel lb[];
	JPanel pn;
	Font f = new Font("TimesRoman", Font.BOLD, 20);

	/****************************/
	/* コンストラクタ           */
	/*      type_i : =0 : 分子  */
	/*               =1 : 分母  */
	/*      ba_i : BodePlot_s   */
	/*      no_i : 式番号       */
	/****************************/
	Coef(int type_i, BodePlot_s ba_i, int no_i)
	{
		int i1;

		type = type_i;
		ba   = ba_i;
		no   = no_i;
		setBackground(Color.white);
					// 次数
		setLayout(new BorderLayout(5, 5));
		JPanel pn1 = new JPanel();
		pn1.setBackground(Color.white);
		add(pn1, BorderLayout.NORTH);
		String str;
		if (type == 0)
			str = (no + 1) + ".分子の次数";
		else
			str = (no + 1) + ".分母の次数";
		JLabel jisu = new JLabel(str);
		jisu.setFont(f);
		pn1.add(jisu);
		n_t = new JTextField(2);
		n_t.setFont(f);
		n_t.getDocument().addDocumentListener(this);
		pn1.add(n_t);
					// 係数
		pn = new JPanel();
		add(pn, BorderLayout.CENTER);
	}

	/************************************/
	/* パラメータが変更されたときの処理 */
	/************************************/
	public void changedUpdate(DocumentEvent e) {}
	public void removeUpdate(DocumentEvent e) {}
	public void insertUpdate(DocumentEvent e)
	{
		int i1, n;

		ba.ta.setForeground(Color.black);
		ba.ta.setText("");

		try {
			n = Integer.parseInt(n_t.getText());
			if (n < 0) {
				n_t.setText("0");
				n = 0;
			}
			if (type == 0) {
				ba.m[no]  = n;
				ba.si[no] = new double [n+1];
			}
			else {
				ba.n[no]  = n;
				ba.bo[no] = new double [n+1];
			}

			remove(pn);

			pn = new JPanel();
			pn.setBackground(Color.white);
			pn.setLayout(new GridLayout(n+1, 1, 5, 0));
			add(pn, BorderLayout.CENTER);

			JPanel pnx[] = new JPanel [n+1];
			bun_t  = new JTextField [n+1];
			lb     = new JLabel [n+1];

			pnx[0] = new JPanel();
			pnx[0].setBackground(Color.white);
			pn.add(pnx[0]);
			lb[0] = new JLabel("定数項");
			lb[0].setFont(f);
			pnx[0].add(lb[0]);
			bun_t[0] = new JTextField(3);
			bun_t[0].setFont(f);
			pnx[0].add(bun_t[0]);

			for (i1 = 1; i1 <= n; i1++) {
				pnx[i1] = new JPanel();
				pnx[i1].setBackground(Color.white);
				pn.add(pnx[i1]);
				lb[i1] = new JLabel("s の "+i1+" 次の項");
				lb[i1].setFont(f);
				pnx[i1].add(lb[i1]);
				bun_t[i1] = new JTextField(3);
				bun_t[i1].setFont(f);
				pnx[i1].add(bun_t[i1]);
			}

			getParent().validate();
		}
		catch (NumberFormatException em) {}
	}
}

/****************************/
/* クラスComplex            */
/*      coded by Y.Suganuma */
/****************************/
class Complex {
	private double r;   // 実部
	private double i;   // 虚部

	/******************/
	/* コンストラクタ */
	/*      a : 実部  */
	/*      b : 虚部  */
	/******************/
	Complex(double a, double b)
	{
		r = a;
		i = b;
	}

	/******************/
	/* コンストラクタ */
	/*      a : 実部  */
	/******************/
	Complex(double a)
	{
		r = a;
		i = 0.0;
	}

	/******************/
	/* コンストラクタ */
	/******************/
	Complex()
	{
		r = 0.0;
		i = 0.0;
	}

	/********/
	/* 出力 */
	/********/
	void output(PrintStream out, Complex a)
	{
		out.print("(" + a.r + ", " + a.i + ")");
	}

	/******************/
	/* 複素数の絶対値 */
	/******************/
	static double abs(Complex a)
	{
		double x;
		x = Math.sqrt(a.r * a.r + a.i * a.i);
		return x;
	}

	/****************/
	/* 複素数の角度 */
	/****************/
	static double angle(Complex a)
	{
		double x;
		if (a.r == 0.0 && a.i == 0.0)
			x = 0.0;
		else
			x = Math.atan2(a.i, a.r);
		return x;
	}

	/****************/
	/* 複素数のn乗 */
	/****************/
	static Complex pow(Complex a, int n)
	{
		int i1;
		Complex c = new Complex (1);
		if (n >= 0) {
			for (i1 = 0; i1 < n; i1++)
				c = Complex.mul(c, a);
		}
		else {
			for (i1 = 0; i1 < -n; i1++)
				c = Complex.mul(c, a);
			c = Complex.dev(new Complex(1.0), c);
		}
		return c;
	}

	/****************/
	/* 複素数の加算 */
	/****************/
	static Complex add(Complex a, Complex b)
	{
		Complex c = new Complex();
		c.r = a.r + b.r;
		c.i = a.i + b.i;
		return c;
	}

	/****************/
	/* 複素数の減算 */
	/****************/
	static Complex sub(Complex a, Complex b)
	{
		Complex c = new Complex();
		c.r = a.r - b.r;
		c.i = a.i - b.i;
		return c;
	}

	/****************/
	/* 複素数の乗算 */
	/****************/
	static Complex mul(Complex a, Complex b)
	{
		Complex c = new Complex();
		c.r = a.r * b.r - a.i * b.i;
		c.i = a.i * b.r + a.r * b.i;
		return c;
	}

	/****************/
	/* 複素数の除算 */
	/****************/
	static Complex dev(Complex a, Complex b)
	{
		double x;
		Complex c = new Complex();
		x   = 1.0 / (b.r * b.r + b.i * b.i);
		c.r = (a.r * b.r + a.i * b.i) * x;
		c.i = (a.i * b.r - a.r * b.i) * x;
		return c;
	}
}