mirror of
https://github.com/PAMGuard/PAMGuard.git
synced 2025-05-14 02:47:53 +00:00
Impulse response plot for IIF filters
Optional IIF filter impulse response plot.
This commit is contained in:
parent
7b6466b06f
commit
cadf61d218
@ -5,6 +5,7 @@ import java.awt.BorderLayout;
|
|||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.FlowLayout;
|
import java.awt.FlowLayout;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.GridBagConstraints;
|
import java.awt.GridBagConstraints;
|
||||||
@ -18,6 +19,7 @@ import java.awt.event.ActionEvent;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.font.LineMetrics;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
@ -29,10 +31,12 @@ import javax.swing.BorderFactory;
|
|||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
import javax.swing.ButtonGroup;
|
import javax.swing.ButtonGroup;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JCheckBoxMenuItem;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JFileChooser;
|
import javax.swing.JFileChooser;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.JRadioButton;
|
import javax.swing.JRadioButton;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
@ -42,12 +46,15 @@ import javax.swing.border.EmptyBorder;
|
|||||||
import javax.swing.border.TitledBorder;
|
import javax.swing.border.TitledBorder;
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.pdmodel.documentinterchange.taggedpdf.PDArtifactMarkedContent;
|
||||||
|
|
||||||
import com.opencsv.CSVReader;
|
import com.opencsv.CSVReader;
|
||||||
import com.opencsv.exceptions.CsvException;
|
import com.opencsv.exceptions.CsvException;
|
||||||
|
|
||||||
import Layout.PamAxis;
|
import Layout.PamAxis;
|
||||||
import PamUtils.PamFileChooser;
|
import PamUtils.PamFileChooser;
|
||||||
import PamUtils.PamFileFilter;
|
import PamUtils.PamFileFilter;
|
||||||
|
import PamUtils.PamUtils;
|
||||||
import PamView.PamColors;
|
import PamView.PamColors;
|
||||||
import PamView.PamColors.PamColor;
|
import PamView.PamColors.PamColor;
|
||||||
import PamView.dialog.PamDialog;
|
import PamView.dialog.PamDialog;
|
||||||
@ -56,8 +63,8 @@ import PamView.panel.PamPanel;
|
|||||||
import fftManager.Complex;
|
import fftManager.Complex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a more generic dialog panel for the PAMGurd
|
* Create a more generic dialog panel for the PAMGuard
|
||||||
* filters which can be incorporated into larger pnales
|
* filters which can be incorporated into larger panels
|
||||||
* if desired.
|
* if desired.
|
||||||
* @author Doug Gillespie
|
* @author Doug Gillespie
|
||||||
*
|
*
|
||||||
@ -696,6 +703,57 @@ public class FilterDialogPanel implements ActionListener {
|
|||||||
// PamColors.getInstance().registerComponent(this,
|
// PamColors.getInstance().registerComponent(this,
|
||||||
// PamColors.PamColor.PlOTWINDOW);
|
// PamColors.PamColor.PlOTWINDOW);
|
||||||
setPreferredSize(new Dimension(100,200));
|
setPreferredSize(new Dimension(100,200));
|
||||||
|
addMouseListener(new PZMouse());
|
||||||
|
setToolTipText("Right click to change IIR Filter plot type");
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PZMouse extends MouseAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
if (e.isPopupTrigger()) {
|
||||||
|
showPopupMenu(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
if (e.isPopupTrigger()) {
|
||||||
|
showPopupMenu(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showPopupMenu(MouseEvent e) {
|
||||||
|
|
||||||
|
if (filterMethod == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (FIRFilterMethod.class.isAssignableFrom(filterMethod.getClass())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JPopupMenu popMenu = new JPopupMenu();
|
||||||
|
JCheckBoxMenuItem menuItem;
|
||||||
|
menuItem = new JCheckBoxMenuItem("Show Pole-Zero plot", FilterParams.pzPlotStyle == FilterParams.PZPLOT_PZ);
|
||||||
|
menuItem.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
FilterParams.pzPlotStyle = FilterParams.PZPLOT_PZ;
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
popMenu.add(menuItem);
|
||||||
|
menuItem = new JCheckBoxMenuItem("Show Impulse Response", FilterParams.pzPlotStyle == FilterParams.PZPLOT_IMPULSE);
|
||||||
|
menuItem.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
FilterParams.pzPlotStyle = FilterParams.PZPLOT_IMPULSE;
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
popMenu.add(menuItem);
|
||||||
|
popMenu.show(e.getComponent(), e.getX(), e.getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -705,8 +763,12 @@ public class FilterDialogPanel implements ActionListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (IIRFilterMethod.class.isAssignableFrom(filterMethod.getClass())) {
|
if (IIRFilterMethod.class.isAssignableFrom(filterMethod.getClass())) {
|
||||||
paintIIRImpulseResponse(g);
|
if (FilterParams.pzPlotStyle == FilterParams.PZPLOT_IMPULSE) {
|
||||||
paintPoleZeros(g);
|
paintIIRImpulseResponse(g);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
paintPoleZeros(g);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (FIRFilterMethod.class.isAssignableFrom(filterMethod.getClass())) {
|
else if (FIRFilterMethod.class.isAssignableFrom(filterMethod.getClass())) {
|
||||||
paintImpulseResponse(g);
|
paintImpulseResponse(g);
|
||||||
@ -781,6 +843,9 @@ public class FilterDialogPanel implements ActionListener {
|
|||||||
for (int i = 0; i < iirFilterMethod.poleZeroCount(); i++) {
|
for (int i = 0; i < iirFilterMethod.poleZeroCount(); i++) {
|
||||||
drawZero(g, zeros[i], center, radius);
|
drawZero(g, zeros[i], center, radius);
|
||||||
}
|
}
|
||||||
|
g.setColor(Color.BLACK);
|
||||||
|
String txt = "Pole-Zero";
|
||||||
|
cornerText(g, txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -795,6 +860,20 @@ public class FilterDialogPanel implements ActionListener {
|
|||||||
if (filterMethod == null) {
|
if (filterMethod == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// try to do an upsampled filter method to make the plot clearer
|
||||||
|
int upsFactor = 10;
|
||||||
|
FilterParams upFP = iirFilterMethod.filterParams.clone();
|
||||||
|
IIRFilterMethod upsMethod = (IIRFilterMethod) FilterMethod.createFilterMethod(sampleRate*upsFactor, upFP);
|
||||||
|
int upsPoints = upsMethod.filterParams.filterOrder*10*upsFactor;
|
||||||
|
double[] upsInput = new double[upsPoints];
|
||||||
|
double[] upsOutput = new double[upsPoints];
|
||||||
|
Filter upsFilter = upsMethod.createFilter(0);
|
||||||
|
for (int i = 0; i < upsFactor; i++) {
|
||||||
|
upsInput[i] = 1;
|
||||||
|
}
|
||||||
|
// upsInput[0] = upsFactor;
|
||||||
|
upsFilter.runFilter(upsInput, upsOutput);
|
||||||
|
|
||||||
int nPoints = iirFilterMethod.filterParams.filterOrder * 10;
|
int nPoints = iirFilterMethod.filterParams.filterOrder * 10;
|
||||||
Filter filter = iirFilterMethod.createFilter(0);
|
Filter filter = iirFilterMethod.createFilter(0);
|
||||||
filter.prepareFilter();
|
filter.prepareFilter();
|
||||||
@ -802,15 +881,85 @@ public class FilterDialogPanel implements ActionListener {
|
|||||||
double[] output = new double[nPoints];
|
double[] output = new double[nPoints];
|
||||||
input[0] = 1;
|
input[0] = 1;
|
||||||
filter.runFilter(input, output);
|
filter.runFilter(input, output);
|
||||||
|
double maxOut = 0;
|
||||||
|
for (int i = 0; i < output.length; i++) {
|
||||||
|
maxOut = Math.max(maxOut, Math.abs(output[i]));
|
||||||
|
}
|
||||||
|
double[] scaleMaxes = {1, .5, .2, .1};
|
||||||
|
double scaleMax = 1.0;
|
||||||
|
for (int i = 1; i < scaleMaxes.length; i++) {
|
||||||
|
if (maxOut > scaleMaxes[i]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
scaleMax = scaleMaxes[i];
|
||||||
|
}
|
||||||
|
|
||||||
// can now plot that.
|
// can now plot that.
|
||||||
|
// what's the lenght of the plot in seconds ?
|
||||||
|
double tSecs = (nPoints-1)/sampleRate;
|
||||||
|
double tScale = 1;
|
||||||
|
String tUnit = "s";
|
||||||
|
if (tSecs < .1) {
|
||||||
|
tScale = 1000;
|
||||||
|
tUnit = "ms";
|
||||||
|
}
|
||||||
|
if (tSecs < 1e-4) {
|
||||||
|
tScale = 1e6;
|
||||||
|
tUnit = "\u00B5s";
|
||||||
|
}
|
||||||
|
|
||||||
Graphics2D g2d = (Graphics2D) g;
|
Graphics2D g2d = (Graphics2D) g;
|
||||||
|
|
||||||
g2d.setColor(PamColors.getInstance().getColor(PamColor.AXIS));
|
g2d.setColor(PamColors.getInstance().getColor(PamColor.AXIS));
|
||||||
|
int charWidth = g2d.getFontMetrics().charWidth('2');
|
||||||
|
|
||||||
Insets insets = getInsets();
|
Insets insets = getInsets();
|
||||||
Rectangle r = getBounds();
|
Rectangle r = getBounds();
|
||||||
|
int marginL = charWidth*3+6;
|
||||||
|
int marginT = 6;
|
||||||
|
int marginR = charWidth*2+3;
|
||||||
|
int x0 = marginL;
|
||||||
|
int y0 = getHeight()/2;
|
||||||
|
int y1 = getWidth()-marginR;
|
||||||
|
double yScale = getHeight()/2-marginT;
|
||||||
|
g.setColor(Color.BLACK);
|
||||||
|
g.drawLine(x0, getHeight()-marginT, x0, marginT);
|
||||||
|
PamAxis yAxis = new PamAxis(x0, getHeight()-marginT, x0, marginT, -1, 1, PamAxis.ABOVE_LEFT, "", PamAxis.LABEL_NEAR_CENTRE, "%3.1f");
|
||||||
|
yAxis.drawAxis(g);
|
||||||
|
g.drawLine(x0, y0, y1, y0);
|
||||||
|
PamAxis xAxis = new PamAxis(x0, y0, y1, y0, 0, tSecs*tScale, PamAxis.BELOW_RIGHT, tUnit, PamAxis.LABEL_NEAR_MAX, "%3.1f");
|
||||||
|
xAxis.drawAxis(g);
|
||||||
|
int lastX = -1;
|
||||||
|
int lastY = 0;
|
||||||
|
g.setColor(Color.GRAY);
|
||||||
|
for (int i = upsFactor; i < upsInput.length; i++) {
|
||||||
|
int x = (int) xAxis.getPosition((i-upsFactor)/sampleRate/upsFactor*tScale) + marginL;
|
||||||
|
int y = (int) yAxis.getPosition(upsOutput[i]) + marginT;
|
||||||
|
if (i > upsFactor) {
|
||||||
|
g2d.drawLine(lastX, lastY, x, y);
|
||||||
|
}
|
||||||
|
lastX = x;
|
||||||
|
lastY = y;
|
||||||
|
}
|
||||||
|
g.setColor(Color.RED);
|
||||||
|
for (int i = 0; i < input.length; i++) {
|
||||||
|
int x = (int) xAxis.getPosition(i/sampleRate*tScale) + marginL;
|
||||||
|
int y = (int) yAxis.getPosition(output[i]) + marginT;
|
||||||
|
if (i > 0) {
|
||||||
|
g2d.drawLine(lastX, lastY, x, y);
|
||||||
|
}
|
||||||
|
lastX = x;
|
||||||
|
lastY = y;
|
||||||
|
}
|
||||||
|
g.setColor(Color.BLACK);
|
||||||
|
String txt = "Impulse response";
|
||||||
|
cornerText(g, txt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cornerText(Graphics g, String txt) {
|
||||||
|
FontMetrics fm = g.getFontMetrics();
|
||||||
|
int w = fm.stringWidth(txt);
|
||||||
|
g.drawString(txt, getWidth()-w-fm.getMaxAdvance(), fm.getAscent()*3/2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawPole(Graphics g, Complex p, Point center, int radius) {
|
void drawPole(Graphics g, Complex p, Point center, int radius) {
|
||||||
|
@ -75,6 +75,10 @@ public class FilterParams implements Serializable, Cloneable, ManagedParameters
|
|||||||
public static final int SCALE_LOG = 0;
|
public static final int SCALE_LOG = 0;
|
||||||
public static final int SCALE_LIN = 1;
|
public static final int SCALE_LIN = 1;
|
||||||
|
|
||||||
|
public static final int PZPLOT_PZ = 0;
|
||||||
|
public static final int PZPLOT_IMPULSE = 1;
|
||||||
|
public static int pzPlotStyle = PZPLOT_IMPULSE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a filter parameter set with default params
|
* Construct a filter parameter set with default params
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user