changeset 1266:dd190086db73 3.0-integration

Tests and fixes for distribute(). Although this version of interpolated distribution passes these tests, it isn't right visually -- the expected values in the tests are offset. To be continued.
author Chris Cannam
date Thu, 17 Nov 2016 14:33:20 +0000
parents e2e66bfd4a88
children 1d8418cca63a
files base/ColumnOp.h base/test/TestColumnOp.h files.pri
diffstat 3 files changed, 103 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- a/base/ColumnOp.h	Thu Nov 17 11:56:54 2016 +0000
+++ b/base/ColumnOp.h	Thu Nov 17 14:33:20 2016 +0000
@@ -18,10 +18,7 @@
 
 #include "BaseTypes.h"
 
-#include <cmath>
 #include <vector>
-#include <algorithm>
-#include <iostream>
 
 /**
  * Display normalization types for columns in e.g. grid plots.
@@ -58,24 +55,17 @@
      * Scale the given column using the given gain multiplier.
      */
     static Column applyGain(const Column &in, double gain) {
-	
-	if (gain == 1.0) {
-	    return in;
-	}
+        if (gain == 1.0) return in;
 	Column out;
 	out.reserve(in.size());
-	for (auto v: in) {
-	    out.push_back(float(v * gain));
-	}
+	for (auto v: in) out.push_back(float(v * gain));
 	return out;
     }
 
     /**
      * Scale an FFT output downward by half the FFT size.
      */
-    static Column fftScale(const Column &in, int fftSize) {
-        return applyGain(in, 2.0 / fftSize);
-    }
+    static Column fftScale(const Column &in, int fftSize);
 
     /**
      * Determine whether an index points to a local peak.
@@ -103,59 +93,18 @@
      * Return a column containing only the local peak values (all
      * others zero).
      */
-    static Column peakPick(const Column &in) {
-	
-	std::vector<float> out(in.size(), 0.f);
-	for (int i = 0; in_range_for(in, i); ++i) {
-	    if (isPeak(in, i)) {
-		out[i] = in[i];
-	    }
-	}
-	
-	return out;
-    }
+    static Column peakPick(const Column &in);
 
     /**
      * Return a column normalized from the input column according to
      * the given normalization scheme.
+     *
+     * Note that the sum or max (as appropriate) used for
+     * normalisation will be calculated from the absolute values of
+     * the column elements, should any of them be negative.
      */
-    static Column normalize(const Column &in, ColumnNormalization n) {
-
-	if (n == ColumnNormalization::None || in.empty()) {
-	    return in;
-	}
-
-        float scale = 1.f;
-        
-        if (n == ColumnNormalization::Sum1) {
-
-            float sum = 0.f;
-
-            for (auto v: in) {
-                sum += v;
-            }
-
-            if (sum != 0.f) {
-                scale = 1.f / sum;
-            }
-        } else {
-        
-            float max = *max_element(in.begin(), in.end());
-
-            if (n == ColumnNormalization::Max1) {
-                if (max != 0.f) {
-                    scale = 1.f / max;
-                }
-            } else if (n == ColumnNormalization::Hybrid) {
-                if (max > 0.f) {
-                    scale = log10f(max + 1.f) / max;
-                }
-            }
-        }
-
-        return applyGain(in, scale);
-    }
-
+    static Column normalize(const Column &in, ColumnNormalization n);
+    
     /**
      * Distribute the given column into a target vector of a different
      * size, optionally using linear interpolation. The binfory vector
@@ -169,63 +118,7 @@
 			     int h,
 			     const std::vector<double> &binfory,
 			     int minbin,
-			     bool interpolate) {
-
-	std::vector<float> out(h, 0.f);
-	int bins = int(in.size());
-
-	for (int y = 0; y < h; ++y) {
-        
-	    double sy0 = binfory[y] - minbin;
-	    double sy1 = sy0 + 1;
-	    if (y+1 < h) {
-		sy1 = binfory[y+1] - minbin;
-	    }
-
-            std::cerr << "y = " << y << " of " << h << ", sy0 = " << sy0 << ", sy1 = " << sy1 << std::endl;
-        
-	    if (interpolate && fabs(sy1 - sy0) < 1.0) {
-            
-		double centre = (sy0 + sy1) / 2;
-		double dist = (centre - 0.5) - rint(centre - 0.5);
-		int bin = int(centre);
-
-		int other = (dist < 0 ? (bin-1) : (bin+1));
-
-		if (bin < 0) bin = 0;
-		if (bin >= bins) bin = bins-1;
-
-		if (other < 0 || other >= bins) {
-		    other = bin;
-		}
-
-		double prop = 1.0 - fabs(dist);
-
-		double v0 = in[bin];
-		double v1 = in[other];
-                
-		out[y] = float(prop * v0 + (1.0 - prop) * v1);
-
-	    } else { // not interpolating this one
-
-		int by0 = int(sy0 + 0.0001);
-		int by1 = int(sy1 + 0.0001);
-		if (by1 < by0 + 1) by1 = by0 + 1;
-                if (by1 >= bins) by1 = bins - 1;
-                
-		for (int bin = by0; bin <= by1; ++bin) {
-
-		    float value = in[bin];
-
-		    if (bin == by0 || value > out[y]) {
-			out[y] = value;
-		    }
-		}
-	    }
-	}
-
-	return out;
-    }
+			     bool interpolate);
 
 };
 
--- a/base/test/TestColumnOp.h	Thu Nov 17 11:56:54 2016 +0000
+++ b/base/test/TestColumnOp.h	Thu Nov 17 14:33:20 2016 +0000
@@ -31,7 +31,18 @@
 
     typedef ColumnOp C;
     typedef ColumnOp::Column Column;
-    
+    typedef vector<double> BinMapping;
+
+    template <typename T>
+    void report(vector<T> v) {
+        cerr << "Vector is: [ ";
+        for (int i = 0; i < int(v.size()); ++i) {
+            if (i > 0) cerr << ", ";
+            cerr << v[i];
+        }
+        cerr << " ]\n";
+    }
+                                     
 private slots:
     void applyGain() {
         QCOMPARE(C::applyGain({}, 1.0), Column());
@@ -129,18 +140,35 @@
         QCOMPARE(C::normalize(c, ColumnNormalization::None), c);
     }
 
+    void normalize_none_mixedSign() {
+        Column c { 1, 2, -3, -4 };
+        QCOMPARE(C::normalize(c, ColumnNormalization::None), c);
+    }
+
     void normalize_sum1() {
         Column c { 1, 2, 4, 3 };
         QCOMPARE(C::normalize(c, ColumnNormalization::Sum1),
                  Column({ 0.1, 0.2, 0.4, 0.3 }));
     }
 
+    void normalize_sum1_mixedSign() {
+        Column c { 1, 2, -4, -3 };
+        QCOMPARE(C::normalize(c, ColumnNormalization::Sum1),
+                 Column({ 0.1, 0.2, -0.4, -0.3 }));
+    }
+
     void normalize_max1() {
         Column c { 4, 3, 2, 1 };
         QCOMPARE(C::normalize(c, ColumnNormalization::Max1),
                  Column({ 1.0, 0.75, 0.5, 0.25 }));
     }
 
+    void normalize_max1_mixedSign() {
+        Column c { -4, -3, 2, 1 };
+        QCOMPARE(C::normalize(c, ColumnNormalization::Max1),
+                 Column({ -1.0, -0.75, 0.5, 0.25 }));
+    }
+
     void normalize_hybrid() {
         // with max == 99, log10(max+1) == 2 so scale factor will be 2/99
         Column c { 22, 44, 99, 66 };
@@ -148,6 +176,68 @@
                  Column({ 44.0/99.0, 88.0/99.0, 2.0, 132.0/99.0 }));
     }
 
+    void normalize_hybrid_mixedSign() {
+        // with max == 99, log10(max+1) == 2 so scale factor will be 2/99
+        Column c { 22, 44, -99, -66 };
+        QCOMPARE(C::normalize(c, ColumnNormalization::Hybrid),
+                 Column({ 44.0/99.0, 88.0/99.0, -2.0, -132.0/99.0 }));
+    }
+    
+    void distribute_simple() {
+        Column in { 1, 2, 3 };
+        BinMapping binfory { 0.0, 0.5, 1.0, 1.5, 2.0, 2.5 };
+        Column expected { 1, 1, 2, 2, 3, 3 };
+        Column actual(C::distribute(in, 6, binfory, 0, false));
+        report(actual);
+        QCOMPARE(actual, expected);
+    }
+    
+    void distribute_simple_interpolated() {
+        Column in { 1, 2, 3 };
+        BinMapping binfory { 0.0, 0.5, 1.0, 1.5, 2.0, 2.5 };
+        Column expected { 1, 1.5, 2, 2.5, 3, 3 };
+        Column actual(C::distribute(in, 6, binfory, 0, true));
+        report(actual);
+        QCOMPARE(actual, expected);
+    }
+    
+    void distribute_nonlinear() {
+        Column in { 1, 2, 3 };
+        BinMapping binfory { 0.0, 0.2, 0.5, 1.0, 2.0, 2.5 };
+        Column expected { 1, 1, 1, 2, 3, 3 };
+        Column actual(C::distribute(in, 6, binfory, 0, false));
+        report(actual);
+        QCOMPARE(actual, expected);
+    }
+    
+    void distribute_nonlinear_interpolated() {
+        Column in { 1, 2, 3 };
+        BinMapping binfory { 0.0, 0.2, 0.5, 1.0, 2.0, 2.5 };
+        Column expected { 1, 1.2, 1.5, 2, 3, 3 };
+        Column actual(C::distribute(in, 6, binfory, 0, true));
+        report(actual);
+        QCOMPARE(actual, expected);
+    }
+    
+    void distribute_shrinking() {
+        Column in { 4, 1, 2, 3, 5, 6 };
+        BinMapping binfory { 0.0, 2.0, 4.0 };
+        Column expected { 4, 3, 6 };
+        Column actual(C::distribute(in, 3, binfory, 0, false));
+        report(actual);
+        QCOMPARE(actual, expected);
+    }
+    
+    void distribute_shrinking_interpolated() {
+        // should be same as distribute_shrinking, we don't
+        // interpolate when resizing down
+        Column in { 4, 1, 2, 3, 5, 6 };
+        BinMapping binfory { 0.0, 2.0, 4.0 };
+        Column expected { 4, 3, 6 };
+        Column actual(C::distribute(in, 3, binfory, 0, true));
+        report(actual);
+        QCOMPARE(actual, expected);
+    }
     
         
 };
--- a/files.pri	Thu Nov 17 11:56:54 2016 +0000
+++ b/files.pri	Thu Nov 17 14:33:20 2016 +0000
@@ -143,6 +143,7 @@
 SVCORE_SOURCES = \
            base/AudioLevel.cpp \
            base/Clipboard.cpp \
+           base/ColumnOp.cpp \
            base/Command.cpp \
            base/Debug.cpp \
            base/Exceptions.cpp \