svcore  1.9
LogRange.cpp
Go to the documentation of this file.
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