Mercurial > hg > qm-dsp
comparison dsp/maths/Histogram.h @ 225:49844bc8a895
* Queen Mary C++ DSP library
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Wed, 05 Apr 2006 17:35:59 +0000 |
parents | |
children | 14839f9a616e |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 225:49844bc8a895 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 // Histogram.h: interface for the THistogram class. | |
4 // | |
5 ////////////////////////////////////////////////////////////////////// | |
6 | |
7 | |
8 #ifndef HISTOGRAM_H | |
9 #define HISTOGRAM_H | |
10 | |
11 | |
12 #include <valarray> | |
13 | |
14 /*! \brief A histogram class | |
15 | |
16 This class computes the histogram of a vector. | |
17 | |
18 \par Template parameters | |
19 | |
20 - T type of input data (can be any: float, double, int, UINT, etc...) | |
21 - TOut type of output data: float or double. (default is double) | |
22 | |
23 \par Moments: | |
24 | |
25 The moments (average, standard deviation, skewness, etc.) are computed using | |
26 the algorithm of the Numerical recipies (see Numerical recipies in C, Chapter 14.1, pg 613). | |
27 | |
28 \par Example: | |
29 | |
30 This example shows the typical use of the class: | |
31 \code | |
32 // a vector containing the data | |
33 vector<float> data; | |
34 // Creating histogram using float data and with 101 containers, | |
35 THistogram<float> histo(101); | |
36 // computing the histogram | |
37 histo.compute(data); | |
38 \endcode | |
39 | |
40 Once this is done, you can get a vector with the histogram or the normalized histogram (such that it's area is 1): | |
41 \code | |
42 // getting normalized histogram | |
43 vector<float> v=histo.getNormalizedHistogram(); | |
44 \endcode | |
45 | |
46 \par Reference | |
47 | |
48 Equally spaced acsissa function integration (used in #GetArea): Numerical Recipies in C, Chapter 4.1, pg 130. | |
49 | |
50 \author Jonathan de Halleux, dehalleux@auto.ucl.ac.be, 2002 | |
51 */ | |
52 | |
53 template<class T, class TOut = double> | |
54 class THistogram | |
55 { | |
56 public: | |
57 //! \name Constructors | |
58 //@{ | |
59 /*! Default constructor | |
60 \param counters the number of histogram containers (default value is 10) | |
61 */ | |
62 THistogram(unsigned int counters = 10); | |
63 virtual ~THistogram() { clear();}; | |
64 //@} | |
65 | |
66 //! \name Histogram computation, update | |
67 //@{ | |
68 /*! Computes histogram of vector v | |
69 \param v vector to compute histogram | |
70 \param computeMinMax set to true if min/max of v have to be used to get the histogram limits | |
71 | |
72 This function computes the histogram of v and stores it internally. | |
73 \sa Update, GeTHistogram | |
74 */ | |
75 void compute( const std::vector<T>& v, bool computeMinMax = true); | |
76 //! Update histogram with the vector v | |
77 void update( const std::vector<T>& v); | |
78 //! Update histogram with t | |
79 void update( const T& t); | |
80 //@} | |
81 | |
82 //! \name Resetting functions | |
83 //@{ | |
84 //! Resize the histogram. Warning this function clear the histogram. | |
85 void resize( unsigned int counters ); | |
86 //! Clears the histogram | |
87 void clear() { m_counters.clear();}; | |
88 //@} | |
89 | |
90 //! \name Setters | |
91 //@{ | |
92 /*! This function sets the minimum of the histogram spectrum. | |
93 The spectrum is not recomputed, use it with care | |
94 */ | |
95 void setMinSpectrum( const T& min ) { m_min = min; computeStep();}; | |
96 /*! This function sets the minimum of the histogram spectrum. | |
97 The spectrum is not recomputed, use it with care | |
98 */ | |
99 void setMaxSpectrum( const T& max ) { m_max = max; computeStep();}; | |
100 //@} | |
101 //! \name Getters | |
102 //@{ | |
103 //! return minimum of histogram spectrum | |
104 const T& getMinSpectrum() const { return m_min;}; | |
105 //! return maximum of histogram spectrum | |
106 const T& getMaxSpectrum() const { return m_max;}; | |
107 //! return step size of histogram containers | |
108 TOut getStep() const { return m_step;}; | |
109 //! return number of points in histogram | |
110 unsigned int getSum() const; | |
111 /*! \brief returns area under the histogram | |
112 | |
113 The Simpson rule is used to integrate the histogram. | |
114 */ | |
115 TOut getArea() const; | |
116 | |
117 /*! \brief Computes the moments of the histogram | |
118 | |
119 \param data dataset | |
120 \param ave mean | |
121 \f[ \bar x = \frac{1}{N} \sum_{j=1}^N x_j\f] | |
122 \param adev mean absolute deviation | |
123 \f[ adev(X) = \frac{1}{N} \sum_{j=1}^N | x_j - \bar x |\f] | |
124 \param var average deviation: | |
125 \f[ \mbox{Var}(X) = \frac{1}{N-1} \sum_{j=1}^N (x_j - \bar x)^2\f] | |
126 \param sdev standard deviation: | |
127 \f[ \sigma(X) = \sqrt{var(\bar x) }\f] | |
128 \param skew skewness | |
129 \f[ \mbox{Skew}(X) = \frac{1}{N}\sum_{j=1}^N \left[ \frac{x_j - \bar x}{\sigma}\right]^3\f] | |
130 \param kurt kurtosis | |
131 \f[ \mbox{Kurt}(X) = \left\{ \frac{1}{N}\sum_{j=1}^N \left[ \frac{x_j - \bar x}{\sigma}\right]^4 \right\} - 3\f] | |
132 | |
133 */ | |
134 static void getMoments(const std::vector<T>& data, TOut& ave, TOut& adev, TOut& sdev, TOut& var, TOut& skew, TOut& kurt); | |
135 | |
136 //! return number of containers | |
137 unsigned int getSize() const { return m_counters.size();}; | |
138 //! returns i-th counter | |
139 unsigned int operator [] (unsigned int i) const { ASSERT( i < m_counters.size() ); return m_counters[i];}; | |
140 //! return the computed histogram | |
141 const std::vector<unsigned int>& geTHistogram() const { return m_counters;}; | |
142 //! return the computed histogram, in TOuts | |
143 std::vector<TOut> geTHistogramD() const; | |
144 /*! return the normalized computed histogram | |
145 | |
146 \return the histogram such that the area is equal to 1 | |
147 */ | |
148 std::vector<TOut> getNormalizedHistogram() const; | |
149 //! returns left containers position | |
150 std::vector<TOut> getLeftContainers() const; | |
151 //! returns center containers position | |
152 std::vector<TOut> getCenterContainers() const; | |
153 //@} | |
154 protected: | |
155 //! Computes the step | |
156 void computeStep() { m_step = (TOut)(((TOut)(m_max-m_min)) / (m_counters.size()-1));}; | |
157 //! Data accumulators | |
158 std::vector<unsigned int> m_counters; | |
159 //! minimum of dataset | |
160 T m_min; | |
161 //! maximum of dataset | |
162 T m_max; | |
163 //! width of container | |
164 TOut m_step; | |
165 }; | |
166 | |
167 template<class T, class TOut> | |
168 THistogram<T,TOut>::THistogram(unsigned int counters) | |
169 : m_counters(counters,0), m_min(0), m_max(0), m_step(0) | |
170 { | |
171 | |
172 } | |
173 | |
174 template<class T, class TOut> | |
175 void THistogram<T,TOut>::resize( unsigned int counters ) | |
176 { | |
177 clear(); | |
178 | |
179 m_counters.resize(counters,0); | |
180 | |
181 computeStep(); | |
182 } | |
183 | |
184 template<class T, class TOut> | |
185 void THistogram<T,TOut>::compute( const std::vector<T>& v, bool computeMinMax) | |
186 { | |
187 using namespace std; | |
188 unsigned int i; | |
189 int index; | |
190 | |
191 if (m_counters.empty()) | |
192 return; | |
193 | |
194 if (computeMinMax) | |
195 { | |
196 m_max = m_min = v[0]; | |
197 for (i=1;i<v.size();i++) | |
198 { | |
199 m_max = std::max( m_max, v[i]); | |
200 m_min = std::min( m_min, v[i]); | |
201 } | |
202 } | |
203 | |
204 computeStep(); | |
205 | |
206 for (i = 0;i < v.size() ; i++) | |
207 { | |
208 index=(int) floor( ((TOut)(v[i]-m_min))/m_step ) ; | |
209 | |
210 if (index >= m_counters.size() || index < 0) | |
211 return; | |
212 | |
213 m_counters[index]++; | |
214 } | |
215 } | |
216 | |
217 template<class T, class TOut> | |
218 void THistogram<T,TOut>::update( const std::vector<T>& v) | |
219 { | |
220 if (m_counters.empty()) | |
221 return; | |
222 | |
223 computeStep(); | |
224 | |
225 TOut size = m_counters.size(); | |
226 | |
227 int index; | |
228 for (unsigned int i = 0;i < size ; i++) | |
229 { | |
230 index = (int)floor(((TOut)(v[i]-m_min))/m_step); | |
231 | |
232 if (index >= m_counters.size() || index < 0) | |
233 return; | |
234 | |
235 m_counters[index]++; | |
236 } | |
237 } | |
238 | |
239 template<class T, class TOut> | |
240 void THistogram<T,TOut>::update( const T& t) | |
241 { | |
242 int index=(int) floor( ((TOut)(t-m_min))/m_step ) ; | |
243 | |
244 if (index >= m_counters.size() || index < 0) | |
245 return; | |
246 | |
247 m_counters[index]++; | |
248 }; | |
249 | |
250 template<class T, class TOut> | |
251 std::vector<TOut> THistogram<T,TOut>::geTHistogramD() const | |
252 { | |
253 std::vector<TOut> v(m_counters.size()); | |
254 for (unsigned int i = 0;i<m_counters.size(); i++) | |
255 v[i]=(TOut)m_counters[i]; | |
256 | |
257 return v; | |
258 } | |
259 | |
260 template <class T, class TOut> | |
261 std::vector<TOut> THistogram<T,TOut>::getLeftContainers() const | |
262 { | |
263 std::vector<TOut> x( m_counters.size()); | |
264 | |
265 for (unsigned int i = 0;i<m_counters.size(); i++) | |
266 x[i]= m_min + i*m_step; | |
267 | |
268 return x; | |
269 } | |
270 | |
271 template <class T, class TOut> | |
272 std::vector<TOut> THistogram<T,TOut>::getCenterContainers() const | |
273 { | |
274 std::vector<TOut> x( m_counters.size()); | |
275 | |
276 for (unsigned int i = 0;i<m_counters.size(); i++) | |
277 x[i]= m_min + (i+0.5)*m_step; | |
278 | |
279 return x; | |
280 } | |
281 | |
282 template <class T, class TOut> | |
283 unsigned int THistogram<T,TOut>::getSum() const | |
284 { | |
285 unsigned int sum = 0; | |
286 for (unsigned int i = 0;i<m_counters.size(); i++) | |
287 sum+=m_counters[i]; | |
288 | |
289 return sum; | |
290 } | |
291 | |
292 template <class T, class TOut> | |
293 TOut THistogram<T,TOut>::getArea() const | |
294 { | |
295 const size_t n=m_counters.size(); | |
296 TOut area=0; | |
297 | |
298 if (n>6) | |
299 { | |
300 area=3.0/8.0*(m_counters[0]+m_counters[n-1]) | |
301 +7.0/6.0*(m_counters[1]+m_counters[n-2]) | |
302 +23.0/24.0*(m_counters[2]+m_counters[n-3]); | |
303 for (unsigned int i=3;i<n-3;i++) | |
304 { | |
305 area+=m_counters[i]; | |
306 } | |
307 } | |
308 else if (n>4) | |
309 { | |
310 area=5.0/12.0*(m_counters[0]+m_counters[n-1]) | |
311 +13.0/12.0*(m_counters[1]+m_counters[n-2]); | |
312 for (unsigned int i=2;i<n-2;i++) | |
313 { | |
314 area+=m_counters[i]; | |
315 } | |
316 } | |
317 else if (n>1) | |
318 { | |
319 area=1/2.0*(m_counters[0]+m_counters[n-1]); | |
320 for (unsigned int i=1;i<n-1;i++) | |
321 { | |
322 area+=m_counters[i]; | |
323 } | |
324 } | |
325 else | |
326 area=0; | |
327 | |
328 return area*m_step; | |
329 } | |
330 | |
331 template <class T, class TOut> | |
332 std::vector<TOut> THistogram<T,TOut>::getNormalizedHistogram() const | |
333 { | |
334 std::vector<TOut> normCounters( m_counters.size()); | |
335 TOut area = (TOut)getArea(); | |
336 | |
337 for (unsigned int i = 0;i<m_counters.size(); i++) | |
338 { | |
339 normCounters[i]= (TOut)m_counters[i]/area; | |
340 } | |
341 | |
342 return normCounters; | |
343 }; | |
344 | |
345 template <class T, class TOut> | |
346 void THistogram<T,TOut>::getMoments(const std::vector<T>& data, TOut& ave, TOut& adev, TOut& sdev, TOut& var, TOut& skew, TOut& kurt) | |
347 { | |
348 int j; | |
349 double ep=0.0,s,p; | |
350 const size_t n = data.size(); | |
351 | |
352 if (n <= 1) | |
353 // nrerror("n must be at least 2 in moment"); | |
354 return; | |
355 | |
356 s=0.0; // First pass to get the mean. | |
357 for (j=0;j<n;j++) | |
358 s += data[j]; | |
359 | |
360 ave=s/(n); | |
361 adev=var=skew=kurt=0.0; | |
362 /* Second pass to get the first (absolute), second, | |
363 third, and fourth moments of the | |
364 deviation from the mean. */ | |
365 | |
366 for (j=0;j<n;j++) | |
367 { | |
368 adev += fabs(s=data[j]-(ave)); | |
369 ep += s; | |
370 var += (p=s*s); | |
371 skew += (p *= s); | |
372 kurt += (p *= s); | |
373 } | |
374 | |
375 | |
376 adev /= n; | |
377 var=(var-ep*ep/n)/(n-1); // Corrected two-pass formula. | |
378 sdev=sqrt(var); // Put the pieces together according to the conventional definitions. | |
379 if (var) | |
380 { | |
381 skew /= (n*(var)*(sdev)); | |
382 kurt=(kurt)/(n*(var)*(var))-3.0; | |
383 } | |
384 else | |
385 //nrerror("No skew/kurtosis when variance = 0 (in moment)"); | |
386 return; | |
387 } | |
388 | |
389 #endif | |
390 |