annotate base/LogRange.cpp @ 997:2104ea2204d2

Separate out stdout ability (not all writers that support one-file will necessarily want to support it, e.g. for binary formats)
author Chris Cannam
date Mon, 13 Oct 2014 10:56:16 +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