annotate base/LogRange.cpp @ 558:1d7ebc05157e

* Some fairly simplistic code to set up layer type properties based on RDF data about feature types (both when running transforms and when importing features from RDF files).
author Chris Cannam
date Thu, 12 Feb 2009 15:26:43 +0000
parents 1405f4a2caf3
children bdc9bb371a9f
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@224 17
Chris@224 18 #include <algorithm>
Chris@464 19 #include <iostream>
Chris@224 20 #include <cmath>
Chris@224 21
Chris@224 22 void
Chris@224 23 LogRange::mapRange(float &min, float &max, float logthresh)
Chris@224 24 {
Chris@224 25 if (min > max) std::swap(min, max);
Chris@224 26 if (max == min) max = min + 1;
Chris@224 27
Chris@464 28 // std::cerr << "LogRange::mapRange: min = " << min << ", max = " << max << std::endl;
Chris@464 29
Chris@224 30 if (min >= 0.f) {
Chris@224 31
Chris@224 32 max = log10f(max); // we know max != 0
Chris@224 33
Chris@224 34 if (min == 0.f) min = std::min(logthresh, max);
Chris@224 35 else min = log10f(min);
Chris@224 36
Chris@464 37 // std::cerr << "LogRange::mapRange: positive: min = " << min << ", max = " << max << std::endl;
Chris@464 38
Chris@224 39 } else if (max <= 0.f) {
Chris@224 40
Chris@224 41 min = log10f(-min); // we know min != 0
Chris@224 42
Chris@224 43 if (max == 0.f) max = std::min(logthresh, min);
Chris@224 44 else max = log10f(-max);
Chris@224 45
Chris@224 46 std::swap(min, max);
Chris@224 47
Chris@464 48 // std::cerr << "LogRange::mapRange: negative: min = " << min << ", max = " << max << std::endl;
Chris@464 49
Chris@224 50 } else {
Chris@224 51
Chris@224 52 // min < 0 and max > 0
Chris@224 53
Chris@224 54 max = log10f(std::max(max, -min));
Chris@224 55 min = std::min(logthresh, max);
Chris@464 56
Chris@464 57 // std::cerr << "LogRange::mapRange: spanning: min = " << min << ", max = " << max << std::endl;
Chris@224 58 }
Chris@224 59
Chris@224 60 if (min == max) min = max - 1;
Chris@224 61 }
Chris@224 62
Chris@224 63 float
Chris@224 64 LogRange::map(float value, float thresh)
Chris@224 65 {
Chris@224 66 if (value == 0.f) return thresh;
Chris@224 67 return log10f(fabsf(value));
Chris@224 68 }
Chris@224 69
Chris@266 70 float
Chris@266 71 LogRange::unmap(float value)
Chris@266 72 {
Chris@266 73 return powf(10.0, value);
Chris@266 74 }
Chris@478 75
Chris@478 76 static float
Chris@478 77 sd(const std::vector<float> &values, size_t start, size_t n)
Chris@478 78 {
Chris@478 79 float sum = 0.f, mean = 0.f, variance = 0.f;
Chris@478 80 for (size_t i = 0; i < n; ++i) {
Chris@478 81 sum += values[start + i];
Chris@478 82 }
Chris@478 83 mean = sum / n;
Chris@478 84 for (size_t i = 0; i < n; ++i) {
Chris@478 85 float diff = values[start + i] - mean;
Chris@478 86 variance += diff * diff;
Chris@478 87 }
Chris@478 88 variance = variance / n;
Chris@478 89 return sqrtf(variance);
Chris@478 90 }
Chris@478 91
Chris@478 92 bool
Chris@478 93 LogRange::useLogScale(std::vector<float> values)
Chris@478 94 {
Chris@478 95 // Principle: Partition the data into two sets around the median;
Chris@478 96 // calculate the standard deviation of each set; if the two SDs
Chris@478 97 // are very different, it's likely that a log scale would be good.
Chris@478 98
Chris@478 99 if (values.size() < 4) return false;
Chris@478 100 std::sort(values.begin(), values.end());
Chris@478 101 size_t mi = values.size() / 2;
Chris@478 102
Chris@478 103 float sd0 = sd(values, 0, mi);
Chris@478 104 float sd1 = sd(values, mi, values.size() - mi);
Chris@478 105
Chris@478 106 std::cerr << "LogRange::useLogScale: sd0 = "
Chris@478 107 << sd0 << ", sd1 = " << sd1 << std::endl;
Chris@478 108
Chris@478 109 if (sd0 == 0 || sd1 == 0) return false;
Chris@478 110
Chris@478 111 // I wonder what method of determining "one sd much bigger than
Chris@478 112 // the other" would be appropriate here...
Chris@478 113 if (std::max(sd0, sd1) / std::min(sd0, sd1) > 10.f) return true;
Chris@478 114 else return false;
Chris@478 115 }
Chris@478 116