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 (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 +120,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 +162,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 +351,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);
@ -363,7 +370,10 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
ComplexArray matchResult= new ComplexArray(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++) {
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");
//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) );
}

View File

@ -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);
@ -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 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[]) {
testMatchCorr();

View File

@ -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);