266 lines
6.8 KiB
C
266 lines
6.8 KiB
C
|
/**@file templates for Complex classes
|
||
|
unlike the built-in complex<> templates, these inline most operations for speed
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* OpenBTS provides an open source alternative to legacy telco protocols and
|
||
|
* traditionally complex, proprietary hardware systems.
|
||
|
*
|
||
|
* Copyright 2008 Free Software Foundation, Inc.
|
||
|
* Copyright 2014 Range Networks, Inc.
|
||
|
*
|
||
|
* This software is distributed under the terms of the GNU General Public
|
||
|
* License version 3. See the COPYING and NOTICE files in the current
|
||
|
* directory for licensing information.
|
||
|
*
|
||
|
* This use of this software may be subject to additional restrictions.
|
||
|
* See the LEGAL file in the main directory for details.
|
||
|
*/
|
||
|
|
||
|
#ifndef COMPLEXCPP_H
|
||
|
#define COMPLEXCPP_H
|
||
|
|
||
|
#include <math.h>
|
||
|
#include <ostream>
|
||
|
|
||
|
|
||
|
template<class Real> class Complex {
|
||
|
|
||
|
public:
|
||
|
|
||
|
Real r, i;
|
||
|
|
||
|
/**@name constructors */
|
||
|
//@{
|
||
|
/**@name from real */
|
||
|
//@{
|
||
|
Complex(Real real, Real imag) {r=real; i=imag;} // x=complex(a,b)
|
||
|
Complex(Real real) {r=real; i=0;} // x=complex(a)
|
||
|
//@}
|
||
|
/**@name from nothing */
|
||
|
//@{
|
||
|
Complex() {r=(Real)0; i=(Real)0;} // x=complex()
|
||
|
//@}
|
||
|
/**@name from other complex */
|
||
|
//@{
|
||
|
Complex(const Complex<float>& z) {r=z.r; i=z.i;} // x=complex(z)
|
||
|
Complex(const Complex<double>& z) {r=z.r; i=z.i;} // x=complex(z)
|
||
|
Complex(const Complex<long double>& z) {r=z.r; i=z.i;} // x=complex(z)
|
||
|
//@}
|
||
|
//@}
|
||
|
|
||
|
/**@name casting up from basic numeric types */
|
||
|
//@{
|
||
|
Complex& operator=(char a) { r=(Real)a; i=(Real)0; return *this; }
|
||
|
Complex& operator=(int a) { r=(Real)a; i=(Real)0; return *this; }
|
||
|
Complex& operator=(long int a) { r=(Real)a; i=(Real)0; return *this; }
|
||
|
Complex& operator=(short a) { r=(Real)a; i=(Real)0; return *this; }
|
||
|
Complex& operator=(float a) { r=(Real)a; i=(Real)0; return *this; }
|
||
|
Complex& operator=(double a) { r=(Real)a; i=(Real)0; return *this; }
|
||
|
Complex& operator=(long double a) { r=(Real)a; i=(Real)0; return *this; }
|
||
|
//@}
|
||
|
|
||
|
/**@name arithmetic */
|
||
|
//@{
|
||
|
/**@ binary operators */
|
||
|
//@{
|
||
|
Complex operator+(const Complex<Real>& a) const { return Complex<Real>(r+a.r, i+a.i); }
|
||
|
Complex operator+(Real a) const { return Complex<Real>(r+a,i); }
|
||
|
Complex operator-(const Complex<Real>& a) const { return Complex<Real>(r-a.r, i-a.i); }
|
||
|
Complex operator-(Real a) const { return Complex<Real>(r-a,i); }
|
||
|
Complex operator*(const Complex<Real>& a) const { return Complex<Real>(r*a.r-i*a.i, r*a.i+i*a.r); }
|
||
|
Complex operator*(Real a) const { return Complex<Real>(r*a, i*a); }
|
||
|
Complex operator/(const Complex<Real>& a) const { return operator*(a.inv()); }
|
||
|
Complex operator/(Real a) const { return Complex<Real>(r/a, i/a); }
|
||
|
//@}
|
||
|
/*@name component-wise product */
|
||
|
//@{
|
||
|
Complex operator&(const Complex<Real>& a) const { return Complex<Real>(r*a.r, i*a.i); }
|
||
|
//@}
|
||
|
/*@name inplace operations */
|
||
|
//@{
|
||
|
Complex& operator+=(const Complex<Real>&);
|
||
|
Complex& operator-=(const Complex<Real>&);
|
||
|
Complex& operator*=(const Complex<Real>&);
|
||
|
Complex& operator/=(const Complex<Real>&);
|
||
|
Complex& operator+=(Real);
|
||
|
Complex& operator-=(Real);
|
||
|
Complex& operator*=(Real);
|
||
|
Complex& operator/=(Real);
|
||
|
//@}
|
||
|
//@}
|
||
|
|
||
|
/**@name comparisons */
|
||
|
//@{
|
||
|
bool operator==(const Complex<Real>& a) const { return ((i==a.i)&&(r==a.r)); }
|
||
|
bool operator!=(const Complex<Real>& a) const { return ((i!=a.i)||(r!=a.r)); }
|
||
|
bool operator<(const Complex<Real>& a) const { return norm2()<a.norm2(); }
|
||
|
bool operator>(const Complex<Real>& a) const { return norm2()>a.norm2(); }
|
||
|
//@}
|
||
|
|
||
|
/// reciprocation
|
||
|
Complex inv() const;
|
||
|
|
||
|
// unary functions -- inlined
|
||
|
/**@name unary functions */
|
||
|
//@{
|
||
|
/**@name inlined */
|
||
|
//@{
|
||
|
Complex conj() const { return Complex<Real>(r,-i); }
|
||
|
Real norm2() const { return i*i+r*r; }
|
||
|
Complex flip() const { return Complex<Real>(i,r); }
|
||
|
Real real() const { return r;}
|
||
|
Real imag() const { return i;}
|
||
|
Complex neg() const { return Complex<Real>(-r, -i); }
|
||
|
bool isZero() const { return ((r==(Real)0) && (i==(Real)0)); }
|
||
|
//@}
|
||
|
/**@name not inlined due to outside calls */
|
||
|
//@{
|
||
|
Real abs() const { return ::sqrt(norm2()); }
|
||
|
Real arg() const { return ::atan2(i,r); }
|
||
|
float dB() const { return 10.0*log10(norm2()); }
|
||
|
Complex exp() const { return expj(i)*(::exp(r)); }
|
||
|
Complex unit() const; ///< unit phasor with same angle
|
||
|
Complex log() const { return Complex(::log(abs()),arg()); }
|
||
|
Complex pow(double n) const { return expj(arg()*n)*(::pow(abs(),n)); }
|
||
|
Complex sqrt() const { return pow(0.5); }
|
||
|
//@}
|
||
|
//@}
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
/**@name standard Complex manifestations */
|
||
|
//@{
|
||
|
typedef Complex<float> complex;
|
||
|
typedef Complex<double> dcomplex;
|
||
|
typedef Complex<short> complex16;
|
||
|
typedef Complex<long> complex32;
|
||
|
//@}
|
||
|
|
||
|
|
||
|
template<class Real> inline Complex<Real> Complex<Real>::inv() const
|
||
|
{
|
||
|
Real nVal;
|
||
|
|
||
|
nVal = norm2();
|
||
|
return Complex<Real>(r/nVal, -i/nVal);
|
||
|
}
|
||
|
|
||
|
template<class Real> Complex<Real>& Complex<Real>::operator+=(const Complex<Real>& a)
|
||
|
{
|
||
|
r += a.r;
|
||
|
i += a.i;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template<class Real> Complex<Real>& Complex<Real>::operator*=(const Complex<Real>& a)
|
||
|
{
|
||
|
operator*(a);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template<class Real> Complex<Real>& Complex<Real>::operator-=(const Complex<Real>& a)
|
||
|
{
|
||
|
r -= a.r;
|
||
|
i -= a.i;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template<class Real> Complex<Real>& Complex<Real>::operator/=(const Complex<Real>& a)
|
||
|
{
|
||
|
operator/(a);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* op= style operations with reals */
|
||
|
|
||
|
template<class Real> Complex<Real>& Complex<Real>::operator+=(Real a)
|
||
|
{
|
||
|
r += a;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template<class Real> Complex<Real>& Complex<Real>::operator*=(Real a)
|
||
|
{
|
||
|
r *=a;
|
||
|
i *=a;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template<class Real> Complex<Real>& Complex<Real>::operator-=(Real a)
|
||
|
{
|
||
|
r -= a;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template<class Real> Complex<Real>& Complex<Real>::operator/=(Real a)
|
||
|
{
|
||
|
r /= a;
|
||
|
i /= a;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
template<class Real> Complex<Real> Complex<Real>::unit() const
|
||
|
{
|
||
|
Real absVal = abs();
|
||
|
return (Complex<Real>(r/absVal, i/absVal));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**@name complex functions outside of the Complex<> class. */
|
||
|
//@{
|
||
|
|
||
|
/** this allows type-commutative multiplication */
|
||
|
template<class Real> Complex<Real> operator*(Real a, const Complex<Real>& z)
|
||
|
{
|
||
|
return Complex<Real>(z.r*a, z.i*a);
|
||
|
}
|
||
|
|
||
|
|
||
|
/** this allows type-commutative addition */
|
||
|
template<class Real> Complex<Real> operator+(Real a, const Complex<Real>& z)
|
||
|
{
|
||
|
return Complex<Real>(z.r+a, z.i);
|
||
|
}
|
||
|
|
||
|
|
||
|
/** this allows type-commutative subtraction */
|
||
|
template<class Real> Complex<Real> operator-(Real a, const Complex<Real>& z)
|
||
|
{
|
||
|
return Complex<Real>(z.r-a, z.i);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/// e^jphi
|
||
|
template<class Real> Complex<Real> expj(Real phi)
|
||
|
{
|
||
|
return Complex<Real>(cos(phi),sin(phi));
|
||
|
}
|
||
|
|
||
|
/// phasor expression of a complex number
|
||
|
template<class Real> Complex<Real> phasor(Real C, Real phi)
|
||
|
{
|
||
|
return (expj(phi)*C);
|
||
|
}
|
||
|
|
||
|
/// formatted stream output
|
||
|
template<class Real> std::ostream& operator<<(std::ostream& os, const Complex<Real>& z)
|
||
|
{
|
||
|
os << z.r << ' ';
|
||
|
//os << z.r << ", ";
|
||
|
//if (z.i>=0) { os << "+"; }
|
||
|
os << z.i << "j";
|
||
|
os << "\n";
|
||
|
return os;
|
||
|
}
|
||
|
|
||
|
//@}
|
||
|
|
||
|
|
||
|
#endif
|