annotate base/LogRange.cpp @ 808:67003fb58ba4

Merge from branch "qt5". This revision actually builds with Qt4 (late releases) or Qt5, though it will warn on configure with Qt4.
author Chris Cannam
date Tue, 14 May 2013 12:36:05 +0100
parents 1424aa29ae95
children cc27f35aa75c
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@224 24 LogRange::mapRange(float &min, float &max, float logthresh)
Chris@224 25 {
Chris@224 26 if (min > max) std::swap(min, max);
Chris@224 27 if (max == min) max = min + 1;
Chris@224 28
Chris@690 29 // SVDEBUG << "LogRange::mapRange: min = " << min << ", max = " << max << endl;
Chris@464 30
Chris@224 31 if (min >= 0.f) {
Chris@224 32
Chris@224 33 max = log10f(max); // we know max != 0
Chris@224 34
Chris@224 35 if (min == 0.f) min = std::min(logthresh, max);
Chris@224 36 else min = log10f(min);
Chris@224 37
Chris@690 38 // SVDEBUG << "LogRange::mapRange: positive: min = " << min << ", max = " << max << endl;
Chris@464 39
Chris@224 40 } else if (max <= 0.f) {
Chris@224 41
Chris@224 42 min = log10f(-min); // we know min != 0
Chris@224 43
Chris@224 44 if (max == 0.f) max = std::min(logthresh, min);
Chris@224 45 else max = log10f(-max);
Chris@224 46
Chris@224 47 std::swap(min, max);
Chris@224 48
Chris@690 49 // SVDEBUG << "LogRange::mapRange: negative: min = " << min << ", max = " << max << endl;
Chris@464 50
Chris@224 51 } else {
Chris@224 52
Chris@224 53 // min < 0 and max > 0
Chris@224 54
Chris@224 55 max = log10f(std::max(max, -min));
Chris@224 56 min = std::min(logthresh, max);
Chris@464 57
Chris@690 58 // SVDEBUG << "LogRange::mapRange: spanning: min = " << min << ", max = " << max << endl;
Chris@224 59 }
Chris@224 60
Chris@224 61 if (min == max) min = max - 1;
Chris@224 62 }
Chris@224 63
Chris@224 64 float
Chris@224 65 LogRange::map(float value, float thresh)
Chris@224 66 {
Chris@224 67 if (value == 0.f) return thresh;
Chris@224 68 return log10f(fabsf(value));
Chris@224 69 }
Chris@224 70
Chris@266 71 float
Chris@266 72 LogRange::unmap(float value)
Chris@266 73 {
Chris@266 74 return powf(10.0, value);
Chris@266 75 }
Chris@478 76
Chris@478 77 static float
Chris@478 78 sd(const std::vector<float> &values, size_t start, size_t n)
Chris@478 79 {
Chris@478 80 float sum = 0.f, mean = 0.f, variance = 0.f;
Chris@478 81 for (size_t i = 0; i < n; ++i) {
Chris@478 82 sum += values[start + i];
Chris@478 83 }
Chris@478 84 mean = sum / n;
Chris@478 85 for (size_t i = 0; i < n; ++i) {
Chris@478 86 float diff = values[start + i] - mean;
Chris@478 87 variance += diff * diff;
Chris@478 88 }
Chris@478 89 variance = variance / n;
Chris@478 90 return sqrtf(variance);
Chris@478 91 }
Chris@478 92
Chris@478 93 bool
Chris@478 94 LogRange::useLogScale(std::vector<float> values)
Chris@478 95 {
Chris@478 96 // Principle: Partition the data into two sets around the median;
Chris@478 97 // calculate the standard deviation of each set; if the two SDs
Chris@478 98 // are very different, it's likely that a log scale would be good.
Chris@478 99
Chris@478 100 if (values.size() < 4) return false;
Chris@478 101 std::sort(values.begin(), values.end());
Chris@478 102 size_t mi = values.size() / 2;
Chris@478 103
Chris@478 104 float sd0 = sd(values, 0, mi);
Chris@478 105 float sd1 = sd(values, mi, values.size() - mi);
Chris@478 106
Chris@690 107 SVDEBUG << "LogRange::useLogScale: sd0 = "
Chris@687 108 << sd0 << ", sd1 = " << sd1 << endl;
Chris@478 109
Chris@478 110 if (sd0 == 0 || sd1 == 0) return false;
Chris@478 111
Chris@478 112 // I wonder what method of determining "one sd much bigger than
Chris@478 113 // the other" would be appropriate here...
Chris@478 114 if (std::max(sd0, sd1) / std::min(sd0, sd1) > 10.f) return true;
Chris@478 115 else return false;
Chris@478 116 }
Chris@478 117