3
* Copyright (c) 2001, 2002 Ben Houston [ ben@exocortex.org ]
4
* Exocortex Technologies [ www.exocortex.org ]
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions are met:
10
* 1. Redistributions of source code must retain the above copyright notice,
11
* this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the <ORGANIZATION> nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
23
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34
using System.Diagnostics;
37
namespace Exocortex.DSP {
39
// Comments? Questions? Bugs? Tell Ben Houston at ben@exocortex.org
40
// Version: May 4, 2002
43
/// <p>A set of array utilities for complex number arrays</p>
45
public class ComplexArray {
47
//---------------------------------------------------------------------------------------------
49
private ComplexArray() {
52
//---------------------------------------------------------------------------------------------
55
/// Clamp length (modulus) of the elements in the complex array
57
/// <param name="array"></param>
58
/// <param name="fMinimum"></param>
59
/// <param name="fMaximum"></param>
60
static public void ClampLength( Complex[] array, double fMinimum, double fMaximum ) {
61
for( int i = 0; i < array.Length; i ++ ) {
62
array[i] = Complex.FromModulusArgument( Math.Max( fMinimum, Math.Min( fMaximum, array[i].GetModulus() ) ), array[i].GetArgument() );
67
/// Clamp elements in the complex array to range [minimum,maximum]
69
/// <param name="array"></param>
70
/// <param name="minimum"></param>
71
/// <param name="maximum"></param>
72
static public void Clamp( Complex[] array, Complex minimum, Complex maximum ) {
73
for( int i = 0; i < array.Length; i ++ ) {
74
array[i].Re = Math.Min( Math.Max( array[ i ].Re, minimum.Re ), maximum.Re );
75
array[i].Im = Math.Min( Math.Max( array[ i ].Re, minimum.Im ), maximum.Im );
80
/// Clamp elements in the complex array to real unit range (i.e. [0,1])
82
/// <param name="array"></param>
83
static public void ClampToRealUnit( Complex[] array ) {
84
for( int i = 0; i < array.Length; i ++ ) {
85
array[i].Re = Math.Min( Math.Max( array[i].Re, 0 ), 1 );
90
//---------------------------------------------------------------------------------------------
92
static private bool _workspaceFLocked = false;
93
static private ComplexF[] _workspaceF = new ComplexF[ 0 ];
95
static private void LockWorkspaceF( int length, ref ComplexF[] workspace ) {
96
Debug.Assert( _workspaceFLocked == false );
97
_workspaceFLocked = true;
98
if( length >= _workspaceF.Length ) {
99
_workspaceF = new ComplexF[ length ];
101
workspace = _workspaceF;
103
static private void UnlockWorkspaceF( ref ComplexF[] workspace ) {
104
Debug.Assert( _workspaceF == workspace );
105
Debug.Assert( _workspaceFLocked == true );
106
_workspaceFLocked = false;
110
//---------------------------------------------------------------------------------------------
113
/// Shift (offset) the elements in the array
115
/// <param name="array"></param>
116
/// <param name="offset"></param>
117
static public void Shift( Complex[] array, int offset ) {
118
Debug.Assert( array != null );
119
Debug.Assert( offset >= 0 );
120
Debug.Assert( offset < array.Length );
126
int length = array.Length;
127
Complex[] temp = new Complex[ length ];
129
for( int i = 0; i < length; i ++ ) {
130
temp[ ( i + offset ) % length ] = array[ i ];
132
for( int i = 0; i < length; i ++ ) {
133
array[ i ] = temp[ i ];
138
/// Shift (offset) the elements in the array
140
/// <param name="array"></param>
141
/// <param name="offset"></param>
142
static public void Shift( ComplexF[] array, int offset ) {
143
Debug.Assert( array != null );
144
Debug.Assert( offset >= 0 );
145
Debug.Assert( offset < array.Length );
151
int length = array.Length;
152
ComplexF[] workspace = null;
153
ComplexArray.LockWorkspaceF( length, ref workspace );
155
for( int i = 0; i < length; i ++ ) {
156
workspace[ ( i + offset ) % length ] = array[ i ];
158
for( int i = 0; i < length; i ++ ) {
159
array[ i ] = workspace[ i ];
162
ComplexArray.UnlockWorkspaceF( ref workspace );
165
//---------------------------------------------------------------------------------------------
168
/// Get the range of element lengths
170
/// <param name="array"></param>
171
/// <param name="minimum"></param>
172
/// <param name="maximum"></param>
173
static public void GetLengthRange( Complex[] array, ref double minimum, ref double maximum ) {
174
minimum = +double.MaxValue;
175
maximum = -double.MaxValue;
176
for( int i = 0; i < array.Length; i ++ ) {
177
double temp = array[i].GetModulus();
178
minimum = Math.Min( temp, minimum );
179
maximum = Math.Max( temp, maximum );
183
/// Get the range of element lengths
185
/// <param name="array"></param>
186
/// <param name="minimum"></param>
187
/// <param name="maximum"></param>
188
static public void GetLengthRange( ComplexF[] array, ref float minimum, ref float maximum ) {
189
minimum = +float.MaxValue;
190
maximum = -float.MaxValue;
191
for( int i = 0; i < array.Length; i ++ ) {
192
float temp = array[i].GetModulus();
193
minimum = Math.Min( temp, minimum );
194
maximum = Math.Max( temp, maximum );
199
// // Conver the complex array to a double array
201
// // <param name="array"></param>
202
// // <param name="style"></param>
203
// // <returns></returns>
204
/* static public double[] ConvertToDoubleArray( Complex[] array, ConversionStyle style ) {
205
double[] newArray = new double[ array.Length ];
207
case ConversionStyle.Length:
208
for( int i = 0; i < array.Length; i ++ ) {
209
newArray[i] = (double) array[i].GetModulus();
212
case ConversionStyle.Real:
213
for( int i = 0; i < array.Length; i ++ ) {
214
newArray[i] = (double) array[i].Re;
217
case ConversionStyle.Imaginary:
218
for( int i = 0; i < array.Length; i ++ ) {
219
newArray[i] = (double) array[i].Im;
223
Debug.Assert( false );
229
//---------------------------------------------------------------------------------------------
232
/// Determine whether the elements in the two arrays are the same
234
/// <param name="array1"></param>
235
/// <param name="array2"></param>
236
/// <param name="tolerance"></param>
237
/// <returns></returns>
238
static public bool IsEqual( Complex[] array1, Complex[] array2, double tolerance ) {
239
if ( array1.Length != array2.Length ) {
242
for( int i = 0; i < array1.Length; i ++ ) {
243
if( Complex.IsEqual( array1[i], array2[i], tolerance ) == false ) {
251
/// Determine whether the elements in the two arrays are the same
253
/// <param name="array1"></param>
254
/// <param name="array2"></param>
255
/// <param name="tolerance"></param>
256
/// <returns></returns>
257
static public bool IsEqual( ComplexF[] array1, ComplexF[] array2, float tolerance ) {
258
if ( array1.Length != array2.Length ) {
261
for( int i = 0; i < array1.Length; i ++ ) {
262
if( ComplexF.IsEqual( array1[i], array2[i], tolerance ) == false ) {
269
//---------------------------------------------------------------------------------------------
272
/// Add a specific value to each element in the array
274
/// <param name="array"></param>
275
/// <param name="offset"></param>
276
static public void Offset( Complex[] array, double offset ) {
277
int length = array.Length;
278
for( int i = 0; i < length; i ++ ) {
279
array[i].Re += offset;
284
/// Add a specific value to each element in the array
286
/// <param name="array"></param>
287
/// <param name="offset"></param>
288
static public void Offset( Complex[] array, Complex offset ) {
289
int length = array.Length;
290
for( int i = 0; i < length; i ++ ) {
296
/// Add a specific value to each element in the array
298
/// <param name="array"></param>
299
/// <param name="offset"></param>
300
static public void Offset( ComplexF[] array, float offset ) {
301
int length = array.Length;
302
for( int i = 0; i < length; i ++ ) {
303
array[i].Re += offset;
308
/// Add a specific value to each element in the array
310
/// <param name="array"></param>
311
/// <param name="offset"></param>
312
static public void Offset( ComplexF[] array, ComplexF offset ) {
313
int length = array.Length;
314
for( int i = 0; i < length; i ++ ) {
319
//---------------------------------------------------------------------------------------------
322
/// Multiply each element in the array by a specific value
324
/// <param name="array"></param>
325
/// <param name="scale"></param>
326
static public void Scale( Complex[] array, double scale ) {
327
Debug.Assert( array != null );
329
int length = array.Length;
330
for( int i = 0; i < length; i ++ ) {
335
/// Multiply each element in the array by a specific value
337
/// <param name="array"></param>
338
/// <param name="scale"></param>
339
/// <param name="start"></param>
340
/// <param name="length"></param>
341
static public void Scale( Complex[] array, double scale, int start, int length ) {
342
Debug.Assert( array != null );
343
Debug.Assert( start >= 0 );
344
Debug.Assert( length >= 0 );
345
Debug.Assert( ( start + length ) < array.Length );
347
for( int i = 0; i < length; i ++ ) {
348
array[i + start] *= scale;
353
/// Multiply each element in the array by a specific value
355
/// <param name="array"></param>
356
/// <param name="scale"></param>
357
static public void Scale( Complex[] array, Complex scale ) {
358
Debug.Assert( array != null );
360
int length = array.Length;
361
for( int i = 0; i < length; i ++ ) {
366
/// Multiply each element in the array by a specific value
368
/// <param name="array"></param>
369
/// <param name="scale"></param>
370
/// <param name="start"></param>
371
/// <param name="length"></param>
372
static public void Scale( Complex[] array, Complex scale, int start, int length ) {
373
Debug.Assert( array != null );
374
Debug.Assert( start >= 0 );
375
Debug.Assert( length >= 0 );
376
Debug.Assert( ( start + length ) < array.Length );
378
for( int i = 0; i < length; i ++ ) {
379
array[i + start] *= scale;
384
/// Multiply each element in the array by a specific value
386
/// <param name="array"></param>
387
/// <param name="scale"></param>
388
static public void Scale( ComplexF[] array, float scale ) {
389
Debug.Assert( array != null );
391
int length = array.Length;
392
for( int i = 0; i < length; i ++ ) {
397
/// Multiply each element in the array by a specific value
399
/// <param name="array"></param>
400
/// <param name="scale"></param>
401
/// <param name="start"></param>
402
/// <param name="length"></param>
403
static public void Scale( ComplexF[] array, float scale, int start, int length ) {
404
Debug.Assert( array != null );
405
Debug.Assert( start >= 0 );
406
Debug.Assert( length >= 0 );
407
Debug.Assert( ( start + length ) < array.Length );
409
for( int i = 0; i < length; i ++ ) {
410
array[i + start] *= scale;
415
/// Multiply each element in the array by a specific value
417
/// <param name="array"></param>
418
/// <param name="scale"></param>
419
static public void Scale( ComplexF[] array, ComplexF scale ) {
420
Debug.Assert( array != null );
422
int length = array.Length;
423
for( int i = 0; i < length; i ++ ) {
428
/// Multiply each element in the array by a specific value
430
/// <param name="array"></param>
431
/// <param name="scale"></param>
432
/// <param name="start"></param>
433
/// <param name="length"></param>
434
static public void Scale( ComplexF[] array, ComplexF scale, int start, int length ) {
435
Debug.Assert( array != null );
436
Debug.Assert( start >= 0 );
437
Debug.Assert( length >= 0 );
438
Debug.Assert( ( start + length ) < array.Length );
440
for( int i = 0; i < length; i ++ ) {
441
array[i + start] *= scale;
445
//---------------------------------------------------------------------------------------------
448
/// Multiply each element in target array with corresponding element in rhs array
450
/// <param name="target"></param>
451
/// <param name="rhs"></param>
452
static public void Multiply( Complex[] target, Complex[] rhs ) {
453
ComplexArray.Multiply( target, rhs, target );
456
/// Multiply each element in lhs array with corresponding element in rhs array and
457
/// put product in result array
459
/// <param name="lhs"></param>
460
/// <param name="rhs"></param>
461
/// <param name="result"></param>
462
static public void Multiply( Complex[] lhs, Complex[] rhs, Complex[] result ) {
463
Debug.Assert( lhs != null );
464
Debug.Assert( rhs != null );
465
Debug.Assert( result != null );
466
Debug.Assert( lhs.Length == rhs.Length );
467
Debug.Assert( lhs.Length == result.Length );
469
int length = lhs.Length;
470
for( int i = 0; i < length; i ++ ) {
471
result[i] = lhs[i] * rhs[i];
476
/// Multiply each element in target array with corresponding element in rhs array
478
/// <param name="target"></param>
479
/// <param name="rhs"></param>
480
static public void Multiply( ComplexF[] target, ComplexF[] rhs ) {
481
ComplexArray.Multiply( target, rhs, target );
484
/// Multiply each element in lhs array with corresponding element in rhs array and
485
/// put product in result array
487
/// <param name="lhs"></param>
488
/// <param name="rhs"></param>
489
/// <param name="result"></param>
490
static public void Multiply( ComplexF[] lhs, ComplexF[] rhs, ComplexF[] result ) {
491
Debug.Assert( lhs != null );
492
Debug.Assert( rhs != null );
493
Debug.Assert( result != null );
494
Debug.Assert( lhs.Length == rhs.Length );
495
Debug.Assert( lhs.Length == result.Length );
497
int length = lhs.Length;
498
for( int i = 0; i < length; i ++ ) {
499
result[i] = lhs[i] * rhs[i];
503
//---------------------------------------------------------------------------------------------
506
/// Divide each element in target array with corresponding element in rhs array
508
/// <param name="target"></param>
509
/// <param name="rhs"></param>
510
static public void Divide( Complex[] target, Complex[] rhs ) {
511
ComplexArray.Divide( target, rhs, target );
514
/// Divide each element in lhs array with corresponding element in rhs array and
515
/// put product in result array
517
/// <param name="lhs"></param>
518
/// <param name="rhs"></param>
519
/// <param name="result"></param>
520
static public void Divide( Complex[] lhs, Complex[] rhs, Complex[] result ) {
521
Debug.Assert( lhs != null );
522
Debug.Assert( rhs != null );
523
Debug.Assert( result != null );
524
Debug.Assert( lhs.Length == rhs.Length );
525
Debug.Assert( lhs.Length == result.Length );
527
int length = lhs.Length;
528
for( int i = 0; i < length; i ++ ) {
529
result[i] = lhs[i] / rhs[i];
534
/// Divide each element in target array with corresponding element in rhs array
536
/// <param name="target"></param>
537
/// <param name="rhs"></param>
538
static public void Divide( ComplexF[] target, ComplexF[] rhs ) {
539
ComplexArray.Divide( target, rhs, target );
542
/// Divide each element in lhs array with corresponding element in rhs array and
543
/// put product in result array
545
/// <param name="lhs"></param>
546
/// <param name="rhs"></param>
547
/// <param name="result"></param>
548
static public void Divide( ComplexF[] lhs, ComplexF[] rhs, ComplexF[] result ) {
549
Debug.Assert( lhs != null );
550
Debug.Assert( rhs != null );
551
Debug.Assert( result != null );
552
Debug.Assert( lhs.Length == rhs.Length );
553
Debug.Assert( lhs.Length == result.Length );
555
ComplexF zero = ComplexF.Zero;
556
int length = lhs.Length;
557
for( int i = 0; i < length; i ++ ) {
558
if( rhs[i] != zero ) {
559
result[i] = lhs[i] / rhs[i];
567
//---------------------------------------------------------------------------------------------
569
/*static public void Flip( ComplexF[] array, Size3 size ) {
570
Debug.Assert( array != null );
572
ComplexF[] workspace = null;
573
ComplexArray.LockWorkspaceF( size.GetTotalLength(), ref workspace );
575
for( int z = 0; z < size.Depth; z ++ ) {
576
for( int y = 0; y < size.Height; y ++ ) {
577
int xyzOffset = 0 + y * size.Width + z * size.Width * size.Height;
578
int abcOffset = size.Width - 1 + ( size.Height - y - 1 ) * size.Width + ( size.Depth - z - 1 ) * size.Width * size.Height;
579
for( int x = 0; x < size.Width; x ++ ) {
580
workspace[ xyzOffset ++ ] = array[ abcOffset -- ];
585
for( int i = 0; i < size.GetTotalLength(); i ++ ) {
586
array[ i ] = workspace[ i ];
589
ComplexArray.UnlockWorkspaceF( ref workspace );
596
/// <param name="dest"></param>
597
/// <param name="source"></param>
598
static public void Copy( Complex[] dest, Complex[] source ) {
599
Debug.Assert( dest != null );
600
Debug.Assert( source != null );
601
Debug.Assert( dest.Length == source.Length );
602
for( int i = 0; i < dest.Length; i ++ ) {
610
/// <param name="dest"></param>
611
/// <param name="source"></param>
612
static public void Copy( ComplexF[] dest, ComplexF[] source ) {
613
Debug.Assert( dest != null );
614
Debug.Assert( source != null );
615
Debug.Assert( dest.Length == source.Length );
616
for( int i = 0; i < dest.Length; i ++ ) {
622
/// Reverse the elements in the array
624
/// <param name="array"></param>
625
static public void Reverse( Complex[] array ) {
627
int length = array.Length;
628
for( int i = 0; i < length/2; i ++ ) {
630
array[i] = array[length-1-i];
631
array[length-1-i] = temp;
636
/// Scale and offset the elements in the array so that the
637
/// overall range is [0, 1]
639
/// <param name="array"></param>
640
static public void Normalize( Complex[] array ) {
641
double min = 0, max = 0;
642
GetLengthRange( array, ref min, ref max );
643
Scale( array, ( 1 / ( max - min ) ) );
644
Offset( array, ( - min / ( max - min ) ) );
648
/// Scale and offset the elements in the array so that the
649
/// overall range is [0, 1]
651
/// <param name="array"></param>
652
static public void Normalize( ComplexF[] array ) {
653
float min = 0, max = 0;
654
GetLengthRange( array, ref min, ref max );
655
Scale( array, ( 1 / ( max - min ) ) );
656
Offset( array, ( - min / ( max - min ) ) );
660
/// Invert each element in the array
662
/// <param name="array"></param>
663
static public void Invert( Complex[] array ) {
664
for( int i = 0; i < array.Length; i ++ ) {
665
array[i] = ((Complex) 1 ) / array[i];
670
/// Invert each element in the array
672
/// <param name="array"></param>
673
static public void Invert( ComplexF[] array ) {
674
for( int i = 0; i < array.Length; i ++ ) {
675
array[i] = ((ComplexF) 1 ) / array[i];
679
//----------------------------------------------------------------------------------------