Click here to Skip to main content
15,885,546 members
Articles / Desktop Programming / MFC

Exocortex.DSP

Rate me:
Please Sign up or sign in to vote.
4.86/5 (17 votes)
25 Apr 2002BSD1 min read 156.3K   1.2K   42  
A C# complex number and FFT library.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;


namespace Exocortex.DSP {

	/// <summary>
	/// <p>A single-precision complex number representation.</p>
	/// <p>Comments? Questions? Bugs? Tell Ben Houston at ben@exocortex.org</p>
	/// <p>Version: March 22, 2002</p>
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	public struct ComplexF : IComparable, ICloneable {

		//-----------------------------------------------------------------------------------
		//-----------------------------------------------------------------------------------

		/// <summary>
		/// The real component of the complex number
		/// </summary>
		public float Re;

		/// <summary>
		/// The imaginary component of the complex number
		/// </summary>
		public float Im;

		//-----------------------------------------------------------------------------------
		//-----------------------------------------------------------------------------------

		/// <summary>
		/// Create a complex number from a real and an imaginary component
		/// </summary>
		/// <param name="real"></param>
		/// <param name="imaginary"></param>
		public ComplexF( float real, float imaginary ) {
			this.Re		= (float) real;
			this.Im	= (float) imaginary;
		}

		/// <summary>
		/// Create a complex number based on an existing complex number
		/// </summary>
		/// <param name="c"></param>
		public ComplexF( ComplexF c ) {
			this.Re		= c.Re;
			this.Im	= c.Im;
		}

		/// <summary>
		/// Create a complex number from a real and an imaginary component
		/// </summary>
		/// <param name="real"></param>
		/// <param name="imaginary"></param>
		/// <returns></returns>
		static public ComplexF	FromRealImaginary( float real, float imaginary ) {
			ComplexF c;
			c.Re		= (float) real;
			c.Im = (float) imaginary;
			return c;
		}

		/// <summary>
		/// Create a complex number from a modulus (length) and an argument (radian)
		/// </summary>
		/// <param name="modulus"></param>
		/// <param name="argument"></param>
		/// <returns></returns>
		static public ComplexF	FromModulusArgument( float modulus, float argument ) {
			ComplexF c;
			c.Re		= (float)( modulus * System.Math.Cos( argument ) );
			c.Im	= (float)( modulus * System.Math.Sin( argument ) );
			return c;
		}
		
		//-----------------------------------------------------------------------------------
		//-----------------------------------------------------------------------------------

		object	ICloneable.Clone() {
			return	new ComplexF( this );
		}
		/// <summary>
		/// Clone the complex number
		/// </summary>
		/// <returns></returns>
		public ComplexF	Clone() {
			return	new ComplexF( this );
		}
		
		//-----------------------------------------------------------------------------------
		//-----------------------------------------------------------------------------------

		/// <summary>
		/// The modulus (length) of the complex number
		/// </summary>
		/// <returns></returns>
		public float	GetModulus() {
			float	x	= this.Re;
			float	y	= this.Im;
			return	(float) Math.Sqrt( x*x + y*y );
		}

		/// <summary>
		/// The squared modulus (length^2) of the complex number
		/// </summary>
		/// <returns></returns>
		public float	GetModulusSquared() {
			float	x	= this.Re;
			float	y	= this.Im;
			return	(float) x*x + y*y;
		}

		/// <summary>
		/// The argument (radians) of the complex number
		/// </summary>
		/// <returns></returns>
		public float	GetArgument() {
			return (float) Math.Atan2( this.Im, this.Re );
		}

		//-----------------------------------------------------------------------------------

		/// <summary>
		/// Get the conjugate of the complex number
		/// </summary>
		/// <returns></returns>
		public ComplexF GetConjugate() {
			return FromRealImaginary( this.Re, -this.Im );
		}

		//-----------------------------------------------------------------------------------

		/// <summary>
		/// Scale the complex number to 1.
		/// </summary>
		public void Normalize() {
			double	modulus = this.GetModulus();
			if( modulus == 0 ) {
				throw new DivideByZeroException( "Can not normalize a complex number that is zero." );
			}
			this.Re	= (float)( this.Re / modulus );
			this.Im	= (float)( this.Im / modulus );
		}

		//-----------------------------------------------------------------------------------
		//-----------------------------------------------------------------------------------

		/// <summary>
		/// Convert to a from double precision complex number to a single precison complex number
		/// </summary>
		/// <param name="c"></param>
		/// <returns></returns>
		public static explicit operator ComplexF ( Complex c ) {
			ComplexF cF;
			cF.Re	= (float) c.Re;
			cF.Im	= (float) c.Im;
			return cF;
		}
		
		/// <summary>
		/// Convert from a single precision real number to a complex number
		/// </summary>
		/// <param name="f"></param>
		/// <returns></returns>
		public static explicit operator ComplexF ( float f ) {
			ComplexF c;
			c.Re		= (float) f;
			c.Im	= (float) 0;
			return c;
		}

		/// <summary>
		/// Convert from a single precision complex to a real number
		/// </summary>
		/// <param name="c"></param>
		/// <returns></returns>
		public static explicit operator float ( ComplexF c ) {
			return (float) c.Re;
		}
		
		//-----------------------------------------------------------------------------------
		//-----------------------------------------------------------------------------------

		/// <summary>
		/// Are these two complex numbers equivalent?
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool	operator==( ComplexF a, ComplexF b ) {
			return	( a.Re == b.Re ) && ( a.Im == b.Im );
		}

		/// <summary>
		/// Are these two complex numbers different?
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool	operator!=( ComplexF a, ComplexF b ) {
			return	( a.Re != b.Re ) || ( a.Im != b.Im );
		}

		/// <summary>
		/// Get the hash code of the complex number
		/// </summary>
		/// <returns></returns>
		public override int		GetHashCode() {
			return	( this.Re.GetHashCode() ^ this.Im.GetHashCode() );
		}

		/// <summary>
		/// Is this complex number equivalent to another object?
		/// </summary>
		/// <param name="o"></param>
		/// <returns></returns>
		public override bool	Equals( object o ) {
			if( o is ComplexF ) {
				ComplexF c = (ComplexF) o;
				return   ( this == c );
			}
			return	false;
		}

		//-----------------------------------------------------------------------------------
		//-----------------------------------------------------------------------------------

		/// <summary>
		/// Compare to other complex numbers or real numbers
		/// </summary>
		/// <param name="o"></param>
		/// <returns></returns>
		public int	CompareTo( object o ) {
			if( o is ComplexF ) {
				return	this.GetModulus().CompareTo( ((ComplexF)o).GetModulus() );
			}
			if( o is float ) {
				return	this.GetModulus().CompareTo( (float)o );
			}
			if( o is Complex ) {
				return	this.GetModulus().CompareTo( ((Complex)o).GetModulus() );
			}
			if( o is double ) {
				return	this.GetModulus().CompareTo( (double)o );
			}
			return	0;
		}

		//-----------------------------------------------------------------------------------
		//-----------------------------------------------------------------------------------

		/// <summary>
		/// This operator doesn't do much. :-)
		/// </summary>
		/// <param name="a"></param>
		/// <returns></returns>
		public static ComplexF operator+( ComplexF a ) {
			return a;
		}

		/// <summary>
		/// Negate the complex number
		/// </summary>
		/// <param name="a"></param>
		/// <returns></returns>
		public static ComplexF operator-( ComplexF a ) {
			a.Re	= -a.Re;
			a.Im	= -a.Im;
			return a;
		}

		/// <summary>
		/// Add a complex number to a real
		/// </summary>
		/// <param name="a"></param>
		/// <param name="f"></param>
		/// <returns></returns>
		public static ComplexF operator+( ComplexF a, float f ) {
			a.Re	= (float)( a.Re + f );
			return a;
		}

		/// <summary>
		/// Add a real to a complex number
		/// </summary>
		/// <param name="f"></param>
		/// <param name="a"></param>
		/// <returns></returns>
		public static ComplexF operator+( float f, ComplexF a ) {
			a.Re	= (float)( a.Re + f );
			return a;
		}

		/// <summary>
		/// Add to complex numbers
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static ComplexF operator+( ComplexF a, ComplexF b ) {
			a.Re	= a.Re + b.Re;
			a.Im	= a.Im + b.Im;
			return a;
		}

		/// <summary>
		/// Subtract a real from a complex number
		/// </summary>
		/// <param name="a"></param>
		/// <param name="f"></param>
		/// <returns></returns>
		public static ComplexF operator-( ComplexF a, float f ) {
			a.Re	= (float)( a.Re - f );
			return a;
		}

		/// <summary>
		/// Subtract a complex number from a real
		/// </summary>
		/// <param name="f"></param>
		/// <param name="a"></param>
		/// <returns></returns>
		public static ComplexF operator-( float f, ComplexF a ) {
			a.Re	= (float)( a.Re - f );
			return a;
		}

		/// <summary>
		/// Subtract two complex numbers
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static ComplexF operator-( ComplexF a, ComplexF b ) {
			a.Re	= a.Re - b.Re;
			a.Im	= a.Im - b.Im;
			return a;
		}

		/// <summary>
		/// Multiply a complex number by a real
		/// </summary>
		/// <param name="a"></param>
		/// <param name="f"></param>
		/// <returns></returns>
		public static ComplexF operator*( ComplexF a, float f ) {
			a.Re	= (float)( a.Re * f );
			a.Im	= (float)( a.Im * f );
			return a;
		}
		
		/// <summary>
		/// Multiply a real by a complex number
		/// </summary>
		/// <param name="f"></param>
		/// <param name="a"></param>
		/// <returns></returns>
		public static ComplexF operator*( float f, ComplexF a ) {
			a.Re	= (float)( a.Re * f );
			a.Im	= (float)( a.Im * f );
			return a;
		}
		
		/// <summary>
		/// Multiply two complex numbers together
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static ComplexF operator*( ComplexF a, ComplexF b ) {
			// (x + yi)(u + vi) = (xu � yv) + (xv + yu)i. 
			double	x = a.Re, y = a.Im;
			double	u = b.Re, v = b.Im;
			a.Re	= (float)( x*u - y*v );
			a.Im	= (float)( x*v + y*u );
			return a;
		}

		/// <summary>
		/// Divide a complex number by a real number
		/// </summary>
		/// <param name="a"></param>
		/// <param name="f"></param>
		/// <returns></returns>
		public static ComplexF operator/( ComplexF a, float f ) {
			if( f == 0 ) {
				throw new DivideByZeroException();
			}
			a.Re	= (float)( a.Re / f );
			a.Im	= (float)( a.Im / f );
			return a;
		}
		
		/// <summary>
		/// Divide a complex number by a complex number
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static ComplexF operator/( ComplexF a, ComplexF b ) {
			double	x = a.Re,	y = a.Im;
			double	u = b.Re,	v = b.Im;
			double	denom = u*u + v*v;

			if( denom == 0 ) {
				throw new DivideByZeroException();
			}
			a.Re	= (float)( ( x*u + y*v ) / denom );
			a.Im	= (float)( ( y*u - x*u ) / denom );
			return a;
		}

		/// <summary>
		/// Parse a complex representation in this fashion: "( %f, %f )"
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		static public ComplexF Parse( string s ) {
			throw new NotImplementedException( "ComplexF ComplexF.Parse( string s ) is not implemented." );
		}
		
		/// <summary>
		/// Get the string representation
		/// </summary>
		/// <returns></returns>
		public override string ToString() {
			return	String.Format( "( {0}, {1}i )", this.Re, this.Im );
		}

		//-----------------------------------------------------------------------------------
		//-----------------------------------------------------------------------------------

		/// <summary>
		/// Determine whether two complex numbers are almost (i.e. within the tolerance) equivalent.
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="tolerance"></param>
		/// <returns></returns>
		static public bool IsEqual( ComplexF a, ComplexF b, float tolerance ) {
			return
				( Math.Abs( a.Re - b.Re ) < tolerance ) &&
				( Math.Abs( a.Im - b.Im ) < tolerance );

		}
		
		//----------------------------------------------------------------------------------
		//----------------------------------------------------------------------------------

		/// <summary>
		/// Represents zero
		/// </summary>
		static public ComplexF	Zero {
			get	{	return	ComplexF.FromRealImaginary( 0, 0 );	}
		}

		/// <summary>
		/// Represents the result of sqrt( -1 )
		/// </summary>
		static public ComplexF	I {
			get {	return	ComplexF.FromRealImaginary( 0, 1 );	}
		}

		/// <summary>
		/// Represents the largest possible value of ComplexF.
		/// </summary>
		static public ComplexF	MaxValue {
			get {	return	ComplexF.FromRealImaginary( float.MaxValue, float.MaxValue );	}
		}

		/// <summary>
		/// Represents the smallest possible value of ComplexF.
		/// </summary>
		static public ComplexF	MinValue {
			get {	return	ComplexF.FromRealImaginary( float.MinValue, float.MinValue );	}
		}


		//----------------------------------------------------------------------------------
		//----------------------------------------------------------------------------------
	}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Web Developer
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions