annotate base/LogRange.cpp @ 1392:667e369cfeab

LogRange tests
author Chris Cannam
date Tue, 28 Feb 2017 11:21:49 +0000
parents b061b9f8fca5
children 04abe8f73b22
rev   line source
Chris@224 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@224 2
Chris@224 3 /*
Chris@224 4 Sonic Visualiser
Chris@224 5 An audio file viewer and annotation editor.
Chris@224 6 Centre for Digital Music, Queen Mary, University of London.
Chris@224 7 This file copyright 2006 Chris Cannam.
Chris@224 8
Chris@224 9 This program is free software; you can redistribute it and/or
Chris@224 10 modify it under the terms of the GNU General Public License as
Chris@224 11 published by the Free Software Foundation; either version 2 of the
Chris@224 12 License, or (at your option) any later version. See the file
Chris@224 13 COPYING included with this distribution for more information.
Chris@224 14 */
Chris@224 15
Chris@224 16 #include "LogRange.h"
Chris@573 17 #include "system/System.h"
Chris@224 18
Chris@224 19 #include <algorithm>
Chris@464 20 #include <iostream>
Chris@224 21 #include <cmath>
Chris@224 22
Chris@224 23 void
Chris@1044 24 LogRange::mapRange(double &min, double &max, double logthresh)
Chris@224 25 {
Chris@1385 26 // ensure that max > min:
Chris@224 27 if (min > max) std::swap(min, max);
Chris@224 28 if (max == min) max = min + 1;
Chris@224 29
Chris@1073 30 // cerr << "LogRange::mapRange: min = " << min << ", max = " << max << endl;
Chris@1073 31
Chris@1385 32 if (min >= 0.0) {
Chris@224 33
Chris@1385 34 // and max > min, so we know min >= 0 and max > 0
Chris@1385 35
Chris@1385 36 max = log10(max);
Chris@224 37
Chris@1385 38 if (min == 0.0) min = std::min(logthresh, max);
Chris@1044 39 else min = log10(min);
Chris@224 40
Chris@1073 41 // cerr << "LogRange::mapRange: positive: min = " << min << ", max = " << max << endl;
Chris@464 42
Chris@1385 43 } else if (max <= 0.0) {
Chris@1385 44
Chris@1385 45 // and max > min, so we know min < 0 and max <= 0
Chris@224 46
Chris@1385 47 min = log10(-min);
Chris@1385 48
Chris@1385 49 if (max == 0.0) max = std::min(logthresh, min);
Chris@1044 50 else max = log10(-max);
Chris@224 51
Chris@224 52 std::swap(min, max);
Chris@224 53
Chris@1073 54 // cerr << "LogRange::mapRange: negative: min = " << min << ", max = " << max << endl;
Chris@464 55
Chris@224 56 } else {
Chris@224 57
Chris@224 58 // min < 0 and max > 0
Chris@224 59
Chris@1044 60 max = log10(std::max(max, -min));
Chris@224 61 min = std::min(logthresh, max);
Chris@464 62
Chris@1073 63 // cerr << "LogRange::mapRange: spanning: min = " << min << ", max = " << max << endl;
Chris@224 64 }
Chris@224 65
Chris@224 66 if (min == max) min = max - 1;
Chris@224 67 }
Chris@224 68
Chris@1044 69 double
Chris@1044 70 LogRange::map(double value, double thresh)
Chris@224 71 {
Chris@1385 72 if (value == 0.0) return thresh;
Chris@1044 73 return log10(fabs(value));
Chris@224 74 }
Chris@224 75
Chris@1044 76 double
Chris@1044 77 LogRange::unmap(double value)
Chris@266 78 {
Chris@1044 79 return pow(10.0, value);
Chris@266 80 }
Chris@478 81
Chris@1038 82 static double
Chris@1044 83 sd(const std::vector<double> &values, int start, int n)
Chris@478 84 {
Chris@1385 85 double sum = 0.0, mean = 0.0, variance = 0.0;
Chris@1038 86 for (int i = 0; i < n; ++i) {
Chris@478 87 sum += values[start + i];
Chris@478 88 }
Chris@478 89 mean = sum / n;
Chris@1038 90 for (int i = 0; i < n; ++i) {
Chris@1038 91 double diff = values[start + i] - mean;
Chris@478 92 variance += diff * diff;
Chris@478 93 }
Chris@478 94 variance = variance / n;
Chris@1038 95 return sqrt(variance);
Chris@478 96 }
Chris@478 97
Chris@478 98 bool
Chris@1392 99 LogRange::shouldUseLogScale(std::vector<double> values)
Chris@478 100 {
Chris@478 101 // Principle: Partition the data into two sets around the median;
Chris@478 102 // calculate the standard deviation of each set; if the two SDs
Chris@478 103 // are very different, it's likely that a log scale would be good.
Chris@478 104
Chris@1038 105 int n = int(values.size());
Chris@1038 106 if (n < 4) return false;
Chris@478 107 std::sort(values.begin(), values.end());
Chris@1038 108 int mi = n / 2;
Chris@478 109
Chris@1038 110 double sd0 = sd(values, 0, mi);
Chris@1038 111 double sd1 = sd(values, mi, n - mi);
Chris@478 112
Chris@690 113 SVDEBUG << "LogRange::useLogScale: sd0 = "
Chris@687 114 << sd0 << ", sd1 = " << sd1 << endl;
Chris@478 115
Chris@478 116 if (sd0 == 0 || sd1 == 0) return false;
Chris@478 117
Chris@478 118 // I wonder what method of determining "one sd much bigger than
Chris@478 119 // the other" would be appropriate here...
Chris@1038 120 if (std::max(sd0, sd1) / std::min(sd0, sd1) > 10.) return true;
Chris@478 121 else return false;
Chris@478 122 }
Chris@478 123