mirror of
https://github.com/PAMGuard/PAMGuard.git
synced 2024-11-25 08:32:32 +00:00
Merge pull request #7 from macster110/main
Matched click classifier bug fixes and TDDisplayFX real time changes
This commit is contained in:
commit
59e5735d4d
@ -184,15 +184,21 @@ public class TDAcousticScroller extends AcousticScrollerFX implements PamSetting
|
||||
|
||||
//add a listener so the visible amount changes of the spinner changes value.
|
||||
spinner.valueProperty().addListener((obsVal, oldVal, newVal)->{
|
||||
if (spinnerCall) return ; //prevent overflow.
|
||||
if (newVal<=this.getRangeMillis()) {
|
||||
// Debug.out.println("TDAcousticScroller: TimeRangeSpinner: " + newVal);
|
||||
Platform.runLater(()->{ //why? But seems necessary
|
||||
super.setVisibleMillis(newVal);
|
||||
});
|
||||
}
|
||||
else spinner.getValueFactory().decrement(1); //need to use decrement here instead of set time because otherwise arrow buttons
|
||||
//don't work.
|
||||
if (spinnerCall) return ; //prevent overflow
|
||||
|
||||
/**
|
||||
* There are two slightly different modes here- in viewer mode we want the spinner to set
|
||||
* only the visible range. However in real time mode we want it to set the visible time and
|
||||
* the data keep time.
|
||||
*/
|
||||
if (newVal<=this.getRangeMillis() || !isViewer) {
|
||||
// Debug.out.println("TDAcousticScroller: TimeRangeSpinner: " + newVal);
|
||||
Platform.runLater(()->{ //why? But seems necessary
|
||||
super.setVisibleMillis(newVal);
|
||||
super.setRangeMillis(0, newVal, false);
|
||||
});
|
||||
}
|
||||
else spinner.getValueFactory().decrement(1); //need to use decrement here instead of set time because otherwise arrow buttons
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,14 @@ import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.jamdev.jpamutils.wavFiles.WavInterpolator;
|
||||
|
||||
import com.jmatio.types.MLArray;
|
||||
import com.jmatio.types.MLDouble;
|
||||
import com.jmatio.types.MLStructure;
|
||||
|
||||
import Filters.SmoothingFilter;
|
||||
import Localiser.DelayMeasurementParams;
|
||||
import PamModel.parametermanager.ManagedParameters;
|
||||
import PamModel.parametermanager.PamParameterSet;
|
||||
import PamModel.parametermanager.PrivatePamParameterData;
|
||||
@ -87,6 +89,21 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
|
||||
public final static int TEST_FFT_LENGTH=300;
|
||||
|
||||
/**
|
||||
* Decimates waveforms.
|
||||
*/
|
||||
transient private WavInterpolator wavInterpolator = new WavInterpolator();
|
||||
|
||||
// /**
|
||||
// * The delay measurment parameters.
|
||||
// */
|
||||
// private transient DelayMeasurementParams delayMeasurementParams = defualtDelayParams();
|
||||
//
|
||||
// /**
|
||||
// * Runs the cross correlation algorithm.
|
||||
// */
|
||||
// private transient Correlations correlations = new Correlations();
|
||||
|
||||
/**
|
||||
* Default MT classifier
|
||||
*/
|
||||
@ -94,6 +111,14 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
fft= new FastFFT();
|
||||
}
|
||||
|
||||
private DelayMeasurementParams defualtDelayParams() {
|
||||
DelayMeasurementParams delayMeasurementParams = new DelayMeasurementParams();
|
||||
//delayMeasurementParams.setUpSample(4);
|
||||
delayMeasurementParams.setFftFilterParams(null);
|
||||
|
||||
return delayMeasurementParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the match waveform FFT for the sampleRate.
|
||||
* @param fftLength - the FFTlength to use. Bins around waveform peak are used.
|
||||
@ -103,9 +128,14 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
if (waveformMatchFFT==null || currentSr!=sR) {
|
||||
if (fft==null) fft=new FastFFT();
|
||||
|
||||
|
||||
//System.out.println("interpWaveform: " + waveformMatch.waveform.length + " sR " + waveformMatch.sR);
|
||||
|
||||
//re-sample the waveform if the sample rate is different
|
||||
this.interpWaveformMatch=interpWaveform(this.waveformMatch, sR);
|
||||
|
||||
//System.out.println("interpWaveformMatch: " + interpWaveformMatch.length + " sR " + sR);
|
||||
|
||||
//normalise
|
||||
//this.interpWaveformMatch=PamArrayUtils.normalise(interpWaveformMatch);
|
||||
|
||||
@ -115,9 +145,11 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
// System.out.println("MatchNorm: MATCH");
|
||||
// MTClassifierTest.normalizeTest(interpWaveformMatch);
|
||||
|
||||
//here use the FFT length with the maximum template size.
|
||||
waveformMatchFFT = fft.rfft(PamArrayUtils.flip(interpWaveformMatch),
|
||||
length);
|
||||
waveformMatchFFT = fft.rfft(interpWaveformMatch, length);
|
||||
|
||||
//need to calculate the complex conjugate - note that originally I was flipping the array but this means
|
||||
//the max value does not equal one with identical waveforms...doh.
|
||||
waveformMatchFFT = waveformMatchFFT.conj();
|
||||
// System.out.println("waveformMatch: " + waveformMatch.waveform.length +
|
||||
// " interpWaveformMatch: " + interpWaveformMatch.length + " for " +sR + " sr ");
|
||||
|
||||
@ -155,9 +187,11 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
// MTClassifierTest.printWaveform(inteprWaveformReject);
|
||||
|
||||
//System.out.println("waveformReject: " +inteprWaveformReject.length + " fftLength: " + getFFTLength(sR));
|
||||
waveformRejectFFT = fft.rfft(inteprWaveformReject, length);
|
||||
|
||||
//must flip the waveform for cross correlation - might as well do this here.
|
||||
waveformRejectFFT = fft.rfft(PamArrayUtils.flip(inteprWaveformReject), length);
|
||||
//need to calculate the complex conjugate - note that originally I was flipping the array but this means
|
||||
//the max value does not equal one with identical waveforms...doh.
|
||||
waveformRejectFFT = waveformRejectFFT.conj();
|
||||
}
|
||||
return waveformRejectFFT;
|
||||
}
|
||||
@ -342,11 +376,9 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
//set the stored sR
|
||||
currentSr=sR;
|
||||
|
||||
// System.out.println("Matched click classifier: Waveform click: " + click.length());
|
||||
// System.out.println("Matched click classifier: Waveform click: " + click.length());
|
||||
//System.out.println("Waveform click: len: " + click.length());
|
||||
|
||||
// System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject));
|
||||
// System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject));
|
||||
//System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject)+ " len " + interpWaveformMatch.length);
|
||||
|
||||
//int fftLength = getFFTLength(sR);
|
||||
//int fftLength = this.getFFTLength(sR);
|
||||
@ -362,14 +394,17 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
int fftLength = click.length()*2;
|
||||
|
||||
ComplexArray matchResult= new ComplexArray(fftLength);
|
||||
ComplexArray matchTemplate = getWaveformMatchFFT(sR,fftLength);
|
||||
//System.out.println("matchTemplate: Waveform click: " + matchTemplate.length());
|
||||
ComplexArray matchTemplate = getWaveformMatchFFT(sR,fftLength); //remember this is the complex conjugate
|
||||
|
||||
//System.out.println("matchTemplate interp: len: " + interpWaveformMatch.length+ " max: " + PamArrayUtils.max(interpWaveformMatch));
|
||||
//System.out.println("matchTemplate: len: " + waveformMatch.waveform.length+ " max: " + PamArrayUtils.max(waveformMatch.waveform));
|
||||
|
||||
for (int i=0; i<Math.min(matchTemplate.length(), click.length()); i++) {
|
||||
matchResult.set(i, click.get(i).times(matchTemplate.get(i)));
|
||||
}
|
||||
|
||||
ComplexArray rejectResult= new ComplexArray(fftLength);
|
||||
ComplexArray rejectTemplate = getWaveformRejectFFT(sR, fftLength);
|
||||
ComplexArray rejectTemplate = getWaveformRejectFFT(sR, fftLength); //remember this is the complex conjugate
|
||||
for (int i=0; i<Math.min(rejectTemplate.length(), click.length()); i++) {
|
||||
rejectResult.set(i, click.get(i).times(rejectTemplate.get(i)));
|
||||
}
|
||||
@ -378,6 +413,9 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
// System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject));
|
||||
|
||||
//System.out.println("Click input: " + click.length() + " click template: " + matchTemplate.length());
|
||||
|
||||
|
||||
|
||||
|
||||
//must use scaling to get the same result as MATLAB
|
||||
if (fft==null) fft= new FastFFT();
|
||||
@ -387,13 +425,13 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
//System.out.println("Inverse MATCH RESULTS");
|
||||
|
||||
//need to take the real part of the result and multiply by 2 to get same as
|
||||
//ifft function in MATLAB
|
||||
//ifft function in MATLAB - dunno why this is...
|
||||
double[] matchReal = new double[matchResult.length()];
|
||||
double[] rejectReal = new double[rejectResult.length()];
|
||||
|
||||
for (int i=0; i<matchResult.length(); i++) {
|
||||
matchReal[i]=matchResult.getReal(i);
|
||||
rejectReal[i]=rejectResult.getReal(i);
|
||||
matchReal[i]=2*matchResult.getReal(i);
|
||||
rejectReal[i]=2*rejectResult.getReal(i);
|
||||
//System.out.println("iFFt match result: " + matchResult.get(i) + " iFFT rejectResult: " + rejectResult.get(i) );
|
||||
}
|
||||
|
||||
@ -407,6 +445,14 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
double maxmatch=PamArrayUtils.max(matchReal);
|
||||
double maxreject=PamArrayUtils.max(rejectReal);
|
||||
|
||||
|
||||
// //TEST
|
||||
// if (correlations==null) correlations=new Correlations();
|
||||
// TimeDelayData matchResultTD = correlations.getDelay(click, matchTemplate.conj(), null, sR, fftLength);
|
||||
// System.out.println("Old xcorr method: " + maxmatch + " new PG method: " + matchResultTD.getDelayScore());
|
||||
|
||||
// //TEST
|
||||
|
||||
//if set to "none" then reject template will return a NaN - TODO bit messy and inefficient.
|
||||
double result;
|
||||
double maxReject = PamArrayUtils.max(rejectReal);
|
||||
@ -434,9 +480,25 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
|
||||
*/
|
||||
private double[] interpWaveform(MatchTemplate waveformMatch, double sR) {
|
||||
//System.out.println("Interp waveform: " + " old: " + waveformMatch.sR + " new: " + sR);
|
||||
|
||||
if ( waveformMatch.sR>sR) {
|
||||
//up sample
|
||||
double[] interpWaveformMatch=reSampleWaveform(waveformMatch.waveform, waveformMatch.sR, sR);
|
||||
//System.out.println("RESULT: old len: " + waveformMatch.waveform.length + " new len: " +interpWaveformMatch.length);
|
||||
return interpWaveformMatch;
|
||||
}
|
||||
else if (waveformMatch.sR<sR){
|
||||
// //TODO - make a better decimator?
|
||||
// double[] interpWaveformMatch=reSampleWaveform(waveformMatch.waveform, waveformMatch.sR, sR);
|
||||
// return interpWaveformMatch;
|
||||
if (wavInterpolator == null) wavInterpolator = new WavInterpolator();
|
||||
return wavInterpolator.decimate(waveformMatch.waveform, waveformMatch.sR, (float) sR);
|
||||
}
|
||||
else {
|
||||
//nothing needed/
|
||||
return waveformMatch.waveform;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,19 +72,32 @@ public class MTClassifierTest {
|
||||
return struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the correlation of several templates
|
||||
* @param testWaveform - the waveform to correlate against.
|
||||
* @param sR - the sample rate of the waveform.
|
||||
* @param templates - the match templates to test.
|
||||
*/
|
||||
private static void testCorrelation(double[] testWaveform, float sR, ArrayList<MatchTemplate> templates) {
|
||||
testCorrelation(testWaveform, sR, templates, MatchedTemplateParams.NORMALIZATION_RMS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test the correlation of several templates
|
||||
* @param testWaveform
|
||||
* @param sR
|
||||
* @param templates
|
||||
* @return
|
||||
* @param testWaveform - the waveform to correlate against.
|
||||
* @param sR - the sample rate of the waveform.
|
||||
* @param templates - the match templates to test.
|
||||
* @param normalisation - the normalisation type to use e.g. MatchedTemplateParams.NORMALIZATION_RMS
|
||||
*/
|
||||
private static void testCorrelation(double[] testWaveform, float sR, ArrayList<MatchTemplate> templates) {
|
||||
private static void testCorrelation(double[] testWaveform, float sR, ArrayList<MatchTemplate> templates, int normalisation) {
|
||||
|
||||
//create the classifier object
|
||||
for (int i=0; i<templates.size(); i++){
|
||||
MTClassifier mtclassifier = new MTClassifier();
|
||||
mtclassifier.normalisation = normalisation;
|
||||
|
||||
//System.out.println("Template " + i + " " + templates.get(i));
|
||||
//add templates if inpout
|
||||
@ -97,8 +110,14 @@ public class MTClassifierTest {
|
||||
|
||||
//System.out.println("Waveform len: " +testWaveform.length + " min: " + PamArrayUtils.min(testWaveform) + " max: " + PamArrayUtils.max(testWaveform));
|
||||
|
||||
|
||||
testWaveform=PamArrayUtils.divide(testWaveform, PamUtils.PamArrayUtils.max(testWaveform));
|
||||
|
||||
testWaveform = MTClassifier.normaliseWaveform(testWaveform, MatchedTemplateParams.NORMALIZATION_RMS);
|
||||
|
||||
//System.out.println("Waveform max: " + PamArrayUtils.max(testWaveform) + " len: " + testWaveform.length);
|
||||
|
||||
|
||||
//calculate the click FFT.
|
||||
fft = new FastFFT();
|
||||
//int fftSize = FastFFT.nextBinaryExp(testWaveform.length/2);
|
||||
@ -115,14 +134,25 @@ public class MTClassifierTest {
|
||||
MatchedTemplateResult matchResult = mtclassifier.calcCorrelationMatch(matchClick, sR);
|
||||
|
||||
|
||||
System.out.println(String.format("The match correlation for %d is %.5f", i, matchResult.matchCorr));
|
||||
System.out.println(String.format("The match correlation for %d is %.5f", i, matchResult.matchCorr));
|
||||
//
|
||||
// printFFt(matchClick);
|
||||
//
|
||||
// System.out.println("-----------------------");
|
||||
//
|
||||
// ComplexArray matchTemplate = mtclassifier.getWaveformMatchFFT(sR, matchClick.length()*2);
|
||||
//
|
||||
// printFFt(matchTemplate);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void printFFt(ComplexArray complexArray) {
|
||||
for (int i=0; i<complexArray.length(); i++ ) {
|
||||
System.out.println(complexArray.get(i).toString(6));
|
||||
//System.out.println(complexArray.get(i).toString(6));
|
||||
System.out.println(complexArray.get(i).real + "," + complexArray.get(i).imag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +207,7 @@ public class MTClassifierTest {
|
||||
MLDouble clickUID=(MLDouble) mlArrayRetrived.getField("UID", i);
|
||||
|
||||
|
||||
clicks.add(new MatchTemplate(Integer.toString((int) clickUID.get(0).doubleValue()), waveform, 288000));
|
||||
clicks.add(new MatchTemplate(Long.toString(clickUID.get(0).longValue()), waveform, 288000));
|
||||
}
|
||||
return clicks;
|
||||
}
|
||||
@ -303,16 +333,19 @@ public class MTClassifierTest {
|
||||
|
||||
}
|
||||
|
||||
public static void testMatchCorr() {
|
||||
/**
|
||||
* Test how the length of the waveform affects the match correlation values
|
||||
*/
|
||||
public static void testMatchCorrLen() {
|
||||
|
||||
String testClicksPath = "/Users/au671271/MATLAB-Drive/MATLAB/PAMGUARD/matchedclickclassifer/DS2clks_test.mat";
|
||||
String templteFilePath= "/Users/au671271/MATLAB-Drive/MATLAB/PAMGUARD/matchedclickclassifer/DS2templates_test.mat";
|
||||
String testClicksPath = "/Users/au671271/MATLAB-Drive/MATLAB/PAMGUARD/matchedclickclassifer/DS3clks_test.mat";
|
||||
String templteFilePath= "/Users/au671271/MATLAB-Drive/MATLAB/PAMGUARD/matchedclickclassifer/DS3templates_test.mat";
|
||||
|
||||
float sR = 288000; //sample rate in samples per second.
|
||||
ArrayList<MatchTemplate> clicks = importClicks(testClicksPath, sR);
|
||||
ArrayList<MatchTemplate> templates = importTemplates(templteFilePath);
|
||||
|
||||
int index = 0;
|
||||
int index = 24;
|
||||
//values in MATLAB are9.73577287114938 8.82782814105430 3.51936216182390
|
||||
System.out.println("Number of clicks: " + clicks.size() + " UID " + clicks.get(index).name);
|
||||
|
||||
@ -321,7 +354,7 @@ public class MTClassifierTest {
|
||||
|
||||
System.out.println("------Restricted Length--------");
|
||||
|
||||
int restrictedBins= 1024;
|
||||
int restrictedBins= 2048;
|
||||
|
||||
ClickLength clickLength = new ClickLength();
|
||||
int[][] lengthPoints = clickLength.createLengthData(clicks.get(index), sR, 5.5, 3, false, null);
|
||||
@ -333,9 +366,23 @@ public class MTClassifierTest {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the match corr algorithm by cross correlating a waveform with itself.
|
||||
*/
|
||||
public static void testMatchCorr() {
|
||||
|
||||
String templteFilePath= "/Users/au671271/MATLAB-Drive/MATLAB/PAMGUARD/matchedclickclassifer/DS2templates_test.mat";
|
||||
//float sR = 288000; //sample rate in samples per second.
|
||||
|
||||
ArrayList<MatchTemplate> templates = importTemplates(templteFilePath);
|
||||
|
||||
testCorrelation(templates.get(0).waveform, templates.get(0).sR, templates);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void main(String args[]) {
|
||||
testMatchCorr();
|
||||
testMatchCorrLen();
|
||||
}
|
||||
|
||||
|
||||
|
@ -257,7 +257,7 @@ public class MTSettingsPane extends SettingsPane<MatchedTemplateParams> {
|
||||
|
||||
//click normalisation
|
||||
normBox = new ComboBox<String>();
|
||||
normBox.getItems().addAll("peak to peak", "RMS", "none");
|
||||
normBox.getItems().addAll("peak to peak", "norm", "none");
|
||||
|
||||
PamHBox clickNormPane= new PamHBox();
|
||||
clickNormPane.setSpacing(5);
|
||||
|
@ -65,6 +65,8 @@ public class MTOfflineProcess {
|
||||
//System.out.println("Click train offline data block " + clickTrainControl.getParentDataBlock());
|
||||
mtOfflineGroup.setPrimaryDataBlock(mtContorl.getParentDataBlock());
|
||||
mtOfflineTask.setParentDataBlock(mtContorl.getParentDataBlock());
|
||||
//need this to make sure annotations trigger saving.
|
||||
mtOfflineTask.addAffectedDataBlock(mtContorl.getParentDataBlock());
|
||||
|
||||
//if null open the dialog- also create a new offlineTask group if the datablock has changed.
|
||||
if (mtOfflineDialog == null) {
|
||||
|
@ -75,7 +75,6 @@ public class GenericModelTest {
|
||||
//long time1 = System.currentTimeMillis();
|
||||
data = new float[][][] {DLUtils.toFloatArray(((FreqTransform) transform).getSpecTransfrom().getTransformedData())};
|
||||
|
||||
|
||||
//data = new float[][][] { DLUtils.makeDummySpectrogram(40, 40)};
|
||||
|
||||
//System.out.println("data len: " + data.length + " " + data[0].length + " " + data[0][0].length);
|
||||
|
Loading…
Reference in New Issue
Block a user