Bug fixes for matched filter

The match filter used in the matched click classifier was flipping arrays instead of using the complex conjugate for FFT xcorr. Ooops
This commit is contained in:
Jamie Mac 2022-01-20 12:04:13 +00:00
parent 5aaedec235
commit cf4e3ccfe1
3 changed files with 66 additions and 20 deletions

View File

@ -103,9 +103,14 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
if (waveformMatchFFT==null || currentSr!=sR) { if (waveformMatchFFT==null || currentSr!=sR) {
if (fft==null) fft=new FastFFT(); 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 //re-sample the waveform if the sample rate is different
this.interpWaveformMatch=interpWaveform(this.waveformMatch, sR); this.interpWaveformMatch=interpWaveform(this.waveformMatch, sR);
//System.out.println("interpWaveformMatch: " + interpWaveformMatch.length + " sR " + sR);
//normalise //normalise
//this.interpWaveformMatch=PamArrayUtils.normalise(interpWaveformMatch); //this.interpWaveformMatch=PamArrayUtils.normalise(interpWaveformMatch);
@ -115,9 +120,11 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// System.out.println("MatchNorm: MATCH"); // System.out.println("MatchNorm: MATCH");
// MTClassifierTest.normalizeTest(interpWaveformMatch); // MTClassifierTest.normalizeTest(interpWaveformMatch);
//here use the FFT length with the maximum template size. waveformMatchFFT = fft.rfft(interpWaveformMatch, length);
waveformMatchFFT = fft.rfft(PamArrayUtils.flip(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 + // System.out.println("waveformMatch: " + waveformMatch.waveform.length +
// " interpWaveformMatch: " + interpWaveformMatch.length + " for " +sR + " sr "); // " interpWaveformMatch: " + interpWaveformMatch.length + " for " +sR + " sr ");
@ -155,9 +162,11 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// MTClassifierTest.printWaveform(inteprWaveformReject); // MTClassifierTest.printWaveform(inteprWaveformReject);
//System.out.println("waveformReject: " +inteprWaveformReject.length + " fftLength: " + getFFTLength(sR)); //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. //need to calculate the complex conjugate - note that originally I was flipping the array but this means
waveformRejectFFT = fft.rfft(PamArrayUtils.flip(inteprWaveformReject), length); //the max value does not equal one with identical waveforms...doh.
waveformRejectFFT = waveformRejectFFT.conj();
} }
return waveformRejectFFT; return waveformRejectFFT;
} }
@ -342,11 +351,9 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
//set the stored sR //set the stored sR
currentSr=sR; currentSr=sR;
// System.out.println("Matched click classifier: Waveform click: " + click.length()); //System.out.println("Waveform click: len: " + click.length());
// System.out.println("Matched click classifier: Waveform click: " + click.length());
// System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject)); //System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject)+ " len " + interpWaveformMatch.length);
// System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject));
//int fftLength = getFFTLength(sR); //int fftLength = getFFTLength(sR);
//int fftLength = this.getFFTLength(sR); //int fftLength = this.getFFTLength(sR);
@ -363,7 +370,10 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
ComplexArray matchResult= new ComplexArray(fftLength); ComplexArray matchResult= new ComplexArray(fftLength);
ComplexArray matchTemplate = getWaveformMatchFFT(sR,fftLength); ComplexArray matchTemplate = getWaveformMatchFFT(sR,fftLength);
//System.out.println("matchTemplate: Waveform click: " + matchTemplate.length());
//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++) { for (int i=0; i<Math.min(matchTemplate.length(), click.length()); i++) {
matchResult.set(i, click.get(i).times(matchTemplate.get(i))); matchResult.set(i, click.get(i).times(matchTemplate.get(i)));
} }
@ -387,13 +397,13 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
//System.out.println("Inverse MATCH RESULTS"); //System.out.println("Inverse MATCH RESULTS");
//need to take the real part of the result and multiply by 2 to get same as //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[] matchReal = new double[matchResult.length()];
double[] rejectReal = new double[rejectResult.length()]; double[] rejectReal = new double[rejectResult.length()];
for (int i=0; i<matchResult.length(); i++) { for (int i=0; i<matchResult.length(); i++) {
matchReal[i]=matchResult.getReal(i); matchReal[i]=2*matchResult.getReal(i);
rejectReal[i]=rejectResult.getReal(i); rejectReal[i]=2*rejectResult.getReal(i);
//System.out.println("iFFt match result: " + matchResult.get(i) + " iFFT rejectResult: " + rejectResult.get(i) ); //System.out.println("iFFt match result: " + matchResult.get(i) + " iFFT rejectResult: " + rejectResult.get(i) );
} }

View File

@ -72,19 +72,32 @@ public class MTClassifierTest {
return struct; 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 * Test the correlation of several templates
* @param testWaveform * @param testWaveform - the waveform to correlate against.
* @param sR * @param sR - the sample rate of the waveform.
* @param templates * @param templates - the match templates to test.
* @return * @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 //create the classifier object
for (int i=0; i<templates.size(); i++){ for (int i=0; i<templates.size(); i++){
MTClassifier mtclassifier = new MTClassifier(); MTClassifier mtclassifier = new MTClassifier();
mtclassifier.normalisation = normalisation;
//System.out.println("Template " + i + " " + templates.get(i)); //System.out.println("Template " + i + " " + templates.get(i));
//add templates if inpout //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)); //System.out.println("Waveform len: " +testWaveform.length + " min: " + PamArrayUtils.min(testWaveform) + " max: " + PamArrayUtils.max(testWaveform));
testWaveform=PamArrayUtils.divide(testWaveform, PamUtils.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. //calculate the click FFT.
fft = new FastFFT(); fft = new FastFFT();
//int fftSize = FastFFT.nextBinaryExp(testWaveform.length/2); //int fftSize = FastFFT.nextBinaryExp(testWaveform.length/2);
@ -303,7 +322,10 @@ 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 testClicksPath = "/Users/au671271/MATLAB-Drive/MATLAB/PAMGUARD/matchedclickclassifer/DS2clks_test.mat";
String templteFilePath= "/Users/au671271/MATLAB-Drive/MATLAB/PAMGUARD/matchedclickclassifer/DS2templates_test.mat"; String templteFilePath= "/Users/au671271/MATLAB-Drive/MATLAB/PAMGUARD/matchedclickclassifer/DS2templates_test.mat";
@ -333,6 +355,20 @@ 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[]) { public static void main(String args[]) {
testMatchCorr(); testMatchCorr();

View File

@ -257,7 +257,7 @@ public class MTSettingsPane extends SettingsPane<MatchedTemplateParams> {
//click normalisation //click normalisation
normBox = new ComboBox<String>(); normBox = new ComboBox<String>();
normBox.getItems().addAll("peak to peak", "RMS", "none"); normBox.getItems().addAll("peak to peak", "norm", "none");
PamHBox clickNormPane= new PamHBox(); PamHBox clickNormPane= new PamHBox();
clickNormPane.setSpacing(5); clickNormPane.setSpacing(5);