svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006 Chris Cannam. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #include "LogRange.h" 00017 #include "system/System.h" 00018 00019 #include <algorithm> 00020 #include <iostream> 00021 #include <cmath> 00022 00023 void 00024 LogRange::mapRange(float &min, float &max, float logthresh) 00025 { 00026 if (min > max) std::swap(min, max); 00027 if (max == min) max = min + 1; 00028 00029 // SVDEBUG << "LogRange::mapRange: min = " << min << ", max = " << max << endl; 00030 00031 if (min >= 0.f) { 00032 00033 max = log10f(max); // we know max != 0 00034 00035 if (min == 0.f) min = std::min(logthresh, max); 00036 else min = log10f(min); 00037 00038 // SVDEBUG << "LogRange::mapRange: positive: min = " << min << ", max = " << max << endl; 00039 00040 } else if (max <= 0.f) { 00041 00042 min = log10f(-min); // we know min != 0 00043 00044 if (max == 0.f) max = std::min(logthresh, min); 00045 else max = log10f(-max); 00046 00047 std::swap(min, max); 00048 00049 // SVDEBUG << "LogRange::mapRange: negative: min = " << min << ", max = " << max << endl; 00050 00051 } else { 00052 00053 // min < 0 and max > 0 00054 00055 max = log10f(std::max(max, -min)); 00056 min = std::min(logthresh, max); 00057 00058 // SVDEBUG << "LogRange::mapRange: spanning: min = " << min << ", max = " << max << endl; 00059 } 00060 00061 if (min == max) min = max - 1; 00062 } 00063 00064 float 00065 LogRange::map(float value, float thresh) 00066 { 00067 if (value == 0.f) return thresh; 00068 return log10f(fabsf(value)); 00069 } 00070 00071 float 00072 LogRange::unmap(float value) 00073 { 00074 return powf(10.0, value); 00075 } 00076 00077 static float 00078 sd(const std::vector<float> &values, size_t start, size_t n) 00079 { 00080 float sum = 0.f, mean = 0.f, variance = 0.f; 00081 for (size_t i = 0; i < n; ++i) { 00082 sum += values[start + i]; 00083 } 00084 mean = sum / n; 00085 for (size_t i = 0; i < n; ++i) { 00086 float diff = values[start + i] - mean; 00087 variance += diff * diff; 00088 } 00089 variance = variance / n; 00090 return sqrtf(variance); 00091 } 00092 00093 bool 00094 LogRange::useLogScale(std::vector<float> values) 00095 { 00096 // Principle: Partition the data into two sets around the median; 00097 // calculate the standard deviation of each set; if the two SDs 00098 // are very different, it's likely that a log scale would be good. 00099 00100 if (values.size() < 4) return false; 00101 std::sort(values.begin(), values.end()); 00102 size_t mi = values.size() / 2; 00103 00104 float sd0 = sd(values, 0, mi); 00105 float sd1 = sd(values, mi, values.size() - mi); 00106 00107 SVDEBUG << "LogRange::useLogScale: sd0 = " 00108 << sd0 << ", sd1 = " << sd1 << endl; 00109 00110 if (sd0 == 0 || sd1 == 0) return false; 00111 00112 // I wonder what method of determining "one sd much bigger than 00113 // the other" would be appropriate here... 00114 if (std::max(sd0, sd1) / std::min(sd0, sd1) > 10.f) return true; 00115 else return false; 00116 } 00117