Rw improvement (#16)

* Update .project

* RWE imporvement to peak detection and dealing with smoothing.

* Make improvements to MARW edge detector so that it doesn't merge
harmonics, by using a threshold down from the peak as well as up from
the noise
This commit is contained in:
Douglas Gillespie 2022-02-18 17:05:51 +00:00 committed by GitHub
parent 591d3157b6
commit e0c9abcc3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 85 additions and 25 deletions

View File

@ -6,8 +6,9 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>PamGuard Main</name>
<name>PamGuard Main DG</name>
<comment></comment>
<projects>
</projects>

View File

@ -264,7 +264,8 @@ public class StandardFileDate implements FileDate, PamSettings {
// System.out.println(d);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// e.printStackTrace();
System.out.println(e.getMessage());
} //throws ParseException if no match
setLastFormat(forcedDateFormat);
return d.getTime();

View File

@ -10,6 +10,7 @@ import javax.swing.JMenuItem;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import KernelSmoothing.KernelSmoothingProcess;
import PamController.PamControlledUnit;
import PamController.PamControlledUnitSettings;
import PamController.PamController;
@ -20,6 +21,8 @@ import PamUtils.PamUtils;
import PamView.GroupedDataSource;
import PamView.GroupedSourceParameters;
import PamView.dialog.GroupedSourcePanel;
import PamguardMVC.PamDataBlock;
import PamguardMVC.ProcessAnnotation;
/**
* Exact implementation of the 2003 Right Whale detector I developed when I was
@ -85,6 +88,19 @@ public class RWEControl extends PamControlledUnit implements PamSettings {
rweProcess.setupProcesses();
}
}
/**
* Check that the input process has implemented kernel smoothing.
* @param inputBlock input data block (should be fft data).
* @return true if kernel smoothing is in place.
*/
protected boolean hasKernelSmoothing(PamDataBlock inputBlock) {
if (inputBlock == null) {
return false;
}
ProcessAnnotation an = inputBlock.findAnnotation(KernelSmoothingProcess.processType, KernelSmoothingProcess.processName);
return an != null;
}
@Override

View File

@ -5,6 +5,7 @@ import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Window;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
@ -29,11 +30,15 @@ public class RWEDialog extends PamDialog {
private static RWEDialog singleInstance;
private SourcePanel sourcePanel;
private RWEControl rweControl;
private JTextField startFreq, endFreq, thresholdDB;
private JTextField minSoundType;
private JCheckBox downThreshold;
private RWEDialog(Window parentFrame) {
private RWEDialog(RWEControl rweControl, Window parentFrame) {
super(parentFrame, "Right Whale Edge Detector Settings", true);
this.rweControl = rweControl;
sourcePanel = new SourcePanel(this, "Source and Channels",
FFTDataUnit.class, true, true);
sourcePanel.setSourceToolTip("Data source should be the output of a Spectrogram Smmothing Kernel");
@ -67,6 +72,11 @@ public class RWEDialog extends PamDialog {
addComponent(det, thresholdDB = new JTextField(5), c);
c.gridx++;
addComponent(det, new JLabel(" dB", SwingConstants.RIGHT), c);
c.gridy++;
c.gridx = 0;
addComponent(det, new JLabel("Appy down threshold ", SwingConstants.RIGHT), c);
c.gridx++;
addComponent(det, downThreshold = new JCheckBox(), c);
JPanel cl = new JPanel(new GridBagLayout());
cl.setBorder(new TitledBorder("Detection"));
@ -85,6 +95,7 @@ public class RWEDialog extends PamDialog {
}
txt += "</html>";
minSoundType.setToolTipText(txt);
downThreshold.setToolTipText("Applies threshold as dB down from the peak, as well as up from the noise floor");
pp.add(BorderLayout.NORTH, det);
pp.add(BorderLayout.CENTER, cl);
@ -96,8 +107,8 @@ public class RWEDialog extends PamDialog {
}
public static RWEParameters showDialog(Window frame, RWEControl rweControl) {
if (singleInstance == null || frame != singleInstance.getOwner()) {
singleInstance = new RWEDialog(frame);
if (singleInstance == null || frame != singleInstance.getOwner() || rweControl != singleInstance.rweControl) {
singleInstance = new RWEDialog(rweControl, frame);
}
singleInstance.rweParameters = rweControl.rweParameters.clone();
singleInstance.setParams();
@ -113,6 +124,7 @@ public class RWEDialog extends PamDialog {
endFreq.setText(String.format("%3.1f", rweParameters.endFreq));
double thDB = 10. * Math.log10(rweParameters.threshold);
thresholdDB.setText(String.format("%3.1f", thDB));
downThreshold.setSelected(rweParameters.downThreshold);
minSoundType.setText(String.format("%d", rweParameters.minSoundType));
}
@ -120,6 +132,7 @@ public class RWEDialog extends PamDialog {
public boolean getParams() {
rweParameters.channelMap = sourcePanel.getChannelList();
rweParameters.dataSourceName = sourcePanel.getSource().getDataName();
rweParameters.downThreshold = downThreshold.isSelected();
if (rweParameters.dataSourceName == null) {
return showWarning("You must select a valid input data source");
}
@ -137,26 +150,13 @@ public class RWEDialog extends PamDialog {
catch (NumberFormatException e) {
return showWarning("Invalid detection or classification parameter");
}
boolean gok = checkInputProcessing();
if (gok == false) {
return showWarning("Right whale detector input must include Gaussian Kernel Smoothing as part of the FFT module, or a stand alone smoothing module");
}
// boolean gok = rweControl.hasKernelSmoothing(sourcePanel.getSource());
// if (gok == false) {
// return showWarning("Right whale detector input must include Gaussian Kernel Smoothing as part of the FFT module, or a stand alone smoothing module");
// }
return true;
}
/**
* Check that the input process has implemented kernel smoothing.
* @return
*/
private boolean checkInputProcessing() {
PamDataBlock db = sourcePanel.getSource();
if (db == null) {
return false;
}
ProcessAnnotation an = db.findAnnotation(KernelSmoothingProcess.processType, KernelSmoothingProcess.processName);
return an != null;
}
@Override
public void cancelButtonPressed() {
rweParameters = null;

View File

@ -27,6 +27,8 @@ public class RWEParameters implements Serializable, Cloneable, ManagedParameters
public int minSoundType = 5;
public boolean downThreshold = false;
@Override
protected RWEParameters clone() {
try {

View File

@ -16,6 +16,7 @@ import fftManager.Complex;
import fftManager.FFTDataBlock;
import fftManager.FFTDataUnit;
import networkTransfer.receive.BuoyStatusDataUnit;
import spectrogramNoiseReduction.kernelSmoothing.KernelSmoothing;
import whistlesAndMoans.WhistleBearingInfo;
import PamController.PamController;
import PamDetection.AbstractLocalisation;
@ -43,6 +44,11 @@ public class RWEProcess extends PamProcess {
private Hashtable<Integer, BearingLocaliser> bearingLocalisers;
private StandardSymbolManager symbolManager;
/**
* Already has Kernel smoothing applied to input data.
*/
private boolean isPreSmoothed;
private KernelSmoothing kernelSmoothing;
public RWEProcess(RWEControl rweControl) {
super(rweControl, null);
@ -96,6 +102,18 @@ public class RWEProcess extends PamProcess {
if (sourceDataBlock == null) {
return;
}
/**
* work out if the fft source has already run the Guassian smoothing or not
*/
isPreSmoothed = rweControl.hasKernelSmoothing(sourceDataBlock);
if (isPreSmoothed) {
kernelSmoothing = null;
}
else {
kernelSmoothing = new KernelSmoothing();
kernelSmoothing.initialise(sourceDataBlock.getChannelMap());
}
// sourceDataBlock.findAnnotation(null);
// rweDataBlock.setChannelMap(rweControl.rweParameters.channelMap);
rweDataBlock.sortOutputMaps(sourceDataBlock.getChannelMap(), sourceDataBlock.getSequenceMapObject(), rweControl.rweParameters.channelMap);
if (db == null) {
@ -135,6 +153,7 @@ public class RWEProcess extends PamProcess {
private int numOT; // number of bins in last analysed slice over threshold
private int minSoundType;
private RWClassifier classifier = new RWStandardClassifier();
public RWEChannelProcess(RWEProcess rweProcess, int iChannel) {
this.rweProcess = rweProcess;
this.iChannel = iChannel;
@ -160,6 +179,15 @@ public class RWEProcess extends PamProcess {
public void newData(FFTDataUnit fftDataUnit) {
if (!isPreSmoothed) {
FFTDataUnit newFFTUnit = new FFTDataUnit(fftDataUnit.getTimeMilliseconds(), fftDataUnit.getChannelBitmap(),
fftDataUnit.getStartSample(), fftDataUnit.getSampleDuration(), null, fftDataUnit.getFftSlice());
newFFTUnit.setSequenceBitmap(fftDataUnit.getSequenceBitmapObject());
newFFTUnit.setFftData(fftDataUnit.getFftData().clone());
kernelSmoothing.runNoiseReduction(newFFTUnit);
fftDataUnit = newFFTUnit;
}
RWEDetectionPeak[] newPeaks = findPeaks(fftDataUnit.getFftData());
RWESound[] newSounds = findSounds(fftDataUnit.getTimeMilliseconds(), newPeaks);
if (newSounds == null) {
@ -197,6 +225,7 @@ public class RWEProcess extends PamProcess {
RWEDetectionPeak[] detectedPeaks = null;
int nPeaks = 0;
int nOver = 0;
double onDown = rweControl.rweParameters.downThreshold ? 1 : 0;
for (int i = searchBin1; i <= searchBin2; i++) {
magData[i] = complexArray.magsq(i);
}
@ -239,7 +268,8 @@ public class RWEProcess extends PamProcess {
// do nothing it it's still off !
}
else {
if (oTh[i]) { // continue peak
// if downThreshold == false then onDown is 0, so second threshold is always on since magData always > 0
if (oTh[i] && magData[i] > newPeak.maxAmp*onDown/threshold) { // continue peak
newPeak.bin2 = i;
if (magData[i] > newPeak.maxAmp) {
newPeak.maxAmp = magData[i];
@ -258,6 +288,16 @@ public class RWEProcess extends PamProcess {
detectedPeaks[nPeaks++] = newPeak;
newPeak = new RWEDetectionPeak(0);
peakOn = false;
// now trim off the start of the peak if it's too wide.
if (onDown > 0) {
for (int ip = newPeak.bin1; ip < newPeak.peakBin; ip++) {
if (magData[ip] < newPeak.maxAmp/threshold) {
newPeak.bin1 = ip+1;
newPeak.signal -= magData[ip];
newPeak.noise -= backgroundData[ip];
}
}
}
}
}
}

View File

@ -91,7 +91,7 @@ public class BinaryStorageDialogPanel {
JPanel qb = new JPanel(new BorderLayout());
qb.add(BorderLayout.WEST, q);
qb.setBorder(new TitledBorder("Options"));
qb.setVisible(PamController.getInstance().getRunMode() != PamController.RUN_PAMVIEW);
// qb.setVisible(PamController.getInstance().getRunMode() != PamController.RUN_PAMVIEW);
p.add(BorderLayout.CENTER, qb);