changeset 81:788799487b1e

More on tests and inverse stuff
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 29 Apr 2014 16:52:16 +0100
parents 872fc9dc0321
children 24ff66e793fd
files yeti/build.xml yeti/icqt.yeti yeti/test_cqtkernel.yeti yeti/test_frequency.yeti
diffstat 4 files changed, 110 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/yeti/build.xml	Tue Apr 29 08:36:47 2014 +0100
+++ b/yeti/build.xml	Tue Apr 29 16:52:16 2014 +0100
@@ -1,4 +1,4 @@
-<project name="cqt" default="jar" basedir=".">
+<project name="cqt" default="test" basedir=".">
 
   <property name="maydir" value="${basedir}/../../may"/>
   <property name="yetidir" value="${basedir}/../../yeti"/>
@@ -45,10 +45,25 @@
     <jar jarfile="${basedir}/cqt.jar">
       <fileset dir="${basedir}/classes" 
 	       includes="**/*.class" 
-	       excludes="**/test/*.class"/>
+	       excludes="**/test*.class"/>
     </jar>
   </target>
 
+  <target name="testjar" depends="classes,taskdef">
+    <jar jarfile="${basedir}/test.jar">
+      <fileset dir="${basedir}/classes" 
+	       includes="**/test*.class"/>
+    </jar>
+  </target>
+
+  <target name="test" depends="jar,testjar,taskdef">
+    <java classpath="${basedir}/test.jar:${basedir}/cqt.jar:${maydir}/may.jar:${yetidir}/yeti.jar:${extjars}"
+	  classname="test"
+	  fork="true" failonerror="true">
+      <sysproperty key="java.library.path" path="${maydir}/ext/native/${archtag}"/>
+    </java>
+  </target>
+
   <target name="clean">
     <delete dir="${basedir}/classes"/>
   </target>
--- a/yeti/icqt.yeti	Tue Apr 29 08:36:47 2014 +0100
+++ b/yeti/icqt.yeti	Tue Apr 29 16:52:16 2014 +0100
@@ -31,13 +31,66 @@
 module icqt;
 
 cqt = load cqt;
+cm = load may.matrix.complex;
+mm = load may.mathmisc;
 
 icqt cq =
    (kdata = cq.kernel;
 
-    // kdata.kernel is the kernel matrix for a single octave, of width
-    // kdata.fftSize and height kdata.binsPerOctave.  !!! todo: unit
-    // tests for kernel size etc kdata.fftHop is the overlap between
-    // kernel matrices in a single octave.  cq.sampleRate is the
-    // output stream sample rate.
+    // kdata.kernel is the kernel matrix for a single octave. It has
+    // width kdata.fftSize and height kdata.binsPerOctave *
+    // kdata.atomsPerFrame.
+    //
+    // kdata.fftHop is the overlap between kernel matrices in a single
+    // octave.
+    // 
+    // cq.sampleRate is the output stream sample rate and cq.octaves
+    // the number of octaves.
+    //
+    // cq.cqComplex is the list of complex matrices containing the CQ
+    // output. Each has width kdata.atomsPerFrame * 2^(cq.octaves-1)
+    // and height kdata.binsPerOctave * cq.octaves.
 
+    bpo = kdata.binsPerOctave;
+    octaves = cq.octaves;
+
+    // transform a single block, all octaves tall, into an array
+    // (indexed by octave) of lists of individual columns (valid
+    // values for that octave only)
+    decomposeOctaves mat = array
+       (map do oct:
+            octMat = cm.rowSlice mat (bpo * oct) (bpo * (oct + 1));
+            gap = (mm.pow 2 oct) - 1;
+            pickFrom cols =
+                case cols of
+                c::cs: c::(pickFrom (drop gap cs));
+                _: [];
+                esac;
+            pickFrom (cm.asColumns octMat);
+        done [0..octaves-1]);
+
+    // transform a list of the arrays produced by decomposeOctaves
+    // into a single array (indexed by octave) of lists of the
+    // individual columns
+    flattenOctaves decomposed =
+       (flattenAux acc decomposed = 
+            case decomposed of
+            chunk::rest:
+                flattenAux 
+                   (array
+                       (map do oct:
+                            acc[oct] ++ chunk[oct]
+                            done [0..octaves-1]))
+                    rest;
+            _: [];
+            esac;
+        flattenAux (array (map \[] [0..octaves-1])) decomposed);
+
+    octaveColumnLists = flattenOctaves (map decomposeOctaves cq.cqComplex);
+
+
+    for octaveColumnLists do l: println "octave column list length: \(length l)" done;
+    
+);
+
+{icqt}
--- a/yeti/test_cqtkernel.yeti	Tue Apr 29 08:36:47 2014 +0100
+++ b/yeti/test_cqtkernel.yeti	Tue Apr 29 16:52:16 2014 +0100
@@ -31,16 +31,32 @@
 module test_cqtkernel;
 
 cm = load may.matrix.complex;
