mirror of
https://github.com/PAMGuard/PAMGuard.git
synced 2024-11-25 00:22:27 +00:00
Data selector for whistle classifier
Added standard data selection options to whistle classifier output, and also made it a 'Detector' type for down stream data connections
This commit is contained in:
parent
368fcbfc61
commit
425dd21d9f
@ -2000,6 +2000,10 @@ public abstract class SQLLogging {
|
||||
}
|
||||
PamSubtableData subtableData = new PamSubtableData();
|
||||
long utc = SQLTypes.millisFromTimeStamp(subtableTableDef.getTimeStampItem().getValue());
|
||||
if (utc % 1000 == 0) {
|
||||
int millis = subtableTableDef.getTimeStampMillis().getIntegerValue();
|
||||
utc += millis;
|
||||
}
|
||||
subtableData.setChildUTC(utc);
|
||||
subtableData.setParentID(subtableTableDef.getParentID().getIntegerValue());
|
||||
subtableData.setParentUID(subtableTableDef.getParentUID().getLongValue());
|
||||
|
@ -351,15 +351,13 @@ public class SQLTypes {
|
||||
* goes to the default, so it needs to be on UTC at the moment data are written to the database, not
|
||||
* just in this function.
|
||||
*/
|
||||
// return timeMillis;
|
||||
if (timeMillis == null) {
|
||||
return null;
|
||||
}
|
||||
// TimeZone tz = TimeZone.getDefault();
|
||||
// TimeZone.setDefault(PamCalendar.defaultTimeZone);
|
||||
// Timestamp ts = new Timestamp(timeMillis - tz.getOffset(timeMillis));
|
||||
Timestamp ts = new Timestamp(timeMillis);
|
||||
// TimeZone.setDefault(tz);
|
||||
// Timestamp newTS = ts.toLocalDateTime();
|
||||
// return PamCalendar.formatDBDateTime(timeMillis, false);
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
Timestamp ts = new UTCTimestamp(timeMillis - tz.getOffset(timeMillis));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
30
src/generalDatabase/UTCTimestamp.java
Normal file
30
src/generalDatabase/UTCTimestamp.java
Normal file
@ -0,0 +1,30 @@
|
||||
package generalDatabase;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Override standard Timestamp class and stop it making UTC corrections as it writes to database
|
||||
* @author dg50
|
||||
*
|
||||
*/
|
||||
public class UTCTimestamp extends Timestamp {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UTCTimestamp(long time) {
|
||||
super(time);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTime() {
|
||||
return super.getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime toLocalDateTime() {
|
||||
return super.toLocalDateTime();
|
||||
}
|
||||
|
||||
}
|
@ -44,6 +44,31 @@ public class SqliteSQLTypes extends SQLTypes {
|
||||
return super.systemSqlType(sqlType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTimeStamp(Long timeMillis) {
|
||||
/**
|
||||
* This has just got nasty WRT time zones.
|
||||
* When the TimeStamp is written to database it uses the default time zone correction, which of course
|
||||
* I don't want since I only do UTC. I was therefore subtracting this off before creating the ts
|
||||
* so that it all worked fine when it was added back on again.
|
||||
* This was fine for many years until someone processed data from exactly when the clocks went
|
||||
* forward in the spring. Because the data were just after the clocks going forward, it took off
|
||||
* an hour, then failed to add it back on again since the time was now before daylight saving.
|
||||
* Amazed this has never happened before. Well done G and E ! I can fix it by setting the
|
||||
* default time zone to UTC when PAMGuard starts, but note that all future references to local time
|
||||
* will then be UTC. If I try to change it temporarily it doesn't help since the Timestamp always
|
||||
* goes to the default, so it needs to be on UTC at the moment data are written to the database, not
|
||||
* just in this function.
|
||||
*
|
||||
* Seems that for SQLite we can get away with a string, for MySQL we need a TimeStamp object still
|
||||
*/
|
||||
// return timeMillis;
|
||||
if (timeMillis == null) {
|
||||
return null;
|
||||
}
|
||||
return PamCalendar.formatDBDateTime(timeMillis, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatDBDateTimeQueryString(long timeMilliseconds) {
|
||||
switch (dateClass) {
|
||||
|
@ -135,7 +135,7 @@ public class Pamguard {
|
||||
Thread folderSizeThread = new Thread(folderSizeMon);
|
||||
folderSizeThread.start();
|
||||
|
||||
TimeZone.setDefault(PamCalendar.defaultTimeZone);
|
||||
// TimeZone.setDefault(PamCalendar.defaultTimeZone);
|
||||
|
||||
System.out.println("**********************************************************");
|
||||
try {
|
||||
|
@ -2,12 +2,25 @@ package whistleClassifier;
|
||||
|
||||
import PamguardMVC.PamDataBlock;
|
||||
import PamguardMVC.PamProcess;
|
||||
import PamguardMVC.dataSelector.DataSelectorCreator;
|
||||
import whistleClassifier.dataselect.WslClsDataSelectCreator;
|
||||
|
||||
public class WhistleClasificationDataBlock extends PamDataBlock<WhistleClassificationDataUnit> {
|
||||
|
||||
public WhistleClasificationDataBlock(PamProcess parentProcess, int channelMap) {
|
||||
super(WhistleClassificationDataUnit.class, "Whistle Classification", parentProcess, channelMap);
|
||||
private WslClsDataSelectCreator dataSelectCreator;
|
||||
private WhistleClassifierControl wslClassifierControl;
|
||||
|
||||
public WhistleClasificationDataBlock(WhistleClassifierControl wslClassifierControl, PamProcess parentProcess, int channelMap) {
|
||||
super(WhistleClassificationDataUnit.class, "Whistle Classification", parentProcess, channelMap);
|
||||
this.wslClassifierControl = wslClassifierControl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSelectorCreator getDataSelectCreator() {
|
||||
if (dataSelectCreator == null) {
|
||||
dataSelectCreator = new WslClsDataSelectCreator(wslClassifierControl, this);
|
||||
}
|
||||
return dataSelectCreator;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package whistleClassifier;
|
||||
|
||||
import PamDetection.PamDetection;
|
||||
import PamguardMVC.AcousticDataUnit;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
|
||||
public class WhistleClassificationDataUnit extends PamDataUnit<PamDataUnit,PamDataUnit> implements AcousticDataUnit {
|
||||
public class WhistleClassificationDataUnit extends PamDataUnit<PamDataUnit,PamDataUnit> implements AcousticDataUnit, PamDetection {
|
||||
|
||||
private double[] speciesLogLikelihoods;
|
||||
|
||||
|
@ -65,7 +65,7 @@ public class WhistleClassifierProcess extends PamProcess {
|
||||
|
||||
this.whistleClassifierControl = whistleClassifierControl;
|
||||
|
||||
whistleClasificationDataBlock = new WhistleClasificationDataBlock(this, 3);
|
||||
whistleClasificationDataBlock = new WhistleClasificationDataBlock(whistleClassifierControl, this, 3);
|
||||
|
||||
addOutputDataBlock(whistleClasificationDataBlock);
|
||||
|
||||
|
35
src/whistleClassifier/dataselect/SppClsSelectParams.java
Normal file
35
src/whistleClassifier/dataselect/SppClsSelectParams.java
Normal file
@ -0,0 +1,35 @@
|
||||
package whistleClassifier.dataselect;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Data selector params for a single species.
|
||||
* @author dg50
|
||||
*
|
||||
*/
|
||||
public class SppClsSelectParams implements Serializable, Cloneable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public String name;
|
||||
public boolean selected;
|
||||
public double minScore;
|
||||
|
||||
public SppClsSelectParams(String name, boolean selected, double minScore) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.selected = selected;
|
||||
this.minScore = minScore;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SppClsSelectParams clone() {
|
||||
try {
|
||||
return (SppClsSelectParams) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package whistleClassifier.dataselect;
|
||||
|
||||
import PamguardMVC.PamDataBlock;
|
||||
import PamguardMVC.dataSelector.DataSelectParams;
|
||||
import PamguardMVC.dataSelector.DataSelector;
|
||||
import PamguardMVC.dataSelector.DataSelectorCreator;
|
||||
import whistleClassifier.WhistleClasificationDataBlock;
|
||||
import whistleClassifier.WhistleClassifierControl;
|
||||
|
||||
public class WslClsDataSelectCreator extends DataSelectorCreator {
|
||||
|
||||
private WhistleClassifierControl wslClassifierControl;
|
||||
private WhistleClasificationDataBlock wslClassifierDataBlock;
|
||||
|
||||
public WslClsDataSelectCreator(WhistleClassifierControl wslClassifierControl, WhistleClasificationDataBlock pamDataBlock) {
|
||||
super(pamDataBlock);
|
||||
this.wslClassifierControl = wslClassifierControl;
|
||||
this.wslClassifierDataBlock = pamDataBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSelector createDataSelector(String selectorName, boolean allowScores, String selectorType) {
|
||||
return new WslClsDataSelector(wslClassifierControl, wslClassifierDataBlock, selectorName, allowScores);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSelectParams createNewParams(String name) {
|
||||
return new WslClsSelectorParams();
|
||||
}
|
||||
|
||||
}
|
70
src/whistleClassifier/dataselect/WslClsDataSelector.java
Normal file
70
src/whistleClassifier/dataselect/WslClsDataSelector.java
Normal file
@ -0,0 +1,70 @@
|
||||
package whistleClassifier.dataselect;
|
||||
|
||||
import PamView.dialog.PamDialogPanel;
|
||||
import PamguardMVC.PamDataBlock;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import PamguardMVC.dataSelector.DataSelectParams;
|
||||
import PamguardMVC.dataSelector.DataSelector;
|
||||
import pamViewFX.fxSettingsPanes.DynamicSettingsPane;
|
||||
import whistleClassifier.WhistleClassificationDataUnit;
|
||||
import whistleClassifier.WhistleClassifierControl;
|
||||
|
||||
/**
|
||||
* Species selector for whistle classifier. Currently only does yes / no, will
|
||||
* maybe one day be extended to allow scores as well.
|
||||
* @author dg50
|
||||
*
|
||||
*/
|
||||
public class WslClsDataSelector extends DataSelector {
|
||||
|
||||
private WhistleClassifierControl wslClassifierControl;
|
||||
|
||||
private WslClsSelectorParams wcsParams = new WslClsSelectorParams();
|
||||
|
||||
public WslClsDataSelector(WhistleClassifierControl wslClassifierControl, PamDataBlock pamDataBlock, String selectorName, boolean allowScores) {
|
||||
super(pamDataBlock, selectorName, allowScores);
|
||||
this.wslClassifierControl = wslClassifierControl;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setParams(DataSelectParams dataSelectParams) {
|
||||
if (dataSelectParams instanceof WslClsSelectorParams) {
|
||||
wcsParams = (WslClsSelectorParams) dataSelectParams;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WslClsSelectorParams getParams() {
|
||||
return wcsParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PamDialogPanel getDialogPanel() {
|
||||
return new WslClsDialogPanel(wslClassifierControl, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicSettingsPane<Boolean> getDialogPaneFX() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double scoreData(PamDataUnit pamDataUnit) {
|
||||
WhistleClassificationDataUnit wcdu = (WhistleClassificationDataUnit) pamDataUnit;
|
||||
String species = wcdu.getSpecies();
|
||||
// score = wcdu.get
|
||||
SppClsSelectParams sppParams = wcsParams.getSppParams(species);
|
||||
// if ()
|
||||
// if (sppParams.selected == false) {
|
||||
// return 0;
|
||||
// }
|
||||
// if (isAllowScores()) {
|
||||
// return sppP
|
||||
// }
|
||||
// wslClassifierControl.getWhistleClassificationParameters().
|
||||
return sppParams.selected ? 1 : 0;
|
||||
}
|
||||
|
||||
}
|
132
src/whistleClassifier/dataselect/WslClsDialogPanel.java
Normal file
132
src/whistleClassifier/dataselect/WslClsDialogPanel.java
Normal file
@ -0,0 +1,132 @@
|
||||
package whistleClassifier.dataselect;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.border.TitledBorder;
|
||||
|
||||
import PamView.dialog.PamDialog;
|
||||
import PamView.dialog.PamDialogPanel;
|
||||
import PamView.dialog.PamGridBagContraints;
|
||||
import PamguardMVC.dataSelector.DataSelectParams;
|
||||
import whistleClassifier.FragmentClassifierParams;
|
||||
import whistleClassifier.WhistleClassificationParameters;
|
||||
import whistleClassifier.WhistleClassifierControl;
|
||||
|
||||
/**
|
||||
* dialog for whistle classifier data selector
|
||||
* @author dg50
|
||||
*
|
||||
*/
|
||||
public class WslClsDialogPanel implements PamDialogPanel {
|
||||
|
||||
private WhistleClassifierControl wslClassifierControl;
|
||||
private WslClsDataSelector wslClsDataSelector;
|
||||
|
||||
private JPanel mainPanel;
|
||||
|
||||
private JPanel sppPanel;
|
||||
|
||||
private JCheckBox[] speciesBoxes;
|
||||
|
||||
private JTextField[] speciesScores;
|
||||
|
||||
public WslClsDialogPanel(WhistleClassifierControl wslClassifierControl, WslClsDataSelector wslClsDataSelector) {
|
||||
this.wslClassifierControl = wslClassifierControl;
|
||||
this.wslClsDataSelector = wslClsDataSelector;
|
||||
|
||||
this.mainPanel = new JPanel(new BorderLayout());
|
||||
mainPanel.setBorder(new TitledBorder("Select species"));
|
||||
|
||||
sppPanel = new JPanel(new GridBagLayout());
|
||||
mainPanel.add(BorderLayout.CENTER, sppPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getDialogComponent() {
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParams() {
|
||||
WhistleClassificationParameters wslParams = wslClassifierControl.getWhistleClassificationParameters();
|
||||
WslClsSelectorParams selParams = wslClsDataSelector.getParams();
|
||||
if (wslParams == null) {
|
||||
return;
|
||||
}
|
||||
FragmentClassifierParams fragParams = wslParams.fragmentClassifierParams;
|
||||
if (fragParams == null) {
|
||||
return;
|
||||
}
|
||||
fillSppPanel(wslParams, selParams);
|
||||
}
|
||||
|
||||
private void fillSppPanel(WhistleClassificationParameters wslParams, WslClsSelectorParams selParams) {
|
||||
boolean allowScores = wslClsDataSelector.isAllowScores();
|
||||
sppPanel.removeAll();
|
||||
String[] sppList = wslParams.fragmentClassifierParams.getSpeciesList();
|
||||
if (sppList == null) {
|
||||
return;
|
||||
}
|
||||
int nSpp = sppList.length;
|
||||
speciesBoxes = new JCheckBox[nSpp];
|
||||
speciesScores = new JTextField[nSpp];
|
||||
GridBagConstraints c = new PamGridBagContraints();
|
||||
sppPanel.add(new JLabel("Species", JLabel.CENTER), c);
|
||||
if (allowScores) {
|
||||
c.gridx++;
|
||||
JLabel lab = new JLabel(" Min score ", JLabel.CENTER);
|
||||
lab.setToolTipText("Minimum classification score (between 0 and 1)");
|
||||
sppPanel.add(lab , c);
|
||||
}
|
||||
for (int i = 0; i < nSpp; i++) {
|
||||
speciesBoxes[i] = new JCheckBox(sppList[i]);
|
||||
speciesScores[i] = new JTextField(3);
|
||||
c.gridx = 0;
|
||||
c.gridy++;
|
||||
sppPanel.add(speciesBoxes[i], c);
|
||||
if (allowScores) {
|
||||
c.gridx++;
|
||||
sppPanel.add(speciesScores[i], c);
|
||||
}
|
||||
SppClsSelectParams sppSel = selParams.getSppParams(sppList[i]);
|
||||
speciesBoxes[i].setSelected(sppSel.selected);
|
||||
speciesScores[i].setText(String.format("%3.2f", sppSel.minScore));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getParams() {
|
||||
WslClsSelectorParams selParams = wslClsDataSelector.getParams();
|
||||
boolean allowScores = wslClsDataSelector.isAllowScores();
|
||||
if (speciesBoxes == null) {
|
||||
return false;
|
||||
}
|
||||
int nSpp = speciesBoxes.length;
|
||||
for (int i = 0; i < nSpp; i++) {
|
||||
String name = speciesBoxes[i].getText();
|
||||
boolean sel = speciesBoxes[i].isSelected();
|
||||
double score = 0;
|
||||
if (allowScores) {
|
||||
try {
|
||||
score = Double.valueOf(speciesScores[i].getText());
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
score = -1;
|
||||
}
|
||||
}
|
||||
if (score < 0 || score > 1) {
|
||||
return PamDialog.showWarning(null, "Invalid score value for " + name, "Score values must be betwween 0 and 1");
|
||||
}
|
||||
selParams.setSppParams(name, new SppClsSelectParams(name, sel, score));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
46
src/whistleClassifier/dataselect/WslClsSelectorParams.java
Normal file
46
src/whistleClassifier/dataselect/WslClsSelectorParams.java
Normal file
@ -0,0 +1,46 @@
|
||||
package whistleClassifier.dataselect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
|
||||
import PamguardMVC.dataSelector.DataSelectParams;
|
||||
|
||||
public class WslClsSelectorParams extends DataSelectParams implements Cloneable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private HashMap<String, SppClsSelectParams> sppParamsTable = new HashMap<>();
|
||||
|
||||
public WslClsSelectorParams() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public WslClsSelectorParams clone() {
|
||||
try {
|
||||
return (WslClsSelectorParams) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSppParams(String sppName, SppClsSelectParams params) {
|
||||
if (sppParamsTable == null) {
|
||||
sppParamsTable = new HashMap<String, SppClsSelectParams>();
|
||||
}
|
||||
sppParamsTable.put(sppName, params);
|
||||
}
|
||||
|
||||
public SppClsSelectParams getSppParams(String sppName) {
|
||||
if (sppParamsTable == null) {
|
||||
sppParamsTable = new HashMap<String, SppClsSelectParams>();
|
||||
}
|
||||
SppClsSelectParams sppParams = sppParamsTable.get(sppName);
|
||||
if (sppParams == null) {
|
||||
sppParams = new SppClsSelectParams(sppName, false, 0);
|
||||
}
|
||||
return sppParams;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user