3 * Copyright (c) 2001, 2002 Ben Houston [ ben@exocortex.org ]
\r
4 * Exocortex Technologies [ www.exocortex.org ]
\r
5 * All rights reserved.
\r
7 * Redistribution and use in source and binary forms, with or without
\r
8 * modification, are permitted provided that the following conditions are met:
\r
10 * 1. Redistributions of source code must retain the above copyright notice,
\r
11 * this list of conditions and the following disclaimer.
\r
12 * 2. Redistributions in binary form must reproduce the above copyright
\r
13 * notice, this list of conditions and the following disclaimer in the
\r
14 * documentation and/or other materials provided with the distribution.
\r
15 * 3. Neither the name of the <ORGANIZATION> nor the names of its contributors
\r
16 * may be used to endorse or promote products derived from this software
\r
17 * without specific prior written permission.
\r
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
\r
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
\r
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
\r
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
\r
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\r
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
\r
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
\r
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
\r
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
\r
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
\r
33 using System.Diagnostics;
\r
35 namespace Exocortex.DSP
\r
37 // Comments? Questions? Bugs? Tell Ben Houston at ben@exocortex.org
\r
38 // Version: May 4, 2002
\r
41 /// <p>A set of statistical utilities for complex number arrays</p>
\r
43 public class ComplexStats
\r
45 //---------------------------------------------------------------------------------------------
\r
47 private ComplexStats() {
\r
50 //---------------------------------------------------------------------------------------------
\r
51 //--------------------------------------------------------------------------------------------
\r
54 /// Calculate the sum
\r
56 /// <param name="data"></param>
\r
57 /// <returns></returns>
\r
58 static public ComplexF Sum( ComplexF[] data ) {
\r
59 Debug.Assert( data != null );
\r
60 return SumRecursion( data, 0, data.Length );
\r
62 static private ComplexF SumRecursion( ComplexF[] data, int start, int end ) {
\r
63 Debug.Assert( 0 <= start, "start = " + start );
\r
64 Debug.Assert( start < end, "start = " + start + " and end = " + end );
\r
65 Debug.Assert( end <= data.Length, "end = " + end + " and data.Length = " + data.Length );
\r
66 if( ( end - start ) <= 1000 ) {
\r
67 ComplexF sum = ComplexF.Zero;
\r
68 for( int i = start; i < end; i ++ ) {
\r
75 int middle = ( start + end ) >> 1;
\r
76 return SumRecursion( data, start, middle ) + SumRecursion( data, middle, end );
\r
81 /// Calculate the sum
\r
83 /// <param name="data"></param>
\r
84 /// <returns></returns>
\r
85 static public Complex Sum( Complex[] data ) {
\r
86 Debug.Assert( data != null );
\r
87 return SumRecursion( data, 0, data.Length );
\r
89 static private Complex SumRecursion( Complex[] data, int start, int end ) {
\r
90 Debug.Assert( 0 <= start, "start = " + start );
\r
91 Debug.Assert( start < end, "start = " + start + " and end = " + end );
\r
92 Debug.Assert( end <= data.Length, "end = " + end + " and data.Length = " + data.Length );
\r
93 if( ( end - start ) <= 1000 ) {
\r
94 Complex sum = Complex.Zero;
\r
95 for( int i = start; i < end; i ++ ) {
\r
102 int middle = ( start + end ) >> 1;
\r
103 return SumRecursion( data, start, middle ) + SumRecursion( data, middle, end );
\r
107 //--------------------------------------------------------------------------------------------
\r
108 //--------------------------------------------------------------------------------------------
\r
111 /// Calculate the sum of squares
\r
113 /// <param name="data"></param>
\r
114 /// <returns></returns>
\r
115 static public ComplexF SumOfSquares( ComplexF[] data ) {
\r
116 Debug.Assert( data != null );
\r
117 return SumOfSquaresRecursion( data, 0, data.Length );
\r
119 static private ComplexF SumOfSquaresRecursion( ComplexF[] data, int start, int end ) {
\r
120 Debug.Assert( 0 <= start, "start = " + start );
\r
121 Debug.Assert( start < end, "start = " + start + " and end = " + end );
\r
122 Debug.Assert( end <= data.Length, "end = " + end + " and data.Length = " + data.Length );
\r
123 if( ( end - start ) <= 1000 ) {
\r
124 ComplexF sumOfSquares = ComplexF.Zero;
\r
125 for( int i = start; i < end; i ++ ) {
\r
126 sumOfSquares += data[ i ] * data[ i ];
\r
129 return sumOfSquares;
\r
132 int middle = ( start + end ) >> 1;
\r
133 return SumOfSquaresRecursion( data, start, middle ) + SumOfSquaresRecursion( data, middle, end );
\r
138 /// Calculate the sum of squares
\r
140 /// <param name="data"></param>
\r
141 /// <returns></returns>
\r
142 static public Complex SumOfSquares( Complex[] data ) {
\r
143 Debug.Assert( data != null );
\r
144 return SumOfSquaresRecursion( data, 0, data.Length );
\r
146 static private Complex SumOfSquaresRecursion( Complex[] data, int start, int end ) {
\r
147 Debug.Assert( 0 <= start, "start = " + start );
\r
148 Debug.Assert( start < end, "start = " + start + " and end = " + end );
\r
149 Debug.Assert( end <= data.Length, "end = " + end + " and data.Length = " + data.Length );
\r
150 if( ( end - start ) <= 1000 ) {
\r
151 Complex sumOfSquares = Complex.Zero;
\r
152 for( int i = start; i < end; i ++ ) {
\r
153 sumOfSquares += data[ i ] * data[ i ];
\r
156 return sumOfSquares;
\r
159 int middle = ( start + end ) >> 1;
\r
160 return SumOfSquaresRecursion( data, start, middle ) + SumOfSquaresRecursion( data, middle, end );
\r
164 //--------------------------------------------------------------------------------------------
\r
165 //--------------------------------------------------------------------------------------------
\r
168 /// Calculate the mean (average)
\r
170 /// <param name="data"></param>
\r
171 /// <returns></returns>
\r
172 static public ComplexF Mean( ComplexF[] data ) {
\r
173 return ComplexStats.Sum( data ) / data.Length;
\r
177 /// Calculate the mean (average)
\r
179 /// <param name="data"></param>
\r
180 /// <returns></returns>
\r
181 static public Complex Mean( Complex[] data ) {
\r
182 return ComplexStats.Sum( data ) / data.Length;
\r
186 /// Calculate the variance
\r
188 /// <param name="data"></param>
\r
189 /// <returns></returns>
\r
190 static public ComplexF Variance( ComplexF[] data ) {
\r
191 Debug.Assert( data != null );
\r
192 if( data.Length == 0 ) {
\r
193 throw new DivideByZeroException( "length of data is zero" );
\r
195 return ComplexStats.SumOfSquares( data ) / data.Length - ComplexStats.Sum( data );
\r
198 /// Calculate the variance
\r
200 /// <param name="data"></param>
\r
201 /// <returns></returns>
\r
202 static public Complex Variance( Complex[] data ) {
\r
203 Debug.Assert( data != null );
\r
204 if( data.Length == 0 ) {
\r
205 throw new DivideByZeroException( "length of data is zero" );
\r
207 return ComplexStats.SumOfSquares( data ) / data.Length - ComplexStats.Sum( data );
\r
211 /// Calculate the standard deviation
\r
213 /// <param name="data"></param>
\r
214 /// <returns></returns>
\r
215 static public ComplexF StdDev( ComplexF[] data ) {
\r
216 Debug.Assert( data != null );
\r
217 if( data.Length == 0 ) {
\r
218 throw new DivideByZeroException( "length of data is zero" );
\r
220 return ComplexMath.Sqrt( ComplexStats.Variance( data ) );
\r
223 /// Calculate the standard deviation
\r
225 /// <param name="data"></param>
\r
226 /// <returns></returns>
\r
227 static public Complex StdDev( Complex[] data ) {
\r
228 Debug.Assert( data != null );
\r
229 if( data.Length == 0 ) {
\r
230 throw new DivideByZeroException( "length of data is zero" );
\r
232 return ComplexMath.Sqrt( ComplexStats.Variance( data ) );
\r
235 //--------------------------------------------------------------------------------------------
\r
236 //--------------------------------------------------------------------------------------------
\r
239 /// Calculate the root mean squared (RMS) error between two sets of data.
\r
241 /// <param name="alpha"></param>
\r
242 /// <param name="beta"></param>
\r
243 /// <returns></returns>
\r
244 static public float RMSError( ComplexF[] alpha, ComplexF[] beta ) {
\r
245 Debug.Assert( alpha != null );
\r
246 Debug.Assert( beta != null );
\r
247 Debug.Assert( beta.Length == alpha.Length );
\r
249 return (float) Math.Sqrt( SumOfSquaredErrorRecursion( alpha, beta, 0, alpha.Length ) );
\r
251 static private float SumOfSquaredErrorRecursion( ComplexF[] alpha, ComplexF[] beta, int start, int end ) {
\r
252 Debug.Assert( 0 <= start, "start = " + start );
\r
253 Debug.Assert( start < end, "start = " + start + " and end = " + end );
\r
254 Debug.Assert( end <= alpha.Length, "end = " + end + " and alpha.Length = " + alpha.Length );
\r
255 Debug.Assert( beta.Length == alpha.Length );
\r
256 if( ( end - start ) <= 1000 ) {
\r
257 float sumOfSquaredError = 0;
\r
258 for( int i = start; i < end; i ++ ) {
\r
259 ComplexF delta = beta[ i ] - alpha[ i ];
\r
260 sumOfSquaredError += ( delta.Re * delta.Re ) + ( delta.Im * delta.Im );
\r
263 return sumOfSquaredError;
\r
266 int middle = ( start + end ) >> 1;
\r
267 return SumOfSquaredErrorRecursion( alpha, beta, start, middle ) + SumOfSquaredErrorRecursion( alpha, beta, middle, end );
\r
272 /// Calculate the root mean squared (RMS) error between two sets of data.
\r
274 /// <param name="alpha"></param>
\r
275 /// <param name="beta"></param>
\r
276 /// <returns></returns>
\r
277 static public double RMSError( Complex[] alpha, Complex[] beta ) {
\r
278 Debug.Assert( alpha != null );
\r
279 Debug.Assert( beta != null );
\r
280 Debug.Assert( beta.Length == alpha.Length );
\r
282 return Math.Sqrt( SumOfSquaredErrorRecursion( alpha, beta, 0, alpha.Length ) );
\r
284 static private double SumOfSquaredErrorRecursion( Complex[] alpha, Complex[] beta, int start, int end ) {
\r
285 Debug.Assert( 0 <= start, "start = " + start );
\r
286 Debug.Assert( start < end, "start = " + start + " and end = " + end );
\r
287 Debug.Assert( end <= alpha.Length, "end = " + end + " and alpha.Length = " + alpha.Length );
\r
288 Debug.Assert( beta.Length == alpha.Length );
\r
289 if( ( end - start ) <= 1000 ) {
\r
290 double sumOfSquaredError = 0;
\r
291 for( int i = start; i < end; i ++ ) {
\r
292 Complex delta = beta[ i ] - alpha[ i ];
\r
293 sumOfSquaredError += ( delta.Re * delta.Re ) + ( delta.Im * delta.Im );
\r
296 return sumOfSquaredError;
\r
299 int middle = ( start + end ) >> 1;
\r
300 return SumOfSquaredErrorRecursion( alpha, beta, start, middle ) + SumOfSquaredErrorRecursion( alpha, beta, middle, end );
\r