+mm = load may.mathmisc;
+
+{ compare, compareUsing } = load may.test;
 
 { makeKernel } = load cqtkernel;
 
+eps = 1e-7;
+
+compareClose = compareUsing do a b: abs (a - b) < eps done;
+
 [
 
 "minimal": \(
     k = makeKernel { sampleRate = 16, maxFreq = 8, binsPerOctave = 4 };
-print k;
-cm.print k.kernel;
-false;
+    compare k.binsPerOctave 4 and
+        compare (cm.size k.kernel) {
+            rows = k.binsPerOctave * k.atomsPerFrame,
+            columns = k.fftSize
+        } and
+        compareClose k.maxFrequency 8 and
+        compareClose k.minFrequency (4 * (mm.pow 2 (1/4))) and
+        compare k.atomsPerFrame 5 and
+        compare k.fftSize 32 and
+        compare (length k.binFrequencies) k.binsPerOctave and
+        compareClose (head k.binFrequencies) k.minFrequency and
+        compareClose (head (reverse k.binFrequencies)) k.maxFrequency
 ),
 
 ] is hash<string, () -> boolean>
--- a/yeti/test_frequency.yeti	Tue Apr 29 08:36:47 2014 +0100
+++ b/yeti/test_frequency.yeti	Tue Apr 29 16:52:16 2014 +0100
@@ -38,6 +38,8 @@
 syn = load may.stream.syntheticstream;
 plot = load may.plot;
 
+{ compare } = load may.test;
+
 { cqt } = load cqt;
 
 // Test with a single windowed sinusoid, repeating at various frequencies
@@ -71,23 +73,30 @@
 report message matrix =
    (eprintln message;
     eprintln "matrix is:";
-    mat.eprint matrix;
-    chart = plot.plot [Grid matrix];
-    sleep 100;
-    chart#dispose());
+    mat.eprint matrix);
+//    chart = plot.plot [Grid matrix];
+//    sleep 100;
+//    chart#dispose());
 
 tests = mapIntoHash
     do f: "freq_\(f)" done
     do f: \(
         str = streamBuilder f;
         cq = cqt { maxFreq = cqmax, minFreq = cqmin, binsPerOctave = bpo } str;
-        out = cq.cqComplex;
-        m = mat.concatHorizontal (map cm.magnitudes out);
+        spec = cq.cqSpectrogram;
+        rightSize = all id
+           (map do s:
+            compare (mat.size s) { 
+                rows = cq.kernel.binsPerOctave * cq.octaves,
+                columns = cq.kernel.atomsPerFrame * mm.pow 2 (cq.octaves - 1)
+            }
+            done spec);
+        m = mat.concatHorizontal spec;
 //    println "binFrequencies = \(cq.kernel.binFrequencies)";
 //    println "binForFreq \(f) = \(binForFreq f)";
         var colno = 0;
         success = all id
-           (map do c:
+           (rightSize :: map do c:
                 // The test passes for this column if:
                 //
                 //  * the max bin is the expected one, or