チーム18A4
課題名
Javaによる関数の計算
研究者名
3年14組19番 Yousuke kawawta
概要
様々な波形データをフーリエ変換やアベレージフィルタ、ハイパスフィルタ、ローパスフィルタで変換した結果をグラフで表示するプログラム
ソースコード
package hardwareB3;
import static java.lang.Math.*;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Hardware2 extends Frame implements ActionListener {
//計算用変数 static double data[] = new double[200]; //フーリエ計算用変数 double[] re = new double[data.length]; double[] im = new double[data.length]; double[] z = new double[data.length]; double max = 0;
// フレームの幅と高さを表す定数 private static final int WIDTH = 500; private static final int HEIGHT = 700;
/**averageFilterの数値計算クラス * @name averageFilter */ public static double averageFilter(int i){ //0から2は平均を取れないので0にする if(0 <= i && i <= 2){ return(0); }
//平均を計算し返す else{ return(( data[i] + data[i-1] + data[i-2] + data[i-3] ) / 4); } }
/**averageFilterX2の数値計算クラス * @name averageFilterX2 */ public static double averageFilterX2(int i){ //0から6は平均を取れないので0にする if(0 <= i && i <= 6){ return(0); }
//アベレージフィルターを二回かけた計算を返す else{ return ( data[i]*1/16 + data[i-1]*2/16 + data[i-2]*3/16 + data[i-3]*4/16 + data[i-4]*3/16 + data[i-5]*2/16 + data[i-6]*1/16); } }
/**highPassFilterの数値計算クラス * @name highPassFilter */ public static double highPassFilter(int i){ //0と199は計算できないので0にする if(i == 0 | | i == 199){ return(0); }
//現在の値からローパスフィルタの結果を引けば、ハイパスフィルタの結果になる else{ return(data[i] - ((data[i-1] + data[i] + data[i+1]) / 3)); } }
/**lowPassFilterの数値計算クラス * @name lowPassFilter */ public static double lowPassFilter(int i){ //0と199は計算できないので0にする if(i == 0 | | i == 199){ return(0); }
//平均を計算し返す else{ return(( data[i-1] + data[i] + data[i+1] ) / 3); } }
/**calculate * フーリエ変換、逆フーリエ変換の計算、および処理結果の表示 * @name calculate */ public void calculate() { //フーリエ変換 for(int f = 0; f < data.length; ++ f){ //周期fについてのフーリエを計算 re[f] = 0; im[f] = 0; for(int i = 0; i < data.length; ++i){ double theta = 2 * PI * f * i / data.length; re[f] += data[i] * cos(theta); im[f] += data[i] * sin(theta); } re[f] /= data.length; im[f] /= data.length; } //振幅スペクトルの計算 for(int f = 0; f < data.length; ++ f){ z[f] = sqrt(re[f] * re[f] + im[f] * im[f]); if(max < z[f]) max = z[f]; }
//逆フーリエ変換の計算 double proc[] = new double[data.length]; for(int f = 0; f < data.length; ++f){ for(int i = 0; i < data.length; ++i){ double theta = 2 * PI * f * i / data.length; proc[i] += re[f] * cos(theta) + im[f] * sin(theta); } }
//フレームの作成 BufferedImage img = new BufferedImage(WIDTH+150, HEIGHT, BufferedImage.TYPE_INT_RGB); Graphics2D g = (Graphics2D) img.getGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, WIDTH+200, HEIGHT); g.setColor(Color.BLACK); GeneralPath gp = new GeneralPath();
//基本線(グラフの横線、縦線、中央線) for(int i = 0; i < HEIGHT/100; i++){ if(i != 1){ g.setColor(Color.RED); g.drawLine(30, 50 + i*100, 640, 50 + i*100); g.setColor(Color.BLACK); g.drawLine(30, 20 + i*100, 30, 80 + i*100); g.drawLine(30, 80 + i*100, 640, 80 + i*100); } }
//源波形のグラフの表示 g.setColor(Color.BLACK); g.drawString("Original", 10, 15); g.setColor(Color.BLUE); gp.moveTo(30, 50); for(int i = 0; i < data.length; ++i){ double a = i * 3 + 30; double b = data[i] * 30 + 50; gp.lineTo(a, b); } g.draw(gp);
//フーリエ変換のグラフの表示 g.setColor(Color.BLACK); g.drawString("Fourier Transformation", 10, 100); g.setColor(Color.BLUE); for(int i = 0; i < re.length / 2; ++i){ int h = (int) (z[i] * 85 / max); g.fillRect(i * 6 + 30, 190 - h, 4, h + 1); }
//逆フーリエ変換のグラフの表示 g.setColor(Color.BLACK); g.drawString("Inverse Fourier Transformation", 10, 210); g.setColor(Color.BLUE); gp = new GeneralPath(); gp.moveTo(30, 250); for(int i = 0; i < data.length; ++i){ double a = i * 3 + 30; double b = proc[i] * 30 + 250; gp.lineTo(a, b); }
//Average Filterのグラフの表示 g.setColor(Color.BLACK); g.drawString("4Tap Average Filter", 10, 310); g.setColor(Color.BLUE); gp.moveTo(30, 350); for(int i = 0; i < data.length; ++i){ double a = i * 3 + 30; double b = averageFilter(i) * 30 + 350; gp.lineTo(a, b); }
//Average Filter*2のグラフの表示 g.setColor(Color.BLACK); g.drawString("4Tap Average Filter *2", 10, 410); g.setColor(Color.BLUE); gp.moveTo(30, 450); for(int i = 0; i < data.length; ++i){ double a = i * 3 + 30; double b = averageFilterX2(i) * 30 + 450; gp.lineTo(a, b); }
//High Pass Filterのグラフの表示 g.setColor(Color.BLACK); g.drawString("High Pass Filter", 10, 510); g.setColor(Color.BLUE); gp.moveTo(30, 550); for(int i = 0; i < data.length; ++i){ double a = i * 3 + 30; double b = highPassFilter(i) * 30 + 550; gp.lineTo(a, b); }
//Low Pass Filterのグラフの表示 g.setColor(Color.BLACK); g.drawString("Low Pass Filter", 10, 610); g.setColor(Color.BLUE); gp.moveTo(30, 650); for(int i = 0; i < data.length; ++i){ double a = i * 3 + 30; double b = lowPassFilter(i) * 30 + 650; gp.lineTo(a, b); }
g.draw(gp); g.dispose();
//フレームのタイトルの表示 JFrame f = new JFrame("Fourier Transformation"); f.setSize(WIDTH+200, HEIGHT+50); f.add(new JLabel(new ImageIcon(img))); f.setVisible(true); }
/**actionPerformed * ボタンの押された時の処理を設定する * @neme actionPerformed * @param ActionEvent */ public void actionPerformed(ActionEvent ae) { String commandName = ae.getActionCommand();
// コマンド名によってそれぞれの処理をする。 //ここでは、初期の波形を設定
//直線 if (commandName.equals("line")) { for(int i = 0; i < data.length; ++i){ data[i] = 0; } }
//sin波 if (commandName.equals("sin")) { for(int i = 0; i < data.length; ++i){ data[i] = sin(i)/4; } }
//矩形波 if (commandName.equals("square")) { for(int i = 0; i < data.length; ++i){ data[i]=(i % 100 >=50)? -1 : 1 ; } }
//ギザギザ if (commandName.equals("sawtooth")) { for(int i = 0; i < data.length; ++i){ data[i] = i % 50 / 25. - 1; } }
//二点だけ飛び出る波 if (commandName.equals("point")) { for(int i = 0; i < data.length; ++i){ data[i] = (i % 100 == 50)? -1 : 0; } }
//ランダム if (commandName.equals("random")) { for(int i = 0; i < data.length; ++i){ data[i] = Math.random() * 2 - 1; } }
//プログラムの終了 else if (commandName.equals("Close")) { System.exit(0); }
//波形の初期化が終わったら、グラフの各処理を行う calculate(); }
/**Hardware文 * 初めの表示を設定する * @neme Hardware */ public Hardware2() { // このフレームの大きさを設定する。 setSize(WIDTH, HEIGHT);
// 配置の方式をFlowLayout に設定 setLayout(new FlowLayout());
//"line"ボタン Button lineCommentButton = new Button("line"); add(lineCommentButton); lineCommentButton.addActionListener(this);
// "sin"ボタン Button sinButton = new Button("sin"); add(sinButton); sinButton.addActionListener(this);
//"square"ボタン Button squareCommentButton = new Button("square"); add(squareCommentButton); squareCommentButton.addActionListener(this);
// "sawtooth"ボタン Button sawtoothButton = new Button("sawtooth"); add(sawtoothButton); sawtoothButton.addActionListener(this);
//"point"ボタン Button pointCommentButton = new Button("point"); add(pointCommentButton); pointCommentButton.addActionListener(this);
//"random"ボタン Button randomCommentButton = new Button("random"); add(randomCommentButton); randomCommentButton.addActionListener(this);
// 終了ボタン Button closeButton = new Button("Close"); add(closeButton); closeButton.addActionListener(this);
//フレームを可視化する setVisible(true); }
/**main文 * オブジェクトの生成 * @neme main * @param args */ public static void main(String[] args) { //オブジェクトの生成 Hardware2 ce = new Hardware2(); }
}
実行結果
直線の場合
正弦波の場合
ノコギリ波の場合
矩形波の場合
一部が飛び出ているもの
ランダムな波
考察
プログラムは15c3を参考にした。
アベレージフィルターを2度かけるとグラフはよりなめらかになることが分かった。また、振幅も減少した。
フーリエ変換した波形を逆フーリエ変換するとしっかりと元のグラフに戻ることができると判明した。
- 最終更新:2018-05-21 17:47:45