/*
* Open Source Physics software is free software as described near the bottom of this code file.
*
* For additional information and documentation on Open Source Physics please see:
* <http://www.opensourcephysics.org/>
*/
package org.opensourcephysics.frames;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.border.EtchedBorder;
import org.opensourcephysics.analysis.FourierSinCosAnalysis;
import org.opensourcephysics.display.Dataset;
import org.opensourcephysics.display.DisplayRes;
import org.opensourcephysics.display.PlottingPanel;
import org.opensourcephysics.ejs.control.GroupControl;
/**
* FFTRealFrame computes the FFT or real data and displays the result.
*
* @author W. Christian
* @version 1.0
*/
public class FFTRealFrame extends PlotFrame {
public static final int FREQ = 1;
public static final int OMEGA = 2;
protected int domainType = FREQ;
protected int gutter = 0;
private FourierSinCosAnalysis fft = new FourierSinCosAnalysis();
JMenuItem connectedItem, postItem;
GroupControl gui;
double[] x, data;
/**
* A DrawingFrame that displays a FFT as its drawable.
*
* @param xlabel String
* @param ylabel String
* @param title String
*/
public FFTRealFrame(String xlabel, String ylabel, String title) {
super(xlabel, ylabel, title);
setConnected(false);
setMarkerShape(0, Dataset.POST);
setMarkerColor(0, Color.DARK_GRAY);
limitAutoscaleY(-1.E-5, 1.E-5);
setXYColumnNames(0, DisplayRes.getString("FourierAnalysis.Column.Frequency"), //$NON-NLS-1$
DisplayRes.getString("FourierSinCosAnalysis.Column.Power"), //$NON-NLS-1$
DisplayRes.getString("FourierSinCosAnalysis.PowerSpectrum")); //$NON-NLS-1$
setMarkerShape(1, Dataset.POST);
setMarkerColor(1, Color.RED);
setXYColumnNames(1, DisplayRes.getString("FourierAnalysis.Column.Frequency"), //$NON-NLS-1$
DisplayRes.getString("FourierAnalysis.Column.Real"), //$NON-NLS-1$
DisplayRes.getString("FourierAnalysis.RealCoefficients")); //$NON-NLS-1$
setMarkerShape(2, Dataset.POST);
setMarkerColor(2, Color.BLUE);
setXYColumnNames(2, DisplayRes.getString("FourierAnalysis.Column.Frequency"), //$NON-NLS-1$
DisplayRes.getString("FourierAnalysis.Column.Imaginary"), //$NON-NLS-1$
DisplayRes.getString("FourierAnalysis.ImaginaryCoefficients")); //$NON-NLS-1$
dataTable.setRowNumberVisible(true);
buildUserInterface();
showPower();
}
/**
* Builds the user interface.
*/
void buildUserInterface() {
setSize(350, 300);
JPanel inputPanel = new JPanel();
inputPanel.setBorder(new EtchedBorder());
gui = new GroupControl(this); // use Easy Java Simulation components to build a user interface
gui.addObject(inputPanel, "Panel", "name=inputPanel;layout=flow"); //$NON-NLS-1$ //$NON-NLS-2$
gui.add("Panel", "name=radioPanel;parent=inputPanel"); //$NON-NLS-1$ //$NON-NLS-2$
gui.add("RadioButton", "parent=radioPanel;text= sin;action=showSin()"); //$NON-NLS-1$ //$NON-NLS-2$
gui.add("RadioButton", "parent=radioPanel;text= cos;action=showCos()"); //$NON-NLS-1$ //$NON-NLS-2$
gui.add("RadioButton", "parent=radioPanel;text= power;action=showPower();selected=true"); //$NON-NLS-1$ //$NON-NLS-2$
gui.add("Panel", "name=numberPanel; parent= inputPanel; layout=flow"); //$NON-NLS-1$ //$NON-NLS-2$
gui.add("Label", "parent=numberPanel; text=added points="); //$NON-NLS-1$ //$NON-NLS-2$
gui.add("NumberField", "parent=numberPanel; variable=gutter; format=000; action=setGutter();size=40,16"); //$NON-NLS-1$ //$NON-NLS-2$
getContentPane().add(inputPanel, BorderLayout.SOUTH);
}
public void showSin() {
getDataset(0).setVisible(false);
getDataset(1).setVisible(false);
getDataset(2).setVisible(true);
invalidateImage();
repaint();
}
public void showCos() {
getDataset(0).setVisible(false);
getDataset(1).setVisible(true);
getDataset(2).setVisible(false);
invalidateImage();
repaint();
}
public void showPower() {
getDataset(0).setVisible(true);
getDataset(1).setVisible(false);
getDataset(2).setVisible(false);
invalidateImage();
repaint();
}
public void setGutter() {
gutter = gui.getInt("gutter"); //$NON-NLS-1$
doFFT();
}
/**
* Adds extra points to the data before performing the Fourier analysis using the FFT.
* @param n int
*/
public void setGutter(int n) {
gutter = n;
gui.setValue("gutter", n); //$NON-NLS-1$
doFFT();
}
/**
* Sets the x-label on the plot.
*
* @param xlabel String
*/
public void setXLabel(String xlabel) {
setXYColumnNames(0, xlabel, DisplayRes.getString("FourierSinCosAnalysis.Column.Power"), //$NON-NLS-1$
DisplayRes.getString("FourierSinCosAnalysis.PowerSpectrum")); //$NON-NLS-1$
if(drawingPanel instanceof PlottingPanel) {
((PlottingPanel) drawingPanel).setXLabel(xlabel);
}
}
/**
* Adds Views menu items on the menu bar.
*/
protected void addMenuItems() {
super.addMenuItems();
JMenuBar menuBar = getJMenuBar();
if(menuBar==null) {
return;
}
JMenu menu = getMenu(DisplayRes.getString("DrawingFrame.Views_menu")); //$NON-NLS-1$
if(menu==null) {
menu = new JMenu(DisplayRes.getString("DrawingFrame.Views_menu")); //$NON-NLS-1$
menuBar.add(menu);
menuBar.validate();
} else { // add a separator if tools already exists
menu.addSeparator();
}
ButtonGroup menubarGroup = new ButtonGroup();
// post view
postItem = new JRadioButtonMenuItem(DisplayRes.getString("ComplexPlotFrame.MenuItem.PostView")); //$NON-NLS-1$
menubarGroup.add(postItem);
postItem.setSelected(true);
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
convertToPostView();
}
};
postItem.addActionListener(actionListener);
menu.add(postItem);
// connected view
connectedItem = new JRadioButtonMenuItem(DisplayRes.getString("FFTRealFrame.MenuItem.ConnectedView")); //$NON-NLS-1$
menubarGroup.add(connectedItem);
actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
convertToConnectedView();
}
};
connectedItem.addActionListener(actionListener);
menu.add(connectedItem);
}
/**
* Sets the units for the FFT output.
* Domain types are: MODE, FREQ, OMEGA
*
* @param type int
*/
public void setDomainType(int type) {
domainType = type;
switch(domainType) {
case FREQ :
fft.useRadians(false);
if(drawingPanel instanceof PlottingPanel) {
((PlottingPanel) drawingPanel).setXLabel(DisplayRes.getString("FourierAnalysis.Column.Frequency")); //$NON-NLS-1$
}
break;
case OMEGA :
fft.useRadians(true);
if(drawingPanel instanceof PlottingPanel) {
((PlottingPanel) drawingPanel).setXLabel("$\\omega$"); //$NON-NLS-1$
}
break;
}
}
public void convertToPostView() {
setConnected(false);
setMarkerShape(0, Dataset.POST);
setMarkerShape(1, Dataset.POST);
setMarkerShape(2, Dataset.POST);
drawingPanel.invalidateImage();
postItem.setSelected(true);
drawingPanel.repaint();
}
public void convertToConnectedView() {
setConnected(true);
setMarkerShape(0, Dataset.NO_MARKER);
setMarkerShape(1, Dataset.NO_MARKER);
setMarkerShape(2, Dataset.NO_MARKER);
connectedItem.setSelected(true);
drawingPanel.invalidateImage();
drawingPanel.repaint();
}
/**
* Does an FFT of the given data array.
*
* The data array is assumed to contain complex numbers stored as
* successive (re,im) pairs.
* The given array remains unchanged.
*
* @param datasetManager double[]
* @param xmin double
* @param xmax double
*/
public void doFFT(double[] xNew, double[] dataNew, int gutter) {
x = new double[2*(xNew.length/2)]; // only even number of points allowed
System.arraycopy(xNew, 0, x, 0, x.length);
data = new double[2*(dataNew.length/2)]; // only even number of points allowed
System.arraycopy(dataNew, 0, data, 0, data.length);
this.gutter = gutter;
gui.setValue("gutter", gutter); //$NON-NLS-1$
doFFT();
}
void doFFT() {
if(x==null) {
return;
}
fft.doAnalysis(x, data, gutter);
clearData();
double[][] arrayData = fft.getData2D();
append(0, arrayData[0], arrayData[1]); // power
append(1, arrayData[0], arrayData[2]); // cos coef
append(2, arrayData[0], arrayData[3]); // sin coef
if((tableFrame!=null)&&tableFrame.isShowing()) {
dataTable.refreshTable();
}
invalidateImage();
repaint();
}
/**
* Sets the axes to use a logarithmetic scale.
*/
public void setLogScale(boolean xlog, boolean ylog) {
if(drawingPanel instanceof PlottingPanel) {
((PlottingPanel) drawingPanel).setLogScale(xlog, ylog);
}
}
}
/*
* Open Source Physics software is free software; you can redistribute
* it and/or modify it under the terms of the GNU General Public License (GPL) as
* published by the Free Software Foundation; either version 2 of the License,
* or(at your option) any later version.
*
* Code that uses any portion of the code in the org.opensourcephysics package
* or any subpackage (subdirectory) of this package must must also be be released
* under the GNU GPL license.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
* or view the license online at http://www.gnu.org/copyleft/gpl.html
*
* Copyright (c) 2007 The Open Source Physics project
* http://www.opensourcephysics.org
*/