Mercurial > hg > qm-dsp
changeset 16:2e3f5d2d62c1
* Move dsp/maths to maths ; bring PCA and HMM across from Soundbite
author | cannam |
---|---|
date | Wed, 09 Jan 2008 10:31:29 +0000 |
parents | 10c3f9df4a07 |
children | a120ac7b26b2 |
files | dsp/chromagram/ChromaProcess.cpp dsp/chromagram/Chromagram.cpp dsp/chromagram/ConstantQ.h dsp/keydetection/GetKeyMode.cpp dsp/maths/Correlation.cpp dsp/maths/Correlation.h dsp/maths/Histogram.h dsp/maths/MathAliases.h dsp/maths/MathUtilities.cpp dsp/maths/MathUtilities.h dsp/maths/Polyfit.h dsp/onsets/DetectionFunction.cpp dsp/onsets/DetectionFunction.h dsp/onsets/PeakPicking.cpp dsp/onsets/PeakPicking.h dsp/signalconditioning/DFProcess.cpp dsp/tempotracking/TempoTrack.cpp dsp/tempotracking/TempoTrack.h dsp/tonal/TCSgram.cpp hmm/hmm.c hmm/hmm.h maths/Correlation.cpp maths/Correlation.h maths/Histogram.h maths/MathAliases.h maths/MathUtilities.cpp maths/MathUtilities.h maths/Polyfit.h maths/pca/data.txt maths/pca/pca.c maths/pca/pca.h qm-dsp.pro |
diffstat | 32 files changed, 2447 insertions(+), 1215 deletions(-) [+] |
line wrap: on
line diff
--- a/dsp/chromagram/ChromaProcess.cpp Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/chromagram/ChromaProcess.cpp Wed Jan 09 10:31:29 2008 +0000 @@ -10,7 +10,7 @@ #include "ChromaProcess.h" -#include "dsp/maths/Histogram.h" +#include "maths/Histogram.h" #include <math.h> ////////////////////////////////////////////////////////////////////// // Construction/Destruction
--- a/dsp/chromagram/Chromagram.cpp Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/chromagram/Chromagram.cpp Wed Jan 09 10:31:29 2008 +0000 @@ -10,7 +10,7 @@ #include <iostream> #include <cmath> -#include "dsp/maths/MathUtilities.h" +#include "maths/MathUtilities.h" #include "Chromagram.h" //----------------------------------------------------------------------------
--- a/dsp/chromagram/ConstantQ.h Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/chromagram/ConstantQ.h Wed Jan 09 10:31:29 2008 +0000 @@ -12,8 +12,8 @@ #define CONSTANTQ_H #include <vector> -#include "dsp/maths/MathAliases.h" -#include "dsp/maths/MathUtilities.h" +#include "maths/MathAliases.h" +#include "maths/MathUtilities.h" struct CQConfig{ unsigned int FS;
--- a/dsp/keydetection/GetKeyMode.cpp Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/keydetection/GetKeyMode.cpp Wed Jan 09 10:31:29 2008 +0000 @@ -3,7 +3,7 @@ ////////////////////////////////////////////////////////////////////// #include "GetKeyMode.h" -#include "dsp/maths/MathUtilities.h" +#include "maths/MathUtilities.h" #include "base/Pitch.h" #include <iostream>
--- a/dsp/maths/Correlation.cpp Wed Nov 21 16:53:51 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - QM DSP Library - - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2005-2006 Christian Landone. - All rights reserved. -*/ - -#include "Correlation.h" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -Correlation::Correlation() -{ - -} - -Correlation::~Correlation() -{ - -} - -void Correlation::doAutoUnBiased(double *src, double *dst, unsigned int length) -{ - double tmp = 0.0; - double outVal = 0.0; - - unsigned int i,j; - - for( i = 0; i < length; i++) - { - for( j = i; j < length; j++) - { - tmp += src[ j-i ] * src[ j ]; - } - - - outVal = tmp / ( length - i ); - - if( outVal <= 0 ) - dst[ i ] = EPS; - else - dst[ i ] = outVal; - - tmp = 0.0; - } -}
--- a/dsp/maths/Correlation.h Wed Nov 21 16:53:51 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - QM DSP Library - - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2005-2006 Christian Landone. - All rights reserved. -*/ - -#ifndef CORRELATION_H -#define CORRELATION_H - -#define EPS 2.2204e-016 - -class Correlation -{ -public: - void doAutoUnBiased( double* src, double* dst, unsigned int length ); - Correlation(); - virtual ~Correlation(); - -}; - -#endif //
--- a/dsp/maths/Histogram.h Wed Nov 21 16:53:51 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -// Histogram.h: interface for the THistogram class. -// -////////////////////////////////////////////////////////////////////// - - -#ifndef HISTOGRAM_H -#define HISTOGRAM_H - - -#include <valarray> - -/*! \brief A histogram class - - This class computes the histogram of a vector. - -\par Template parameters - - - T type of input data (can be any: float, double, int, UINT, etc...) - - TOut type of output data: float or double. (default is double) - -\par Moments: - - The moments (average, standard deviation, skewness, etc.) are computed using -the algorithm of the Numerical recipies (see Numerical recipies in C, Chapter 14.1, pg 613). - -\par Example: - - This example shows the typical use of the class: -\code - // a vector containing the data - vector<float> data; - // Creating histogram using float data and with 101 containers, - THistogram<float> histo(101); - // computing the histogram - histo.compute(data); -\endcode - -Once this is done, you can get a vector with the histogram or the normalized histogram (such that it's area is 1): -\code - // getting normalized histogram - vector<float> v=histo.getNormalizedHistogram(); -\endcode - -\par Reference - - Equally spaced acsissa function integration (used in #GetArea): Numerical Recipies in C, Chapter 4.1, pg 130. - -\author Jonathan de Halleux, dehalleux@auto.ucl.ac.be, 2002 -*/ - -template<class T, class TOut = double> -class THistogram -{ -public: - //! \name Constructors - //@{ - /*! Default constructor - \param counters the number of histogram containers (default value is 10) - */ - THistogram(unsigned int counters = 10); - virtual ~THistogram() { clear();}; - //@} - - //! \name Histogram computation, update - //@{ - /*! Computes histogram of vector v - \param v vector to compute histogram - \param computeMinMax set to true if min/max of v have to be used to get the histogram limits - - This function computes the histogram of v and stores it internally. - \sa Update, GeTHistogram - */ - void compute( const std::vector<T>& v, bool computeMinMax = true); - //! Update histogram with the vector v - void update( const std::vector<T>& v); - //! Update histogram with t - void update( const T& t); - //@} - - //! \name Resetting functions - //@{ - //! Resize the histogram. Warning this function clear the histogram. - void resize( unsigned int counters ); - //! Clears the histogram - void clear() { m_counters.clear();}; - //@} - - //! \name Setters - //@{ - /*! This function sets the minimum of the histogram spectrum. - The spectrum is not recomputed, use it with care - */ - void setMinSpectrum( const T& min ) { m_min = min; computeStep();}; - /*! This function sets the minimum of the histogram spectrum. - The spectrum is not recomputed, use it with care - */ - void setMaxSpectrum( const T& max ) { m_max = max; computeStep();}; - //@} - //! \name Getters - //@{ - //! return minimum of histogram spectrum - const T& getMinSpectrum() const { return m_min;}; - //! return maximum of histogram spectrum - const T& getMaxSpectrum() const { return m_max;}; - //! return step size of histogram containers - TOut getStep() const { return m_step;}; - //! return number of points in histogram - unsigned int getSum() const; - /*! \brief returns area under the histogram - - The Simpson rule is used to integrate the histogram. - */ - TOut getArea() const; - - /*! \brief Computes the moments of the histogram - - \param data dataset - \param ave mean - \f[ \bar x = \frac{1}{N} \sum_{j=1}^N x_j\f] - \param adev mean absolute deviation - \f[ adev(X) = \frac{1}{N} \sum_{j=1}^N | x_j - \bar x |\f] - \param var average deviation: - \f[ \mbox{Var}(X) = \frac{1}{N-1} \sum_{j=1}^N (x_j - \bar x)^2\f] - \param sdev standard deviation: - \f[ \sigma(X) = \sqrt{var(\bar x) }\f] - \param skew skewness - \f[ \mbox{Skew}(X) = \frac{1}{N}\sum_{j=1}^N \left[ \frac{x_j - \bar x}{\sigma}\right]^3\f] - \param kurt kurtosis - \f[ \mbox{Kurt}(X) = \left\{ \frac{1}{N}\sum_{j=1}^N \left[ \frac{x_j - \bar x}{\sigma}\right]^4 \right\} - 3\f] - - */ - static void getMoments(const std::vector<T>& data, TOut& ave, TOut& adev, TOut& sdev, TOut& var, TOut& skew, TOut& kurt); - - //! return number of containers - unsigned int getSize() const { return m_counters.size();}; - //! returns i-th counter - unsigned int operator [] (unsigned int i) const { -// ASSERT( i < m_counters.size() ); - return m_counters[i]; - }; - //! return the computed histogram - const std::vector<unsigned int>& geTHistogram() const { return m_counters;}; - //! return the computed histogram, in TOuts - std::vector<TOut> geTHistogramD() const; - /*! return the normalized computed histogram - - \return the histogram such that the area is equal to 1 - */ - std::vector<TOut> getNormalizedHistogram() const; - //! returns left containers position - std::vector<TOut> getLeftContainers() const; - //! returns center containers position - std::vector<TOut> getCenterContainers() const; - //@} -protected: - //! Computes the step - void computeStep() { m_step = (TOut)(((TOut)(m_max-m_min)) / (m_counters.size()-1));}; - //! Data accumulators - std::vector<unsigned int> m_counters; - //! minimum of dataset - T m_min; - //! maximum of dataset - T m_max; - //! width of container - TOut m_step; -}; - -template<class T, class TOut> -THistogram<T,TOut>::THistogram(unsigned int counters) - : m_counters(counters,0), m_min(0), m_max(0), m_step(0) -{ - -} - -template<class T, class TOut> -void THistogram<T,TOut>::resize( unsigned int counters ) -{ - clear(); - - m_counters.resize(counters,0); - - computeStep(); -} - -template<class T, class TOut> -void THistogram<T,TOut>::compute( const std::vector<T>& v, bool computeMinMax) -{ - using namespace std; - unsigned int i; - int index; - - if (m_counters.empty()) - return; - - if (computeMinMax) - { - m_max = m_min = v[0]; - for (i=1;i<v.size();i++) - { - m_max = std::max( m_max, v[i]); - m_min = std::min( m_min, v[i]); - } - } - - computeStep(); - - for (i = 0;i < v.size() ; i++) - { - index=(int) floor( ((TOut)(v[i]-m_min))/m_step ) ; - - if (index >= m_counters.size() || index < 0) - return; - - m_counters[index]++; - } -} - -template<class T, class TOut> -void THistogram<T,TOut>::update( const std::vector<T>& v) -{ - if (m_counters.empty()) - return; - - computeStep(); - - TOut size = m_counters.size(); - - int index; - for (unsigned int i = 0;i < size ; i++) - { - index = (int)floor(((TOut)(v[i]-m_min))/m_step); - - if (index >= m_counters.size() || index < 0) - return; - - m_counters[index]++; - } -} - -template<class T, class TOut> -void THistogram<T,TOut>::update( const T& t) -{ - int index=(int) floor( ((TOut)(t-m_min))/m_step ) ; - - if (index >= m_counters.size() || index < 0) - return; - - m_counters[index]++; -}; - -template<class T, class TOut> -std::vector<TOut> THistogram<T,TOut>::geTHistogramD() const -{ - std::vector<TOut> v(m_counters.size()); - for (unsigned int i = 0;i<m_counters.size(); i++) - v[i]=(TOut)m_counters[i]; - - return v; -} - -template <class T, class TOut> -std::vector<TOut> THistogram<T,TOut>::getLeftContainers() const -{ - std::vector<TOut> x( m_counters.size()); - - for (unsigned int i = 0;i<m_counters.size(); i++) - x[i]= m_min + i*m_step; - - return x; -} - -template <class T, class TOut> -std::vector<TOut> THistogram<T,TOut>::getCenterContainers() const -{ - std::vector<TOut> x( m_counters.size()); - - for (unsigned int i = 0;i<m_counters.size(); i++) - x[i]= m_min + (i+0.5)*m_step; - - return x; -} - -template <class T, class TOut> -unsigned int THistogram<T,TOut>::getSum() const -{ - unsigned int sum = 0; - for (unsigned int i = 0;i<m_counters.size(); i++) - sum+=m_counters[i]; - - return sum; -} - -template <class T, class TOut> -TOut THistogram<T,TOut>::getArea() const -{ - const size_t n=m_counters.size(); - TOut area=0; - - if (n>6) - { - area=3.0/8.0*(m_counters[0]+m_counters[n-1]) - +7.0/6.0*(m_counters[1]+m_counters[n-2]) - +23.0/24.0*(m_counters[2]+m_counters[n-3]); - for (unsigned int i=3;i<n-3;i++) - { - area+=m_counters[i]; - } - } - else if (n>4) - { - area=5.0/12.0*(m_counters[0]+m_counters[n-1]) - +13.0/12.0*(m_counters[1]+m_counters[n-2]); - for (unsigned int i=2;i<n-2;i++) - { - area+=m_counters[i]; - } - } - else if (n>1) - { - area=1/2.0*(m_counters[0]+m_counters[n-1]); - for (unsigned int i=1;i<n-1;i++) - { - area+=m_counters[i]; - } - } - else - area=0; - - return area*m_step; -} - -template <class T, class TOut> -std::vector<TOut> THistogram<T,TOut>::getNormalizedHistogram() const -{ - std::vector<TOut> normCounters( m_counters.size()); - TOut area = (TOut)getArea(); - - for (unsigned int i = 0;i<m_counters.size(); i++) - { - normCounters[i]= (TOut)m_counters[i]/area; - } - - return normCounters; -}; - -template <class T, class TOut> -void THistogram<T,TOut>::getMoments(const std::vector<T>& data, TOut& ave, TOut& adev, TOut& sdev, TOut& var, TOut& skew, TOut& kurt) -{ - int j; - double ep=0.0,s,p; - const size_t n = data.size(); - - if (n <= 1) - // nrerror("n must be at least 2 in moment"); - return; - - s=0.0; // First pass to get the mean. - for (j=0;j<n;j++) - s += data[j]; - - ave=s/(n); - adev=var=skew=kurt=0.0; - /* Second pass to get the first (absolute), second, - third, and fourth moments of the - deviation from the mean. */ - - for (j=0;j<n;j++) - { - adev += fabs(s=data[j]-(ave)); - ep += s; - var += (p=s*s); - skew += (p *= s); - kurt += (p *= s); - } - - - adev /= n; - var=(var-ep*ep/n)/(n-1); // Corrected two-pass formula. - sdev=sqrt(var); // Put the pieces together according to the conventional definitions. - if (var) - { - skew /= (n*(var)*(sdev)); - kurt=(kurt)/(n*(var)*(var))-3.0; - } - else - //nrerror("No skew/kurtosis when variance = 0 (in moment)"); - return; -} - -#endif -
--- a/dsp/maths/MathAliases.h Wed Nov 21 16:53:51 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - QM DSP Library - - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2005-2006 Christian Landone. - All rights reserved. -*/ - -#ifndef MATHALIASES_H -#define MATHALIASES_H - -#include <cmath> -#include <complex> - -using namespace std; -typedef complex<double> ComplexData; - - -#ifndef PI -#define PI (3.14159265358979232846) -#endif - -#define TWO_PI (*2.PI) - -#define EPS 2.2204e-016 - -/* aliases to math.h functions */ -#define EXP exp -#define COS cos -#define SIN sin -#define ABS fabs -#define POW powf -#define SQRT sqrtf -#define LOG10 log10f -#define LOG logf -#define FLOOR floorf -#define TRUNC truncf - -/* aliases to complex.h functions */ -/** sample = EXPC(complex) */ -#define EXPC cexpf -/** complex = CEXPC(complex) */ -#define CEXPC cexp -/** sample = ARGC(complex) */ -#define ARGC cargf -/** sample = ABSC(complex) norm */ -#define ABSC cabsf -/** sample = REAL(complex) */ -#define REAL crealf -/** sample = IMAG(complex) */ -#define IMAG cimagf - -#endif
--- a/dsp/maths/MathUtilities.cpp Wed Nov 21 16:53:51 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,221 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - QM DSP Library - - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2005-2006 Christian Landone. - All rights reserved. -*/ - -#include "MathUtilities.h" - -#include <iostream> -#include <cmath> - - -double MathUtilities::mod(double x, double y) -{ - double a = floor( x / y ); - - double b = x - ( y * a ); - return b; -} - -double MathUtilities::princarg(double ang) -{ - double ValOut; - - ValOut = mod( ang + M_PI, -2 * M_PI ) + M_PI; - - return ValOut; -} - -void MathUtilities::getAlphaNorm(const double *data, unsigned int len, unsigned int alpha, double* ANorm) -{ - unsigned int i; - double temp = 0.0; - double a=0.0; - - for( i = 0; i < len; i++) - { - temp = data[ i ]; - - a += ::pow( fabs(temp), alpha ); - } - a /= ( double )len; - a = ::pow( a, ( 1.0 / (double) alpha ) ); - - *ANorm = a; -} - -double MathUtilities::getAlphaNorm( const std::vector <double> &data, unsigned int alpha ) -{ - unsigned int i; - unsigned int len = data.size(); - double temp = 0.0; - double a=0.0; - - for( i = 0; i < len; i++) - { - temp = data[ i ]; - - a += ::pow( fabs(temp), alpha ); - } - a /= ( double )len; - a = ::pow( a, ( 1.0 / (double) alpha ) ); - - return a; -} - -double MathUtilities::round(double x) -{ - double val = (double)floor(x + 0.5); - - return val; -} - -double MathUtilities::median(const double *src, unsigned int len) -{ - unsigned int i, j; - double tmp = 0.0; - double tempMedian; - double medianVal; - - double* scratch = new double[ len ];//Vector < double > sortedX = Vector < double > ( size ); - - for ( i = 0; i < len; i++ ) - { - scratch[i] = src[i]; - } - - for ( i = 0; i < len - 1; i++ ) - { - for ( j = 0; j < len - 1 - i; j++ ) - { - if ( scratch[j + 1] < scratch[j] ) - { - // compare the two neighbors - tmp = scratch[j]; // swap a[j] and a[j+1] - scratch[j] = scratch[j + 1]; - scratch[j + 1] = tmp; - } - } - } - int middle; - if ( len % 2 == 0 ) - { - middle = len / 2; - tempMedian = ( scratch[middle] + scratch[middle - 1] ) / 2; - } - else - { - middle = ( int )floor( len / 2.0 ); - tempMedian = scratch[middle]; - } - - medianVal = tempMedian; - - delete [] scratch; - return medianVal; -} - -double MathUtilities::sum(const double *src, unsigned int len) -{ - unsigned int i ; - double retVal =0.0; - - for( i = 0; i < len; i++) - { - retVal += src[ i ]; - } - - return retVal; -} - -double MathUtilities::mean(const double *src, unsigned int len) -{ - double retVal =0.0; - - double s = sum( src, len ); - - retVal = s / (double)len; - - return retVal; -} - -void MathUtilities::getFrameMinMax(const double *data, unsigned int len, double *min, double *max) -{ - unsigned int i; - double temp = 0.0; - double a=0.0; - - *min = data[0]; - *max = data[0]; - - for( i = 0; i < len; i++) - { - temp = data[ i ]; - - if( temp < *min ) - { - *min = temp ; - } - if( temp > *max ) - { - *max = temp ; - } - - } -} - -int MathUtilities::getMax( double* pData, unsigned int Length, double* pMax ) -{ - unsigned int index = 0; - unsigned int i; - double temp = 0.0; - - double max = pData[0]; - - for( i = 0; i < Length; i++) - { - temp = pData[ i ]; - - if( temp > max ) - { - max = temp ; - index = i; - } - - } - - *pMax = max; - - - return index; -} - -void MathUtilities::circShift( double* pData, int length, int shift) -{ - shift = shift % length; - double temp; - int i,n; - - for( i = 0; i < shift; i++) - { - temp=*(pData + length - 1); - - for( n = length-2; n >= 0; n--) - { - *(pData+n+1)=*(pData+n); - } - - *pData = temp; - } -} - -int MathUtilities::compareInt (const void * a, const void * b) -{ - return ( *(int*)a - *(int*)b ); -} -
--- a/dsp/maths/MathUtilities.h Wed Nov 21 16:53:51 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - QM DSP Library - - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2005-2006 Christian Landone. - All rights reserved. -*/ - -#ifndef MATHUTILITIES_H -#define MATHUTILITIES_H - -#include <vector> - -class MathUtilities -{ -public: - static double round( double x ); - static void getFrameMinMax( const double* data, unsigned int len, double* min, double* max ); - static double mean( const double* src, unsigned int len ); - static double sum( const double* src, unsigned int len ); - static double princarg( double ang ); - static double median( const double* src, unsigned int len ); - static double mod( double x, double y); - static void getAlphaNorm(const double *data, unsigned int len, unsigned int alpha, double* ANorm); - static double getAlphaNorm(const std::vector <double> &data, unsigned int alpha ); - static void circShift( double* data, int length, int shift); - static int getMax( double* data, unsigned int length, double* max ); - static int compareInt(const void * a, const void * b); -}; - -#endif
--- a/dsp/maths/Polyfit.h Wed Nov 21 16:53:51 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,398 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ -//--------------------------------------------------------------------------- - -#ifndef PolyfitHPP -#define PolyfitHPP -//--------------------------------------------------------------------------- -// Least-squares curve fitting class for arbitrary data types -/* - -{ ****************************************** - **** Scientific Subroutine Library **** - **** for C++ Builder **** - ****************************************** - - The following programs were written by Allen Miller and appear in the - book entitled "Pascal Programs For Scientists And Engineers" which is - published by Sybex, 1981. - They were originally typed and submitted to MTPUG in Oct. 1982 - Juergen Loewner - Hoher Heckenweg 3 - D-4400 Muenster - They have had minor corrections and adaptations for Turbo Pascal by - Jeff Weiss - 1572 Peacock Ave. - Sunnyvale, CA 94087. - - -2000 Oct 28 Updated for Delphi 4, open array parameters. - This allows the routine to be generalised so that it is no longer - hard-coded to make a specific order of best fit or work with a - specific number of points. -2001 Jan 07 Update Web site address - -Copyright © David J Taylor, Edinburgh and others listed above -Web site: www.satsignal.net -E-mail: davidtaylor@writeme.com -}*/ - - /////////////////////////////////////////////////////////////////////////////// - // Modified by CLandone for VC6 Aug 2004 - /////////////////////////////////////////////////////////////////////////////// - - -using std::vector; - - -class TPolyFit -{ - typedef vector<vector<double> > Matrix; -public: - - static double PolyFit2 (const vector<double> &x, // does the work - const vector<double> &y, - vector<double> &coef); - - -private: - TPolyFit &operator = (const TPolyFit &); // disable assignment - TPolyFit(); // and instantiation - TPolyFit(const TPolyFit&); // and copying - - - static void Square (const Matrix &x, // Matrix multiplication routine - const vector<double> &y, - Matrix &a, // A = transpose X times X - vector<double> &g, // G = Y times X - const int nrow, const int ncol); - // Forms square coefficient matrix - - static bool GaussJordan (Matrix &b, // square matrix of coefficients - const vector<double> &y, // constant vector - vector<double> &coef); // solution vector - // returns false if matrix singular - - static bool GaussJordan2(Matrix &b, - const vector<double> &y, - Matrix &w, - vector<vector<int> > &index); -}; - -// some utility functions - -namespace NSUtility -{ - inline void swap(double &a, double &b) {double t = a; a = b; b = t;} - void zeroise(vector<double> &array, int n); - void zeroise(vector<int> &array, int n); - void zeroise(vector<vector<double> > &matrix, int m, int n); - void zeroise(vector<vector<int> > &matrix, int m, int n); - inline double sqr(const double &x) {return x * x;} -}; - -//--------------------------------------------------------------------------- -// Implementation -//--------------------------------------------------------------------------- -using namespace NSUtility; -//------------------------------------------------------------------------------------------ - - -// main PolyFit routine - -double TPolyFit::PolyFit2 (const vector<double> &x, - const vector<double> &y, - vector<double> &coefs) -// nterms = coefs.size() -// npoints = x.size() -{ - int i, j; - double xi, yi, yc, srs, sum_y, sum_y2; - Matrix xmatr; // Data matrix - Matrix a; - vector<double> g; // Constant vector - const int npoints(x.size()); - const int nterms(coefs.size()); - double correl_coef; - zeroise(g, nterms); - zeroise(a, nterms, nterms); - zeroise(xmatr, npoints, nterms); - if(nterms < 1) - throw "PolyFit called with less than one term"; - if(npoints < 2) - throw "PolyFit called with less than two points"; - if(npoints != y.size()) - throw "PolyFit called with x and y of unequal size"; - for(i = 0; i < npoints; ++i) - { - // { setup x matrix } - xi = x[i]; - xmatr[i][0] = 1.0; // { first column } - for(j = 1; j < nterms; ++j) - xmatr[i][j] = xmatr [i][j - 1] * xi; - } - Square (xmatr, y, a, g, npoints, nterms); - if(!GaussJordan (a, g, coefs)) - return -1; - sum_y = 0.0; - sum_y2 = 0.0; - srs = 0.0; - for(i = 0; i < npoints; ++i) - { - yi = y[i]; - yc = 0.0; - for(j = 0; j < nterms; ++j) - yc += coefs [j] * xmatr [i][j]; - srs += sqr (yc - yi); - sum_y += yi; - sum_y2 += yi * yi; - } - - // If all Y values are the same, avoid dividing by zero - correl_coef = sum_y2 - sqr (sum_y) / npoints; - // Either return 0 or the correct value of correlation coefficient - if (correl_coef != 0) - correl_coef = srs / correl_coef; - if (correl_coef >= 1) - correl_coef = 0.0; - else - correl_coef = sqrt (1.0 - correl_coef); - return correl_coef; -} - - -//------------------------------------------------------------------------ - -// Matrix multiplication routine -// A = transpose X times X -// G = Y times X - -// Form square coefficient matrix - -void TPolyFit::Square (const Matrix &x, - const vector<double> &y, - Matrix &a, - vector<double> &g, - const int nrow, - const int ncol) -{ - int i, k, l; - for(k = 0; k < ncol; ++k) - { - for(l = 0; l < k + 1; ++l) - { - a [k][l] = 0.0; - for(i = 0; i < nrow; ++i) - { - a[k][l] += x[i][l] * x [i][k]; - if(k != l) - a[l][k] = a[k][l]; - } - } - g[k] = 0.0; - for(i = 0; i < nrow; ++i) - g[k] += y[i] * x[i][k]; - } -} -//--------------------------------------------------------------------------------- - - -bool TPolyFit::GaussJordan (Matrix &b, - const vector<double> &y, - vector<double> &coef) -//b square matrix of coefficients -//y constant vector -//coef solution vector -//ncol order of matrix got from b.size() - - -{ -/* - { Gauss Jordan matrix inversion and solution } - - { B (n, n) coefficient matrix becomes inverse } - { Y (n) original constant vector } - { W (n, m) constant vector(s) become solution vector } - { DETERM is the determinant } - { ERROR = 1 if singular } - { INDEX (n, 3) } - { NV is number of constant vectors } -*/ - - int ncol(b.size()); - int irow, icol; - vector<vector<int> >index; - Matrix w; - - zeroise(w, ncol, ncol); - zeroise(index, ncol, 3); - - if(!GaussJordan2(b, y, w, index)) - return false; - - // Interchange columns - int m; - for (int i = 0; i < ncol; ++i) - { - m = ncol - i - 1; - if(index [m][0] != index [m][1]) - { - irow = index [m][0]; - icol = index [m][1]; - for(int k = 0; k < ncol; ++k) - swap (b[k][irow], b[k][icol]); - } - } - - for(int k = 0; k < ncol; ++k) - { - if(index [k][2] != 0) - { - throw "Error in GaussJordan: matrix is singular"; - } - } - - for( int i = 0; i < ncol; ++i) - coef[i] = w[i][0]; - - - return true; -} // end; { procedure GaussJordan } -//---------------------------------------------------------------------------------------------- - - -bool TPolyFit::GaussJordan2(Matrix &b, - const vector<double> &y, - Matrix &w, - vector<vector<int> > &index) -{ - //GaussJordan2; // first half of GaussJordan - // actual start of gaussj - - double big, t; - double pivot; - double determ; - int irow, icol; - int ncol(b.size()); - int nv = 1; // single constant vector - for(int i = 0; i < ncol; ++i) - { - w[i][0] = y[i]; // copy constant vector - index[i][2] = -1; - } - determ = 1.0; - for(int i = 0; i < ncol; ++i) - { - // Search for largest element - big = 0.0; - for(int j = 0; j < ncol; ++j) - { - if(index[j][2] != 0) - { - for(int k = 0; k < ncol; ++k) - { - if(index[k][2] > 0) - throw "Error in GaussJordan2: matrix is singular"; - - if(index[k][2] < 0 && fabs(b[j][k]) > big) - { - irow = j; - icol = k; - big = fabs(b[j][k]); - } - } // { k-loop } - } - } // { j-loop } - index [icol][2] = index [icol][2] + 1; - index [i][0] = irow; - index [i][1] = icol; - - // Interchange rows to put pivot on diagonal - // GJ3 - if(irow != icol) - { - determ = -determ; - for(int m = 0; m < ncol; ++m) - swap (b [irow][m], b[icol][m]); - if (nv > 0) - for (int m = 0; m < nv; ++m) - swap (w[irow][m], w[icol][m]); - } // end GJ3 - - // divide pivot row by pivot column - pivot = b[icol][icol]; - determ *= pivot; - b[icol][icol] = 1.0; - - for(int m = 0; m < ncol; ++m) - b[icol][m] /= pivot; - if(nv > 0) - for(int m = 0; m < nv; ++m) - w[icol][m] /= pivot; - - // Reduce nonpivot rows - for(int n = 0; n < ncol; ++n) - { - if(n != icol) - { - t = b[n][icol]; - b[n][icol] = 0.0; - for(int m = 0; m < ncol; ++m) - b[n][m] -= b[icol][m] * t; - if(nv > 0) - for(int m = 0; m < nv; ++m) - w[n][m] -= w[icol][m] * t; - } - } - } // { i-loop } - return true; -} -//---------------------------------------------------------------------------------------------- - -//------------------------------------------------------------------------------------ - -// Utility functions -//-------------------------------------------------------------------------- - -// fills a vector with zeros. -void NSUtility::zeroise(vector<double> &array, int n) -{ - array.clear(); - for(int j = 0; j < n; ++j) - array.push_back(0); -} -//-------------------------------------------------------------------------- - -// fills a vector with zeros. -void NSUtility::zeroise(vector<int> &array, int n) -{ - array.clear(); - for(int j = 0; j < n; ++j) - array.push_back(0); -} -//-------------------------------------------------------------------------- - -// fills a (m by n) matrix with zeros. -void NSUtility::zeroise(vector<vector<double> > &matrix, int m, int n) -{ - vector<double> zero; - zeroise(zero, n); - matrix.clear(); - for(int j = 0; j < m; ++j) - matrix.push_back(zero); -} -//-------------------------------------------------------------------------- - -// fills a (m by n) matrix with zeros. -void NSUtility::zeroise(vector<vector<int> > &matrix, int m, int n) -{ - vector<int> zero; - zeroise(zero, n); - matrix.clear(); - for(int j = 0; j < m; ++j) - matrix.push_back(zero); -} -//-------------------------------------------------------------------------- - - -#endif -
--- a/dsp/onsets/DetectionFunction.cpp Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/onsets/DetectionFunction.cpp Wed Jan 09 10:31:29 2008 +0000 @@ -144,10 +144,6 @@ case DF_BROADBAND: retVal = broadband( m_halfLength, m_magnitude); break; - - case DF_POWER: - retVal = power( m_halfLength, m_magnitude ); - break; } return retVal; @@ -269,15 +265,6 @@ return val; } -double DetectionFunction::power(unsigned int length, double *src) -{ - double val = 0; - for (unsigned int i = 0; i < length; ++i) { - val += src[i]; - } - return val; -} - double* DetectionFunction::getSpectrumMagnitude() { return m_magnitude;
--- a/dsp/onsets/DetectionFunction.h Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/onsets/DetectionFunction.h Wed Jan 09 10:31:29 2008 +0000 @@ -11,8 +11,8 @@ #ifndef DETECTIONFUNCTION_H #define DETECTIONFUNCTION_H -#include "dsp/maths/MathUtilities.h" -#include "dsp/maths/MathAliases.h" +#include "maths/MathUtilities.h" +#include "maths/MathAliases.h" #include "dsp/phasevocoder/PhaseVocoder.h" #include "base/Window.h" @@ -21,7 +21,6 @@ #define DF_PHASEDEV (3) #define DF_COMPLEXSD (4) #define DF_BROADBAND (5) -#define DF_POWER (6) struct DFConfig{ double stepSecs; // DF step in seconds @@ -52,7 +51,6 @@ double phaseDev(unsigned int length, double *srcPhase); double complexSD(unsigned int length, double *srcMagnitude, double *srcPhase); double broadband(unsigned int length, double *srcMagnitude); - double power(unsigned int length, double *src); private: void initialise( DFConfig Config );
--- a/dsp/onsets/PeakPicking.cpp Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/onsets/PeakPicking.cpp Wed Jan 09 10:31:29 2008 +0000 @@ -9,7 +9,7 @@ */ #include "PeakPicking.h" -#include "dsp/maths/Polyfit.h" +#include "maths/Polyfit.h" #include <iostream>
--- a/dsp/onsets/PeakPicking.h Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/onsets/PeakPicking.h Wed Jan 09 10:31:29 2008 +0000 @@ -15,8 +15,8 @@ #ifndef PEAKPICKING_H #define PEAKPICKING_H -#include "dsp/maths/MathUtilities.h" -#include "dsp/maths/MathAliases.h" +#include "maths/MathUtilities.h" +#include "maths/MathAliases.h" #include "dsp/signalconditioning/DFProcess.h"
--- a/dsp/signalconditioning/DFProcess.cpp Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/signalconditioning/DFProcess.cpp Wed Jan 09 10:31:29 2008 +0000 @@ -9,7 +9,7 @@ */ #include "DFProcess.h" -#include "dsp/maths/MathUtilities.h" +#include "maths/MathUtilities.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction
--- a/dsp/tempotracking/TempoTrack.cpp Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/tempotracking/TempoTrack.cpp Wed Jan 09 10:31:29 2008 +0000 @@ -10,8 +10,8 @@ #include "TempoTrack.h" -#include "dsp/maths/MathAliases.h" -#include "dsp/maths/MathUtilities.h" +#include "maths/MathAliases.h" +#include "maths/MathUtilities.h" #include <iostream>
--- a/dsp/tempotracking/TempoTrack.h Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/tempotracking/TempoTrack.h Wed Jan 09 10:31:29 2008 +0000 @@ -16,7 +16,7 @@ #include <vector> #include "dsp/signalconditioning/DFProcess.h" -#include "dsp/maths/Correlation.h" +#include "maths/Correlation.h" #include "dsp/signalconditioning/Framer.h"
--- a/dsp/tonal/TCSgram.cpp Wed Nov 21 16:53:51 2007 +0000 +++ b/dsp/tonal/TCSgram.cpp Wed Jan 09 10:31:29 2008 +0000 @@ -15,7 +15,7 @@ #include <iostream> #include <limits> -#include "dsp/maths/MathUtilities.h" +#include "maths/MathUtilities.h" TCSGram::TCSGram() : m_uNumBins(6)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hmm/hmm.c Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,800 @@ +/* + * hmm.c + * soundbite + * + * Created by Mark Levy on 12/02/2006. + * Copyright 2006 Centre for Digital Music, Queen Mary, University of London. All rights reserved. + * + */ + +#include <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <float.h> +#include <time.h> /* to seed random number generator */ +#include "clapack.h" /* LAPACK for matrix inversion */ +#ifdef _MAC_OS_X +#include <vecLib/cblas.h> +#else +#include <cblas.h> /* BLAS for matrix multiplication */ +#endif + +#include "hmm.h" + +model_t* hmm_init(double** x, int T, int L, int N) +{ + int i, j, d, e, t; + double s, ss; + + model_t* model; + model = (model_t*) malloc(sizeof(model_t)); + model->N = N; + model->L = L; + model->p0 = (double*) malloc(N*sizeof(double)); + model->a = (double**) malloc(N*sizeof(double*)); + model->mu = (double**) malloc(N*sizeof(double*)); + for (i = 0; i < N; i++) + { + model->a[i] = (double*) malloc(N*sizeof(double)); + model->mu[i] = (double*) malloc(L*sizeof(double)); + } + model->cov = (double**) malloc(L*sizeof(double*)); + for (i = 0; i < L; i++) + model->cov[i] = (double*) malloc(L*sizeof(double)); + + srand(time(0)); + double* global_mean = (double*) malloc(L*sizeof(double)); + + /* find global mean */ + for (d = 0; d < L; d++) + { + global_mean[d] = 0; + for (t = 0; t < T; t++) + global_mean[d] += x[t][d]; + global_mean[d] /= T; + } + + /* calculate global diagonal covariance */ + for (d = 0; d < L; d++) + { + for (e = 0; e < L; e++) + model->cov[d][e] = 0; + for (t = 0; t < T; t++) + model->cov[d][d] += (x[t][d] - global_mean[d]) * (x[t][d] - global_mean[d]); + model->cov[d][d] /= T-1; + } + + /* set all means close to global mean */ + for (i = 0; i < N; i++) + { + for (d = 0; d < L; d++) + { + /* add some random noise related to covariance */ + /* ideally the random number would be Gaussian(0,1), as a hack we make it uniform on [-0.25,0.25] */ + model->mu[i][d] = global_mean[d] + (0.5 * rand() / (double) RAND_MAX - 0.25) * sqrt(model->cov[d][d]); + } + } + + /* random intial and transition probs */ + s = 0; + for (i = 0; i < N; i++) + { + model->p0[i] = 1 + rand() / (double) RAND_MAX; + s += model->p0[i]; + ss = 0; + for (j = 0; j < N; j++) + { + model->a[i][j] = 1 + rand() / (double) RAND_MAX; + ss += model->a[i][j]; + } + for (j = 0; j < N; j++) + { + model->a[i][j] /= ss; + } + } + for (i = 0; i < N; i++) + model->p0[i] /= s; + + free(global_mean); + + return model; +} + +void hmm_close(model_t* model) +{ + int i; + + for (i = 0; i < model->N; i++) + { + free(model->a[i]); + free(model->mu[i]); + } + free(model->a); + free(model->mu); + for (i = 0; i < model->L; i++) + free(model->cov[i]); + free(model->cov); + free(model); +} + +void hmm_train(double** x, int T, model_t* model) +{ + int i, t; + double loglik; /* overall log-likelihood at each iteration */ + + int N = model->N; + int L = model->L; + double* p0 = model->p0; + double** a = model->a; + double** mu = model->mu; + double** cov = model->cov; + + /* allocate memory */ + double** gamma = (double**) malloc(T*sizeof(double*)); + double*** xi = (double***) malloc(T*sizeof(double**)); + for (t = 0; t < T; t++) + { + gamma[t] = (double*) malloc(N*sizeof(double)); + xi[t] = (double**) malloc(N*sizeof(double*)); + for (i = 0; i < N; i++) + xi[t][i] = (double*) malloc(N*sizeof(double)); + } + + /* temporary memory */ + double* gauss_y = (double*) malloc(L*sizeof(double)); + double* gauss_z = (double*) malloc(L*sizeof(double)); + + /* obs probs P(j|{x}) */ + double** b = (double**) malloc(T*sizeof(double*)); + for (t = 0; t < T; t++) + b[t] = (double*) malloc(N*sizeof(double)); + + /* inverse covariance and its determinant */ + double** icov = (double**) malloc(L*sizeof(double*)); + for (i = 0; i < L; i++) + icov[i] = (double*) malloc(L*sizeof(double)); + double detcov; + + double thresh = 0.0001; + int niter = 50; + int iter = 0; + double loglik1, loglik2; + while(iter < niter && !(iter > 1 && (loglik - loglik1) < thresh * (loglik1 - loglik2))) + { + ++iter; + + fprintf(stderr, "calculating obsprobs...\n"); + fflush(stderr); + + /* precalculate obs probs */ + invert(cov, L, icov, &detcov); + + for (t = 0; t < T; t++) + { + //int allzero = 1; + for (i = 0; i < N; i++) + { + b[t][i] = exp(loggauss(x[t], L, mu[i], icov, detcov, gauss_y, gauss_z)); + + //if (b[t][i] != 0) + // allzero = 0; + } + /* + if (allzero) + { + printf("all the b[t][i] were zero for t = %d, correcting...\n", t); + for (i = 0; i < N; i++) + { + b[t][i] = 0.00001; + } + } + */ + } + + fprintf(stderr, "forwards-backwards...\n"); + fflush(stderr); + + forward_backwards(xi, gamma, &loglik, &loglik1, &loglik2, iter, N, T, p0, a, b); + + fprintf(stderr, "iteration %d: loglik = %f\n", iter, loglik); + fprintf(stderr, "re-estimation...\n"); + fflush(stderr); + + baum_welch(p0, a, mu, cov, N, T, L, x, xi, gamma); + + /* + printf("a:\n"); + for (i = 0; i < model->N; i++) + { + for (j = 0; j < model->N; j++) + printf("%f ", model->a[i][j]); + printf("\n"); + } + printf("\n\n"); + */ + //hmm_print(model); + } + + /* deallocate memory */ + for (t = 0; t < T; t++) + { + free(gamma[t]); + free(b[t]); + for (i = 0; i < N; i++) + free(xi[t][i]); + free(xi[t]); + } + free(gamma); + free(xi); + free(b); + + for (i = 0; i < L; i++) + free(icov[i]); + free(icov); + + free(gauss_y); + free(gauss_z); +} + +void mlss_reestimate(double* p0, double** a, double** mu, double** cov, int N, int T, int L, int* q, double** x) +{ + /* fit a single Gaussian to observations in each state */ + + /* calculate the mean observation in each state */ + + /* calculate the overall covariance */ + + /* count transitions */ + + /* estimate initial probs from transitions (???) */ +} + +void baum_welch(double* p0, double** a, double** mu, double** cov, int N, int T, int L, double** x, double*** xi, double** gamma) +{ + int i, j, t; + + double* sum_gamma = (double*) malloc(N*sizeof(double)); + + /* temporary memory */ + double* u = (double*) malloc(L*L*sizeof(double)); + double* yy = (double*) malloc(T*L*sizeof(double)); + double* yy2 = (double*) malloc(T*L*sizeof(double)); + + /* re-estimate transition probs */ + for (i = 0; i < N; i++) + { + sum_gamma[i] = 0; + for (t = 0; t < T-1; t++) + sum_gamma[i] += gamma[t][i]; + } + + for (i = 0; i < N; i++) + { + if (sum_gamma[i] == 0) + { + fprintf(stderr, "sum_gamma[%d] was zero...\n", i); + } + //double s = 0; + for (j = 0; j < N; j++) + { + a[i][j] = 0; + for (t = 0; t < T-1; t++) + a[i][j] += xi[t][i][j]; + //s += a[i][j]; + a[i][j] /= sum_gamma[i]; + } + /* + for (j = 0; j < N; j++) + { + a[i][j] /= s; + } + */ + } + + /* NB: now we need to sum gamma over all t */ + for (i = 0; i < N; i++) + sum_gamma[i] += gamma[T-1][i]; + + /* re-estimate initial probs */ + for (i = 0; i < N; i++) + p0[i] = gamma[0][i]; + + /* re-estimate covariance */ + int d, e; + double sum_sum_gamma = 0; + for (i = 0; i < N; i++) + sum_sum_gamma += sum_gamma[i]; + + /* + for (d = 0; d < L; d++) + { + for (e = d; e < L; e++) + { + cov[d][e] = 0; + for (t = 0; t < T; t++) + for (j = 0; j < N; j++) + cov[d][e] += gamma[t][j] * (x[t][d] - mu[j][d]) * (x[t][e] - mu[j][e]); + + cov[d][e] /= sum_sum_gamma; + + if (isnan(cov[d][e])) + { + printf("cov[%d][%d] was nan\n", d, e); + for (j = 0; j < N; j++) + for (i = 0; i < L; i++) + if (isnan(mu[j][i])) + printf("mu[%d][%d] was nan\n", j, i); + for (t = 0; t < T; t++) + for (j = 0; j < N; j++) + if (isnan(gamma[t][j])) + printf("gamma[%d][%d] was nan\n", t, j); + exit(-1); + } + } + } + for (d = 0; d < L; d++) + for (e = 0; e < d; e++) + cov[d][e] = cov[e][d]; + */ + + /* using BLAS */ + for (d = 0; d < L; d++) + for (e = 0; e < L; e++) + cov[d][e] = 0; + + for (j = 0; j < N; j++) + { + for (d = 0; d < L; d++) + for (t = 0; t < T; t++) + { + yy[d*T+t] = x[t][d] - mu[j][d]; + yy2[d*T+t] = gamma[t][j] * (x[t][d] - mu[j][d]); + } + + cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, L, L, T, 1.0, yy, T, yy2, T, 0, u, L); + + for (e = 0; e < L; e++) + for (d = 0; d < L; d++) + cov[d][e] += u[e*L+d]; + } + + for (d = 0; d < L; d++) + for (e = 0; e < L; e++) + cov[d][e] /= T; /* sum_sum_gamma; */ + + //printf("sum_sum_gamma = %f\n", sum_sum_gamma); /* fine, = T IS THIS ALWAYS TRUE with pooled cov?? */ + + /* re-estimate means */ + for (j = 0; j < N; j++) + { + for (d = 0; d < L; d++) + { + mu[j][d] = 0; + for (t = 0; t < T; t++) + mu[j][d] += gamma[t][j] * x[t][d]; + mu[j][d] /= sum_gamma[j]; + } + } + + /* deallocate memory */ + free(sum_gamma); + free(yy); + free(yy2); + free(u); +} + +void forward_backwards(double*** xi, double** gamma, double* loglik, double* loglik1, double* loglik2, int iter, int N, int T, double* p0, double** a, double** b) +{ + /* forwards-backwards with scaling */ + int i, j, t; + + double** alpha = (double**) malloc(T*sizeof(double*)); + double** beta = (double**) malloc(T*sizeof(double*)); + for (t = 0; t < T; t++) + { + alpha[t] = (double*) malloc(N*sizeof(double)); + beta[t] = (double*) malloc(N*sizeof(double)); + } + + /* scaling coefficients */ + double* c = (double*) malloc(T*sizeof(double)); + + /* calculate forward probs and scale coefficients */ + c[0] = 0; + for (i = 0; i < N; i++) + { + alpha[0][i] = p0[i] * b[0][i]; + c[0] += alpha[0][i]; + + //printf("p0[%d] = %f, b[0][%d] = %f\n", i, p0[i], i, b[0][i]); + } + c[0] = 1 / c[0]; + for (i = 0; i < N; i++) + { + alpha[0][i] *= c[0]; + + //printf("alpha[0][%d] = %f\n", i, alpha[0][i]); /* OK agrees with Matlab */ + } + + *loglik1 = *loglik; + *loglik = -log(c[0]); + if (iter == 2) + *loglik2 = *loglik; + + for (t = 1; t < T; t++) + { + c[t] = 0; + for (j = 0; j < N; j++) + { + alpha[t][j] = 0; + for (i = 0; i < N; i++) + alpha[t][j] += alpha[t-1][i] * a[i][j]; + alpha[t][j] *= b[t][j]; + + c[t] += alpha[t][j]; + } + + /* + if (c[t] == 0) + { + printf("c[%d] = 0, going to blow up so exiting\n", t); + for (i = 0; i < N; i++) + if (b[t][i] == 0) + fprintf(stderr, "b[%d][%d] was zero\n", t, i); + fprintf(stderr, "x[t] was \n"); + for (i = 0; i < L; i++) + fprintf(stderr, "%f ", x[t][i]); + fprintf(stderr, "\n\n"); + exit(-1); + } + */ + + c[t] = 1 / c[t]; + for (j = 0; j < N; j++) + alpha[t][j] *= c[t]; + + //printf("c[%d] = %e\n", t, c[t]); + + *loglik -= log(c[t]); + } + + /* calculate backwards probs using same coefficients */ + for (i = 0; i < N; i++) + beta[T-1][i] = 1; + t = T - 1; + while (1) + { + for (i = 0; i < N; i++) + beta[t][i] *= c[t]; + + if (t == 0) + break; + + for (i = 0; i < N; i++) + { + beta[t-1][i] = 0; + for (j = 0; j < N; j++) + beta[t-1][i] += a[i][j] * b[t][j] * beta[t][j]; + } + + t--; + } + + /* + printf("alpha:\n"); + for (t = 0; t < T; t++) + { + for (i = 0; i < N; i++) + printf("%4.4e\t\t", alpha[t][i]); + printf("\n"); + } + printf("\n\n");printf("beta:\n"); + for (t = 0; t < T; t++) + { + for (i = 0; i < N; i++) + printf("%4.4e\t\t", beta[t][i]); + printf("\n"); + } + printf("\n\n"); + */ + + /* calculate posterior probs */ + double tot; + for (t = 0; t < T; t++) + { + tot = 0; + for (i = 0; i < N; i++) + { + gamma[t][i] = alpha[t][i] * beta[t][i]; + tot += gamma[t][i]; + } + for (i = 0; i < N; i++) + { + gamma[t][i] /= tot; + + //printf("gamma[%d][%d] = %f\n", t, i, gamma[t][i]); + } + } + + for (t = 0; t < T-1; t++) + { + tot = 0; + for (i = 0; i < N; i++) + { + for (j = 0; j < N; j++) + { + xi[t][i][j] = alpha[t][i] * a[i][j] * b[t+1][j] * beta[t+1][j]; + tot += xi[t][i][j]; + } + } + for (i = 0; i < N; i++) + for (j = 0; j < N; j++) + xi[t][i][j] /= tot; + } + + /* + // CHECK - fine + // gamma[t][i] = \sum_j{xi[t][i][j]} + tot = 0; + for (j = 0; j < N; j++) + tot += xi[3][1][j]; + printf("gamma[3][1] = %f, sum_j(xi[3][1][j]) = %f\n", gamma[3][1], tot); + */ + + for (t = 0; t < T; t++) + { + free(alpha[t]); + free(beta[t]); + } + free(alpha); + free(beta); + free(c); +} + +void viterbi_decode(double** x, int T, model_t* model, int* q) +{ + int i, j, t; + double max; + + int N = model->N; + int L = model->L; + double* p0 = model->p0; + double** a = model->a; + double** mu = model->mu; + double** cov = model->cov; + + /* inverse covariance and its determinant */ + double** icov = (double**) malloc(L*sizeof(double*)); + for (i = 0; i < L; i++) + icov[i] = (double*) malloc(L*sizeof(double)); + double detcov; + + double** logb = (double**) malloc(T*sizeof(double*)); + double** phi = (double**) malloc(T*sizeof(double*)); + int** psi = (int**) malloc(T*sizeof(int*)); + for (t = 0; t < T; t++) + { + logb[t] = (double*) malloc(N*sizeof(double)); + phi[t] = (double*) malloc(N*sizeof(double)); + psi[t] = (int*) malloc(N*sizeof(int)); + } + + /* temporary memory */ + double* gauss_y = (double*) malloc(L*sizeof(double)); + double* gauss_z = (double*) malloc(L*sizeof(double)); + + /* calculate observation logprobs */ + invert(cov, L, icov, &detcov); + for (t = 0; t < T; t++) + for (i = 0; i < N; i++) + logb[t][i] = loggauss(x[t], L, mu[i], icov, detcov, gauss_y, gauss_z); + + /* initialise */ + for (i = 0; i < N; i++) + { + phi[0][i] = log(p0[i]) + logb[0][i]; + psi[0][i] = 0; + } + + for (t = 1; t < T; t++) + { + for (j = 0; j < N; j++) + { + max = -1000000; // TODO: what should this be?? = smallest possible sumlogprob + psi[t][j] = 0; + for (i = 0; i < N; i++) + { + if (phi[t-1][i] + log(a[i][j]) > max) + { + max = phi[t-1][i] + log(a[i][j]); + phi[t][j] = max + logb[t][j]; + psi[t][j] = i; + } + } + } + } + + /* find maximising state at time T-1 */ + max = phi[T-1][0]; + q[T-1] = 0; + for (i = 1; i < N; i++) + { + if (phi[T-1][i] > max) + { + max = phi[T-1][i]; + q[T-1] = i; + } + } + + + /* track back */ + t = T - 2; + while (t >= 0) + { + q[t] = psi[t+1][q[t+1]]; + t--; + } + + /* de-allocate memory */ + for (i = 0; i < L; i++) + free(icov[i]); + free(icov); + for (t = 0; t < T; t++) + { + free(logb[t]); + free(phi[t]); + free(psi[t]); + } + free(logb); + free(phi); + free(psi); + + free(gauss_y); + free(gauss_z); +} + +/* invert matrix and calculate determinant using LAPACK */ +void invert(double** cov, int L, double** icov, double* detcov) +{ + /* copy square matrix into a vector in column-major order */ + double* a = (double*) malloc(L*L*sizeof(double)); + int i, j; + for(j=0; j < L; j++) + for (i=0; i < L; i++) + a[j*L+i] = cov[i][j]; + + long M = (long) L; + long* ipiv = (long*) malloc(L*L*sizeof(int)); + long ret; + + /* LU decomposition */ + ret = dgetrf_(&M, &M, a, &M, ipiv, &ret); /* ret should be zero, negative if cov is singular */ + if (ret < 0) + { + fprintf(stderr, "Covariance matrix was singular, couldn't invert\n"); + exit(-1); + } + + /* find determinant */ + double det = 1; + for(i = 0; i < L; i++) + det *= a[i*L+i]; + // TODO: get this to work!!! If detcov < 0 then cov is bad anyway... + /* + int sign = 1; + for (i = 0; i < L; i++) + if (ipiv[i] != i) + sign = -sign; + det *= sign; + */ + if (det < 0) + det = -det; + *detcov = det; + + /* allocate required working storage */ + long lwork = -1; + double lwbest; + dgetri_(&M, a, &M, ipiv, &lwbest, &lwork, &ret); + lwork = (long) lwbest; + double* work = (double*) malloc(lwork*sizeof(double)); + + /* find inverse */ + dgetri_(&M, a, &M, ipiv, work, &lwork, &ret); + + for(j=0; j < L; j++) + for (i=0; i < L; i++) + icov[i][j] = a[j*L+i]; + + free(work); + free(a); +} + +/* probability of multivariate Gaussian given mean, inverse and determinant of covariance */ +double gauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z) +{ + int i, j; + double s = 0; + for (i = 0; i < L; i++) + y[i] = x[i] - mu[i]; + for (i = 0; i < L; i++) + { + //z[i] = 0; + //for (j = 0; j < L; j++) + // z[i] += icov[i][j] * y[j]; + z[i] = cblas_ddot(L, &icov[i][0], 1, y, 1); + } + s = cblas_ddot(L, z, 1, y, 1); + //for (i = 0; i < L; i++) + // s += z[i] * y[i]; + + return exp(-s/2.0) / (pow(2*PI, L/2.0) * sqrt(detcov)); +} + +/* log probability of multivariate Gaussian given mean, inverse and determinant of covariance */ +double loggauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z) +{ + int i, j; + double s = 0; + double ret; + for (i = 0; i < L; i++) + y[i] = x[i] - mu[i]; + for (i = 0; i < L; i++) + { + //z[i] = 0; + //for (j = 0; j < L; j++) + // z[i] += icov[i][j] * y[j]; + z[i] = cblas_ddot(L, &icov[i][0], 1, y, 1); + } + s = cblas_ddot(L, z, 1, y, 1); + //for (i = 0; i < L; i++) + // s += z[i] * y[i]; + + ret = -0.5 * (s + L * log(2*PI) + log(detcov)); + + /* + // TEST + if (isinf(ret) > 0) + printf("loggauss returning infinity\n"); + if (isinf(ret) < 0) + printf("loggauss returning -infinity\n"); + if (isnan(ret)) + printf("loggauss returning nan\n"); + */ + + return ret; +} + +void hmm_print(model_t* model) +{ + int i, j; + printf("p0:\n"); + for (i = 0; i < model->N; i++) + printf("%f ", model->p0[i]); + printf("\n\n"); + printf("a:\n"); + for (i = 0; i < model->N; i++) + { + for (j = 0; j < model->N; j++) + printf("%f ", model->a[i][j]); + printf("\n"); + } + printf("\n\n"); + printf("mu:\n"); + for (i = 0; i < model->N; i++) + { + for (j = 0; j < model->L; j++) + printf("%f ", model->mu[i][j]); + printf("\n"); + } + printf("\n\n"); + printf("cov:\n"); + for (i = 0; i < model->L; i++) + { + for (j = 0; j < model->L; j++) + printf("%f ", model->cov[i][j]); + printf("\n"); + } + printf("\n\n"); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hmm/hmm.h Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,39 @@ +#ifndef _HMM_H +#define _HMM_H + +/* + * hmm.h + * soundbite + * + * Created by Mark Levy on 12/02/2006. + * Copyright 2006 Centre for Digital Music, Queen Mary, University of London. All rights reserved. + * + */ + +#ifndef PI +#define PI 3.14159265358979323846264338327950288 +#endif + +typedef struct _model_t { + int N; /* number of states */ + double* p0; /* initial probs */ + double** a; /* transition probs */ + int L; /* dimensionality of data */ + double** mu; /* state means */ + double** cov; /* covariance, tied between all states */ +} model_t; + +void hmm_train(double** x, int T, model_t* model); /* with scaling */ +void forward_backwards(double*** xi, double** gamma, double* loglik, double* loglik1, double* loglik2, int iter, + int N, int T, double* p0, double** a, double** b); +void baum_welch(double* p0, double** a, double** mu, double** cov, int N, int T, int L, double** x, double*** xi, double** gamma); +void viterbi_decode(double** x, int T, model_t* model, int* q); /* using logs */ +model_t* hmm_init(double** x, int T, int L, int N); +void hmm_close(model_t* model); +void invert(double** cov, int L, double** icov, double* detcov); /* uses LAPACK (included with Mac OSX) */ +double gauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z); +double loggauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z); +void hmm_print(model_t* model); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/maths/Correlation.cpp Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,51 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + QM DSP Library + + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2005-2006 Christian Landone. + All rights reserved. +*/ + +#include "Correlation.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +Correlation::Correlation() +{ + +} + +Correlation::~Correlation() +{ + +} + +void Correlation::doAutoUnBiased(double *src, double *dst, unsigned int length) +{ + double tmp = 0.0; + double outVal = 0.0; + + unsigned int i,j; + + for( i = 0; i < length; i++) + { + for( j = i; j < length; j++) + { + tmp += src[ j-i ] * src[ j ]; + } + + + outVal = tmp / ( length - i ); + + if( outVal <= 0 ) + dst[ i ] = EPS; + else + dst[ i ] = outVal; + + tmp = 0.0; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/maths/Correlation.h Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,25 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + QM DSP Library + + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2005-2006 Christian Landone. + All rights reserved. +*/ + +#ifndef CORRELATION_H +#define CORRELATION_H + +#define EPS 2.2204e-016 + +class Correlation +{ +public: + void doAutoUnBiased( double* src, double* dst, unsigned int length ); + Correlation(); + virtual ~Correlation(); + +}; + +#endif //
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/maths/Histogram.h Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,393 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +// Histogram.h: interface for the THistogram class. +// +////////////////////////////////////////////////////////////////////// + + +#ifndef HISTOGRAM_H +#define HISTOGRAM_H + + +#include <valarray> + +/*! \brief A histogram class + + This class computes the histogram of a vector. + +\par Template parameters + + - T type of input data (can be any: float, double, int, UINT, etc...) + - TOut type of output data: float or double. (default is double) + +\par Moments: + + The moments (average, standard deviation, skewness, etc.) are computed using +the algorithm of the Numerical recipies (see Numerical recipies in C, Chapter 14.1, pg 613). + +\par Example: + + This example shows the typical use of the class: +\code + // a vector containing the data + vector<float> data; + // Creating histogram using float data and with 101 containers, + THistogram<float> histo(101); + // computing the histogram + histo.compute(data); +\endcode + +Once this is done, you can get a vector with the histogram or the normalized histogram (such that it's area is 1): +\code + // getting normalized histogram + vector<float> v=histo.getNormalizedHistogram(); +\endcode + +\par Reference + + Equally spaced acsissa function integration (used in #GetArea): Numerical Recipies in C, Chapter 4.1, pg 130. + +\author Jonathan de Halleux, dehalleux@auto.ucl.ac.be, 2002 +*/ + +template<class T, class TOut = double> +class THistogram +{ +public: + //! \name Constructors + //@{ + /*! Default constructor + \param counters the number of histogram containers (default value is 10) + */ + THistogram(unsigned int counters = 10); + virtual ~THistogram() { clear();}; + //@} + + //! \name Histogram computation, update + //@{ + /*! Computes histogram of vector v + \param v vector to compute histogram + \param computeMinMax set to true if min/max of v have to be used to get the histogram limits + + This function computes the histogram of v and stores it internally. + \sa Update, GeTHistogram + */ + void compute( const std::vector<T>& v, bool computeMinMax = true); + //! Update histogram with the vector v + void update( const std::vector<T>& v); + //! Update histogram with t + void update( const T& t); + //@} + + //! \name Resetting functions + //@{ + //! Resize the histogram. Warning this function clear the histogram. + void resize( unsigned int counters ); + //! Clears the histogram + void clear() { m_counters.clear();}; + //@} + + //! \name Setters + //@{ + /*! This function sets the minimum of the histogram spectrum. + The spectrum is not recomputed, use it with care + */ + void setMinSpectrum( const T& min ) { m_min = min; computeStep();}; + /*! This function sets the minimum of the histogram spectrum. + The spectrum is not recomputed, use it with care + */ + void setMaxSpectrum( const T& max ) { m_max = max; computeStep();}; + //@} + //! \name Getters + //@{ + //! return minimum of histogram spectrum + const T& getMinSpectrum() const { return m_min;}; + //! return maximum of histogram spectrum + const T& getMaxSpectrum() const { return m_max;}; + //! return step size of histogram containers + TOut getStep() const { return m_step;}; + //! return number of points in histogram + unsigned int getSum() const; + /*! \brief returns area under the histogram + + The Simpson rule is used to integrate the histogram. + */ + TOut getArea() const; + + /*! \brief Computes the moments of the histogram + + \param data dataset + \param ave mean + \f[ \bar x = \frac{1}{N} \sum_{j=1}^N x_j\f] + \param adev mean absolute deviation + \f[ adev(X) = \frac{1}{N} \sum_{j=1}^N | x_j - \bar x |\f] + \param var average deviation: + \f[ \mbox{Var}(X) = \frac{1}{N-1} \sum_{j=1}^N (x_j - \bar x)^2\f] + \param sdev standard deviation: + \f[ \sigma(X) = \sqrt{var(\bar x) }\f] + \param skew skewness + \f[ \mbox{Skew}(X) = \frac{1}{N}\sum_{j=1}^N \left[ \frac{x_j - \bar x}{\sigma}\right]^3\f] + \param kurt kurtosis + \f[ \mbox{Kurt}(X) = \left\{ \frac{1}{N}\sum_{j=1}^N \left[ \frac{x_j - \bar x}{\sigma}\right]^4 \right\} - 3\f] + + */ + static void getMoments(const std::vector<T>& data, TOut& ave, TOut& adev, TOut& sdev, TOut& var, TOut& skew, TOut& kurt); + + //! return number of containers + unsigned int getSize() const { return m_counters.size();}; + //! returns i-th counter + unsigned int operator [] (unsigned int i) const { +// ASSERT( i < m_counters.size() ); + return m_counters[i]; + }; + //! return the computed histogram + const std::vector<unsigned int>& geTHistogram() const { return m_counters;}; + //! return the computed histogram, in TOuts + std::vector<TOut> geTHistogramD() const; + /*! return the normalized computed histogram + + \return the histogram such that the area is equal to 1 + */ + std::vector<TOut> getNormalizedHistogram() const; + //! returns left containers position + std::vector<TOut> getLeftContainers() const; + //! returns center containers position + std::vector<TOut> getCenterContainers() const; + //@} +protected: + //! Computes the step + void computeStep() { m_step = (TOut)(((TOut)(m_max-m_min)) / (m_counters.size()-1));}; + //! Data accumulators + std::vector<unsigned int> m_counters; + //! minimum of dataset + T m_min; + //! maximum of dataset + T m_max; + //! width of container + TOut m_step; +}; + +template<class T, class TOut> +THistogram<T,TOut>::THistogram(unsigned int counters) + : m_counters(counters,0), m_min(0), m_max(0), m_step(0) +{ + +} + +template<class T, class TOut> +void THistogram<T,TOut>::resize( unsigned int counters ) +{ + clear(); + + m_counters.resize(counters,0); + + computeStep(); +} + +template<class T, class TOut> +void THistogram<T,TOut>::compute( const std::vector<T>& v, bool computeMinMax) +{ + using namespace std; + unsigned int i; + int index; + + if (m_counters.empty()) + return; + + if (computeMinMax) + { + m_max = m_min = v[0]; + for (i=1;i<v.size();i++) + { + m_max = std::max( m_max, v[i]); + m_min = std::min( m_min, v[i]); + } + } + + computeStep(); + + for (i = 0;i < v.size() ; i++) + { + index=(int) floor( ((TOut)(v[i]-m_min))/m_step ) ; + + if (index >= m_counters.size() || index < 0) + return; + + m_counters[index]++; + } +} + +template<class T, class TOut> +void THistogram<T,TOut>::update( const std::vector<T>& v) +{ + if (m_counters.empty()) + return; + + computeStep(); + + TOut size = m_counters.size(); + + int index; + for (unsigned int i = 0;i < size ; i++) + { + index = (int)floor(((TOut)(v[i]-m_min))/m_step); + + if (index >= m_counters.size() || index < 0) + return; + + m_counters[index]++; + } +} + +template<class T, class TOut> +void THistogram<T,TOut>::update( const T& t) +{ + int index=(int) floor( ((TOut)(t-m_min))/m_step ) ; + + if (index >= m_counters.size() || index < 0) + return; + + m_counters[index]++; +}; + +template<class T, class TOut> +std::vector<TOut> THistogram<T,TOut>::geTHistogramD() const +{ + std::vector<TOut> v(m_counters.size()); + for (unsigned int i = 0;i<m_counters.size(); i++) + v[i]=(TOut)m_counters[i]; + + return v; +} + +template <class T, class TOut> +std::vector<TOut> THistogram<T,TOut>::getLeftContainers() const +{ + std::vector<TOut> x( m_counters.size()); + + for (unsigned int i = 0;i<m_counters.size(); i++) + x[i]= m_min + i*m_step; + + return x; +} + +template <class T, class TOut> +std::vector<TOut> THistogram<T,TOut>::getCenterContainers() const +{ + std::vector<TOut> x( m_counters.size()); + + for (unsigned int i = 0;i<m_counters.size(); i++) + x[i]= m_min + (i+0.5)*m_step; + + return x; +} + +template <class T, class TOut> +unsigned int THistogram<T,TOut>::getSum() const +{ + unsigned int sum = 0; + for (unsigned int i = 0;i<m_counters.size(); i++) + sum+=m_counters[i]; + + return sum; +} + +template <class T, class TOut> +TOut THistogram<T,TOut>::getArea() const +{ + const size_t n=m_counters.size(); + TOut area=0; + + if (n>6) + { + area=3.0/8.0*(m_counters[0]+m_counters[n-1]) + +7.0/6.0*(m_counters[1]+m_counters[n-2]) + +23.0/24.0*(m_counters[2]+m_counters[n-3]); + for (unsigned int i=3;i<n-3;i++) + { + area+=m_counters[i]; + } + } + else if (n>4) + { + area=5.0/12.0*(m_counters[0]+m_counters[n-1]) + +13.0/12.0*(m_counters[1]+m_counters[n-2]); + for (unsigned int i=2;i<n-2;i++) + { + area+=m_counters[i]; + } + } + else if (n>1) + { + area=1/2.0*(m_counters[0]+m_counters[n-1]); + for (unsigned int i=1;i<n-1;i++) + { + area+=m_counters[i]; + } + } + else + area=0; + + return area*m_step; +} + +template <class T, class TOut> +std::vector<TOut> THistogram<T,TOut>::getNormalizedHistogram() const +{ + std::vector<TOut> normCounters( m_counters.size()); + TOut area = (TOut)getArea(); + + for (unsigned int i = 0;i<m_counters.size(); i++) + { + normCounters[i]= (TOut)m_counters[i]/area; + } + + return normCounters; +}; + +template <class T, class TOut> +void THistogram<T,TOut>::getMoments(const std::vector<T>& data, TOut& ave, TOut& adev, TOut& sdev, TOut& var, TOut& skew, TOut& kurt) +{ + int j; + double ep=0.0,s,p; + const size_t n = data.size(); + + if (n <= 1) + // nrerror("n must be at least 2 in moment"); + return; + + s=0.0; // First pass to get the mean. + for (j=0;j<n;j++) + s += data[j]; + + ave=s/(n); + adev=var=skew=kurt=0.0; + /* Second pass to get the first (absolute), second, + third, and fourth moments of the + deviation from the mean. */ + + for (j=0;j<n;j++) + { + adev += fabs(s=data[j]-(ave)); + ep += s; + var += (p=s*s); + skew += (p *= s); + kurt += (p *= s); + } + + + adev /= n; + var=(var-ep*ep/n)/(n-1); // Corrected two-pass formula. + sdev=sqrt(var); // Put the pieces together according to the conventional definitions. + if (var) + { + skew /= (n*(var)*(sdev)); + kurt=(kurt)/(n*(var)*(var))-3.0; + } + else + //nrerror("No skew/kurtosis when variance = 0 (in moment)"); + return; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/maths/MathAliases.h Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,55 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + QM DSP Library + + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2005-2006 Christian Landone. + All rights reserved. +*/ + +#ifndef MATHALIASES_H +#define MATHALIASES_H + +#include <cmath> +#include <complex> + +using namespace std; +typedef complex<double> ComplexData; + + +#ifndef PI +#define PI (3.14159265358979232846) +#endif + +#define TWO_PI (*2.PI) + +#define EPS 2.2204e-016 + +/* aliases to math.h functions */ +#define EXP exp +#define COS cos +#define SIN sin +#define ABS fabs +#define POW powf +#define SQRT sqrtf +#define LOG10 log10f +#define LOG logf +#define FLOOR floorf +#define TRUNC truncf + +/* aliases to complex.h functions */ +/** sample = EXPC(complex) */ +#define EXPC cexpf +/** complex = CEXPC(complex) */ +#define CEXPC cexp +/** sample = ARGC(complex) */ +#define ARGC cargf +/** sample = ABSC(complex) norm */ +#define ABSC cabsf +/** sample = REAL(complex) */ +#define REAL crealf +/** sample = IMAG(complex) */ +#define IMAG cimagf + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/maths/MathUtilities.cpp Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,221 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + QM DSP Library + + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2005-2006 Christian Landone. + All rights reserved. +*/ + +#include "MathUtilities.h" + +#include <iostream> +#include <cmath> + + +double MathUtilities::mod(double x, double y) +{ + double a = floor( x / y ); + + double b = x - ( y * a ); + return b; +} + +double MathUtilities::princarg(double ang) +{ + double ValOut; + + ValOut = mod( ang + M_PI, -2 * M_PI ) + M_PI; + + return ValOut; +} + +void MathUtilities::getAlphaNorm(const double *data, unsigned int len, unsigned int alpha, double* ANorm) +{ + unsigned int i; + double temp = 0.0; + double a=0.0; + + for( i = 0; i < len; i++) + { + temp = data[ i ]; + + a += ::pow( fabs(temp), alpha ); + } + a /= ( double )len; + a = ::pow( a, ( 1.0 / (double) alpha ) ); + + *ANorm = a; +} + +double MathUtilities::getAlphaNorm( const std::vector <double> &data, unsigned int alpha ) +{ + unsigned int i; + unsigned int len = data.size(); + double temp = 0.0; + double a=0.0; + + for( i = 0; i < len; i++) + { + temp = data[ i ]; + + a += ::pow( fabs(temp), alpha ); + } + a /= ( double )len; + a = ::pow( a, ( 1.0 / (double) alpha ) ); + + return a; +} + +double MathUtilities::round(double x) +{ + double val = (double)floor(x + 0.5); + + return val; +} + +double MathUtilities::median(const double *src, unsigned int len) +{ + unsigned int i, j; + double tmp = 0.0; + double tempMedian; + double medianVal; + + double* scratch = new double[ len ];//Vector < double > sortedX = Vector < double > ( size ); + + for ( i = 0; i < len; i++ ) + { + scratch[i] = src[i]; + } + + for ( i = 0; i < len - 1; i++ ) + { + for ( j = 0; j < len - 1 - i; j++ ) + { + if ( scratch[j + 1] < scratch[j] ) + { + // compare the two neighbors + tmp = scratch[j]; // swap a[j] and a[j+1] + scratch[j] = scratch[j + 1]; + scratch[j + 1] = tmp; + } + } + } + int middle; + if ( len % 2 == 0 ) + { + middle = len / 2; + tempMedian = ( scratch[middle] + scratch[middle - 1] ) / 2; + } + else + { + middle = ( int )floor( len / 2.0 ); + tempMedian = scratch[middle]; + } + + medianVal = tempMedian; + + delete [] scratch; + return medianVal; +} + +double MathUtilities::sum(const double *src, unsigned int len) +{ + unsigned int i ; + double retVal =0.0; + + for( i = 0; i < len; i++) + { + retVal += src[ i ]; + } + + return retVal; +} + +double MathUtilities::mean(const double *src, unsigned int len) +{ + double retVal =0.0; + + double s = sum( src, len ); + + retVal = s / (double)len; + + return retVal; +} + +void MathUtilities::getFrameMinMax(const double *data, unsigned int len, double *min, double *max) +{ + unsigned int i; + double temp = 0.0; + double a=0.0; + + *min = data[0]; + *max = data[0]; + + for( i = 0; i < len; i++) + { + temp = data[ i ]; + + if( temp < *min ) + { + *min = temp ; + } + if( temp > *max ) + { + *max = temp ; + } + + } +} + +int MathUtilities::getMax( double* pData, unsigned int Length, double* pMax ) +{ + unsigned int index = 0; + unsigned int i; + double temp = 0.0; + + double max = pData[0]; + + for( i = 0; i < Length; i++) + { + temp = pData[ i ]; + + if( temp > max ) + { + max = temp ; + index = i; + } + + } + + *pMax = max; + + + return index; +} + +void MathUtilities::circShift( double* pData, int length, int shift) +{ + shift = shift % length; + double temp; + int i,n; + + for( i = 0; i < shift; i++) + { + temp=*(pData + length - 1); + + for( n = length-2; n >= 0; n--) + { + *(pData+n+1)=*(pData+n); + } + + *pData = temp; + } +} + +int MathUtilities::compareInt (const void * a, const void * b) +{ + return ( *(int*)a - *(int*)b ); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/maths/MathUtilities.h Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,33 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + QM DSP Library + + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2005-2006 Christian Landone. + All rights reserved. +*/ + +#ifndef MATHUTILITIES_H +#define MATHUTILITIES_H + +#include <vector> + +class MathUtilities +{ +public: + static double round( double x ); + static void getFrameMinMax( const double* data, unsigned int len, double* min, double* max ); + static double mean( const double* src, unsigned int len ); + static double sum( const double* src, unsigned int len ); + static double princarg( double ang ); + static double median( const double* src, unsigned int len ); + static double mod( double x, double y); + static void getAlphaNorm(const double *data, unsigned int len, unsigned int alpha, double* ANorm); + static double getAlphaNorm(const std::vector <double> &data, unsigned int alpha ); + static void circShift( double* data, int length, int shift); + static int getMax( double* data, unsigned int length, double* max ); + static int compareInt(const void * a, const void * b); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/maths/Polyfit.h Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,398 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ +//--------------------------------------------------------------------------- + +#ifndef PolyfitHPP +#define PolyfitHPP +//--------------------------------------------------------------------------- +// Least-squares curve fitting class for arbitrary data types +/* + +{ ****************************************** + **** Scientific Subroutine Library **** + **** for C++ Builder **** + ****************************************** + + The following programs were written by Allen Miller and appear in the + book entitled "Pascal Programs For Scientists And Engineers" which is + published by Sybex, 1981. + They were originally typed and submitted to MTPUG in Oct. 1982 + Juergen Loewner + Hoher Heckenweg 3 + D-4400 Muenster + They have had minor corrections and adaptations for Turbo Pascal by + Jeff Weiss + 1572 Peacock Ave. + Sunnyvale, CA 94087. + + +2000 Oct 28 Updated for Delphi 4, open array parameters. + This allows the routine to be generalised so that it is no longer + hard-coded to make a specific order of best fit or work with a + specific number of points. +2001 Jan 07 Update Web site address + +Copyright © David J Taylor, Edinburgh and others listed above +Web site: www.satsignal.net +E-mail: davidtaylor@writeme.com +}*/ + + /////////////////////////////////////////////////////////////////////////////// + // Modified by CLandone for VC6 Aug 2004 + /////////////////////////////////////////////////////////////////////////////// + + +using std::vector; + + +class TPolyFit +{ + typedef vector<vector<double> > Matrix; +public: + + static double PolyFit2 (const vector<double> &x, // does the work + const vector<double> &y, + vector<double> &coef); + + +private: + TPolyFit &operator = (const TPolyFit &); // disable assignment + TPolyFit(); // and instantiation + TPolyFit(const TPolyFit&); // and copying + + + static void Square (const Matrix &x, // Matrix multiplication routine + const vector<double> &y, + Matrix &a, // A = transpose X times X + vector<double> &g, // G = Y times X + const int nrow, const int ncol); + // Forms square coefficient matrix + + static bool GaussJordan (Matrix &b, // square matrix of coefficients + const vector<double> &y, // constant vector + vector<double> &coef); // solution vector + // returns false if matrix singular + + static bool GaussJordan2(Matrix &b, + const vector<double> &y, + Matrix &w, + vector<vector<int> > &index); +}; + +// some utility functions + +namespace NSUtility +{ + inline void swap(double &a, double &b) {double t = a; a = b; b = t;} + void zeroise(vector<double> &array, int n); + void zeroise(vector<int> &array, int n); + void zeroise(vector<vector<double> > &matrix, int m, int n); + void zeroise(vector<vector<int> > &matrix, int m, int n); + inline double sqr(const double &x) {return x * x;} +}; + +//--------------------------------------------------------------------------- +// Implementation +//--------------------------------------------------------------------------- +using namespace NSUtility; +//------------------------------------------------------------------------------------------ + + +// main PolyFit routine + +double TPolyFit::PolyFit2 (const vector<double> &x, + const vector<double> &y, + vector<double> &coefs) +// nterms = coefs.size() +// npoints = x.size() +{ + int i, j; + double xi, yi, yc, srs, sum_y, sum_y2; + Matrix xmatr; // Data matrix + Matrix a; + vector<double> g; // Constant vector + const int npoints(x.size()); + const int nterms(coefs.size()); + double correl_coef; + zeroise(g, nterms); + zeroise(a, nterms, nterms); + zeroise(xmatr, npoints, nterms); + if(nterms < 1) + throw "PolyFit called with less than one term"; + if(npoints < 2) + throw "PolyFit called with less than two points"; + if(npoints != y.size()) + throw "PolyFit called with x and y of unequal size"; + for(i = 0; i < npoints; ++i) + { + // { setup x matrix } + xi = x[i]; + xmatr[i][0] = 1.0; // { first column } + for(j = 1; j < nterms; ++j) + xmatr[i][j] = xmatr [i][j - 1] * xi; + } + Square (xmatr, y, a, g, npoints, nterms); + if(!GaussJordan (a, g, coefs)) + return -1; + sum_y = 0.0; + sum_y2 = 0.0; + srs = 0.0; + for(i = 0; i < npoints; ++i) + { + yi = y[i]; + yc = 0.0; + for(j = 0; j < nterms; ++j) + yc += coefs [j] * xmatr [i][j]; + srs += sqr (yc - yi); + sum_y += yi; + sum_y2 += yi * yi; + } + + // If all Y values are the same, avoid dividing by zero + correl_coef = sum_y2 - sqr (sum_y) / npoints; + // Either return 0 or the correct value of correlation coefficient + if (correl_coef != 0) + correl_coef = srs / correl_coef; + if (correl_coef >= 1) + correl_coef = 0.0; + else + correl_coef = sqrt (1.0 - correl_coef); + return correl_coef; +} + + +//------------------------------------------------------------------------ + +// Matrix multiplication routine +// A = transpose X times X +// G = Y times X + +// Form square coefficient matrix + +void TPolyFit::Square (const Matrix &x, + const vector<double> &y, + Matrix &a, + vector<double> &g, + const int nrow, + const int ncol) +{ + int i, k, l; + for(k = 0; k < ncol; ++k) + { + for(l = 0; l < k + 1; ++l) + { + a [k][l] = 0.0; + for(i = 0; i < nrow; ++i) + { + a[k][l] += x[i][l] * x [i][k]; + if(k != l) + a[l][k] = a[k][l]; + } + } + g[k] = 0.0; + for(i = 0; i < nrow; ++i) + g[k] += y[i] * x[i][k]; + } +} +//--------------------------------------------------------------------------------- + + +bool TPolyFit::GaussJordan (Matrix &b, + const vector<double> &y, + vector<double> &coef) +//b square matrix of coefficients +//y constant vector +//coef solution vector +//ncol order of matrix got from b.size() + + +{ +/* + { Gauss Jordan matrix inversion and solution } + + { B (n, n) coefficient matrix becomes inverse } + { Y (n) original constant vector } + { W (n, m) constant vector(s) become solution vector } + { DETERM is the determinant } + { ERROR = 1 if singular } + { INDEX (n, 3) } + { NV is number of constant vectors } +*/ + + int ncol(b.size()); + int irow, icol; + vector<vector<int> >index; + Matrix w; + + zeroise(w, ncol, ncol); + zeroise(index, ncol, 3); + + if(!GaussJordan2(b, y, w, index)) + return false; + + // Interchange columns + int m; + for (int i = 0; i < ncol; ++i) + { + m = ncol - i - 1; + if(index [m][0] != index [m][1]) + { + irow = index [m][0]; + icol = index [m][1]; + for(int k = 0; k < ncol; ++k) + swap (b[k][irow], b[k][icol]); + } + } + + for(int k = 0; k < ncol; ++k) + { + if(index [k][2] != 0) + { + throw "Error in GaussJordan: matrix is singular"; + } + } + + for( int i = 0; i < ncol; ++i) + coef[i] = w[i][0]; + + + return true; +} // end; { procedure GaussJordan } +//---------------------------------------------------------------------------------------------- + + +bool TPolyFit::GaussJordan2(Matrix &b, + const vector<double> &y, + Matrix &w, + vector<vector<int> > &index) +{ + //GaussJordan2; // first half of GaussJordan + // actual start of gaussj + + double big, t; + double pivot; + double determ; + int irow, icol; + int ncol(b.size()); + int nv = 1; // single constant vector + for(int i = 0; i < ncol; ++i) + { + w[i][0] = y[i]; // copy constant vector + index[i][2] = -1; + } + determ = 1.0; + for(int i = 0; i < ncol; ++i) + { + // Search for largest element + big = 0.0; + for(int j = 0; j < ncol; ++j) + { + if(index[j][2] != 0) + { + for(int k = 0; k < ncol; ++k) + { + if(index[k][2] > 0) + throw "Error in GaussJordan2: matrix is singular"; + + if(index[k][2] < 0 && fabs(b[j][k]) > big) + { + irow = j; + icol = k; + big = fabs(b[j][k]); + } + } // { k-loop } + } + } // { j-loop } + index [icol][2] = index [icol][2] + 1; + index [i][0] = irow; + index [i][1] = icol; + + // Interchange rows to put pivot on diagonal + // GJ3 + if(irow != icol) + { + determ = -determ; + for(int m = 0; m < ncol; ++m) + swap (b [irow][m], b[icol][m]); + if (nv > 0) + for (int m = 0; m < nv; ++m) + swap (w[irow][m], w[icol][m]); + } // end GJ3 + + // divide pivot row by pivot column + pivot = b[icol][icol]; + determ *= pivot; + b[icol][icol] = 1.0; + + for(int m = 0; m < ncol; ++m) + b[icol][m] /= pivot; + if(nv > 0) + for(int m = 0; m < nv; ++m) + w[icol][m] /= pivot; + + // Reduce nonpivot rows + for(int n = 0; n < ncol; ++n) + { + if(n != icol) + { + t = b[n][icol]; + b[n][icol] = 0.0; + for(int m = 0; m < ncol; ++m) + b[n][m] -= b[icol][m] * t; + if(nv > 0) + for(int m = 0; m < nv; ++m) + w[n][m] -= w[icol][m] * t; + } + } + } // { i-loop } + return true; +} +//---------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------------ + +// Utility functions +//-------------------------------------------------------------------------- + +// fills a vector with zeros. +void NSUtility::zeroise(vector<double> &array, int n) +{ + array.clear(); + for(int j = 0; j < n; ++j) + array.push_back(0); +} +//-------------------------------------------------------------------------- + +// fills a vector with zeros. +void NSUtility::zeroise(vector<int> &array, int n) +{ + array.clear(); + for(int j = 0; j < n; ++j) + array.push_back(0); +} +//-------------------------------------------------------------------------- + +// fills a (m by n) matrix with zeros. +void NSUtility::zeroise(vector<vector<double> > &matrix, int m, int n) +{ + vector<double> zero; + zeroise(zero, n); + matrix.clear(); + for(int j = 0; j < m; ++j) + matrix.push_back(zero); +} +//-------------------------------------------------------------------------- + +// fills a (m by n) matrix with zeros. +void NSUtility::zeroise(vector<vector<int> > &matrix, int m, int n) +{ + vector<int> zero; + zeroise(zero, n); + matrix.clear(); + for(int j = 0; j < m; ++j) + matrix.push_back(zero); +} +//-------------------------------------------------------------------------- + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/maths/pca/data.txt Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,36 @@ + 3.0 3.0 3.0 3.0 3.0 3.0 35.0 45.0 + 53.0 55.0 58.0 113.0 113.0 86.0 67.0 90.0 + 3.5 3.5 4.0 4.0 4.5 4.5 46.0 59.0 + 63.0 58.0 58.0 125.0 126.0 110.0 78.0 97.0 + 4.0 4.0 4.5 4.5 5.0 5.0 48.0 60.0 + 68.0 65.0 65.0 123.0 123.0 117.0 87.0 108.0 + 5.0 5.0 5.0 5.5 5.5 5.5 46.0 63.0 + 70.0 64.0 63.0 116.0 119.0 115.0 97.0 112.0 + 6.0 6.0 6.0 6.0 6.5 6.5 51.0 69.0 + 77.0 70.0 71.0 120.0 122.0 122.0 96.0 123.0 + 11.0 11.0 11.0 11.0 11.0 11.0 64.0 75.0 + 81.0 79.0 79.0 112.0 114.0 113.0 98.0 115.0 + 20.0 20.0 20.0 20.0 20.0 20.0 76.0 86.0 + 93.0 92.0 91.0 104.0 104.5 107.0 97.5 104.0 + 30.0 30.0 30.0 30.0 30.1 30.2 84.0 96.0 + 98.0 99.0 96.0 101.0 102.0 99.0 94.0 99.0 + 30.0 33.4 36.8 40.0 43.0 45.6 100.0 106.0 + 106.0 108.0 101.0 99.0 98.0 99.0 95.0 95.0 + 42.0 44.0 46.0 48.0 50.0 51.0 109.0 111.0 + 110.0 110.0 103.0 95.5 95.5 95.0 92.5 92.0 + 60.0 61.7 63.5 65.5 67.3 69.2 122.0 124.0 + 124.0 121.0 103.0 93.2 92.5 92.2 90.0 90.8 + 70.0 70.1 70.2 70.3 70.4 70.5 137.0 132.0 + 134.0 128.0 101.0 91.7 90.2 88.8 87.3 85.8 + 78.0 77.6 77.2 76.8 76.4 76.0 167.0 159.0 + 152.0 144.0 103.0 89.8 87.7 85.7 83.7 81.8 + 98.9 97.8 96.7 95.5 94.3 93.2 183.0 172.0 + 162.0 152.0 102.0 87.5 85.3 83.3 81.3 79.3 + 160.0 157.0 155.0 152.0 149.0 147.0 186.0 175.0 + 165.0 156.0 120.0 87.0 84.9 82.8 80.8 79.0 + 272.0 266.0 260.0 254.0 248.0 242.0 192.0 182.0 + 170.0 159.0 131.0 88.0 85.8 83.7 81.6 79.6 + 382.0 372.0 362.0 352.0 343.0 333.0 205.0 192.0 + 178.0 166.0 138.0 86.2 84.0 82.0 79.8 77.5 + 770.0 740.0 710.0 680.0 650.0 618.0 226.0 207.0 + 195.0 180.0 160.0 82.9 80.2 77.7 75.2 72.7 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/maths/pca/pca.c Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,356 @@ +/*********************************/ +/* Principal Components Analysis */ +/*********************************/ + +/*********************************************************************/ +/* Principal Components Analysis or the Karhunen-Loeve expansion is a + classical method for dimensionality reduction or exploratory data + analysis. One reference among many is: F. Murtagh and A. Heck, + Multivariate Data Analysis, Kluwer Academic, Dordrecht, 1987. + + Author: + F. Murtagh + Phone: + 49 89 32006298 (work) + + 49 89 965307 (home) + Earn/Bitnet: fionn@dgaeso51, fim@dgaipp1s, murtagh@stsci + Span: esomc1::fionn + Internet: murtagh@scivax.stsci.edu + + F. Murtagh, Munich, 6 June 1989 */ +/*********************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#include "pca.h" + +#define SIGN(a, b) ( (b) < 0 ? -fabs(a) : fabs(a) ) + +/** Variance-covariance matrix: creation *****************************/ + +/* Create m * m covariance matrix from given n * m data matrix. */ +void covcol(double** data, int n, int m, double** symmat) +{ +double *mean; +int i, j, j1, j2; + +/* Allocate storage for mean vector */ + +mean = (double*) malloc(m*sizeof(double)); + +/* Determine mean of column vectors of input data matrix */ + +for (j = 0; j < m; j++) + { + mean[j] = 0.0; + for (i = 0; i < n; i++) + { + mean[j] += data[i][j]; + } + mean[j] /= (double)n; + } + +/* +printf("\nMeans of column vectors:\n"); +for (j = 0; j < m; j++) { + printf("%12.1f",mean[j]); } printf("\n"); + */ + +/* Center the column vectors. */ + +for (i = 0; i < n; i++) + { + for (j = 0; j < m; j++) + { + data[i][j] -= mean[j]; + } + } + +/* Calculate the m * m covariance matrix. */ +for (j1 = 0; j1 < m; j1++) + { + for (j2 = j1; j2 < m; j2++) + { + symmat[j1][j2] = 0.0; + for (i = 0; i < n; i++) + { + symmat[j1][j2] += data[i][j1] * data[i][j2]; + } + symmat[j2][j1] = symmat[j1][j2]; + } + } + +free(mean); + +return; + +} + +/** Error handler **************************************************/ + +void erhand(char* err_msg) +{ + fprintf(stderr,"Run-time error:\n"); + fprintf(stderr,"%s\n", err_msg); + fprintf(stderr,"Exiting to system.\n"); + exit(1); +} + + +/** Reduce a real, symmetric matrix to a symmetric, tridiag. matrix. */ + +/* Householder reduction of matrix a to tridiagonal form. +Algorithm: Martin et al., Num. Math. 11, 181-195, 1968. +Ref: Smith et al., Matrix Eigensystem Routines -- EISPACK Guide +Springer-Verlag, 1976, pp. 489-494. +W H Press et al., Numerical Recipes in C, Cambridge U P, +1988, pp. 373-374. */ +void tred2(double** a, int n, double* d, double* e) +{ + int l, k, j, i; + double scale, hh, h, g, f; + + for (i = n-1; i >= 1; i--) + { + l = i - 1; + h = scale = 0.0; + if (l > 0) + { + for (k = 0; k <= l; k++) + scale += fabs(a[i][k]); + if (scale == 0.0) + e[i] = a[i][l]; + else + { + for (k = 0; k <= l; k++) + { + a[i][k] /= scale; + h += a[i][k] * a[i][k]; + } + f = a[i][l]; + g = f>0 ? -sqrt(h) : sqrt(h); + e[i] = scale * g; + h -= f * g; + a[i][l] = f - g; + f = 0.0; + for (j = 0; j <= l; j++) + { + a[j][i] = a[i][j]/h; + g = 0.0; + for (k = 0; k <= j; k++) + g += a[j][k] * a[i][k]; + for (k = j+1; k <= l; k++) + g += a[k][j] * a[i][k]; + e[j] = g / h; + f += e[j] * a[i][j]; + } + hh = f / (h + h); + for (j = 0; j <= l; j++) + { + f = a[i][j]; + e[j] = g = e[j] - hh * f; + for (k = 0; k <= j; k++) + a[j][k] -= (f * e[k] + g * a[i][k]); + } + } + } + else + e[i] = a[i][l]; + d[i] = h; + } + d[0] = 0.0; + e[0] = 0.0; + for (i = 0; i < n; i++) + { + l = i - 1; + if (d[i]) + { + for (j = 0; j <= l; j++) + { + g = 0.0; + for (k = 0; k <= l; k++) + g += a[i][k] * a[k][j]; + for (k = 0; k <= l; k++) + a[k][j] -= g * a[k][i]; + } + } + d[i] = a[i][i]; + a[i][i] = 1.0; + for (j = 0; j <= l; j++) + a[j][i] = a[i][j] = 0.0; + } +} + +/** Tridiagonal QL algorithm -- Implicit **********************/ + +void tqli(double* d, double* e, int n, double** z) +{ + int m, l, iter, i, k; + double s, r, p, g, f, dd, c, b; + + for (i = 1; i < n; i++) + e[i-1] = e[i]; + e[n-1] = 0.0; + for (l = 0; l < n; l++) + { + iter = 0; + do + { + for (m = l; m < n-1; m++) + { + dd = fabs(d[m]) + fabs(d[m+1]); + if (fabs(e[m]) + dd == dd) break; + } + if (m != l) + { + if (iter++ == 30) erhand("No convergence in TLQI."); + g = (d[l+1] - d[l]) / (2.0 * e[l]); + r = sqrt((g * g) + 1.0); + g = d[m] - d[l] + e[l] / (g + SIGN(r, g)); + s = c = 1.0; + p = 0.0; + for (i = m-1; i >= l; i--) + { + f = s * e[i]; + b = c * e[i]; + if (fabs(f) >= fabs(g)) + { + c = g / f; + r = sqrt((c * c) + 1.0); + e[i+1] = f * r; + c *= (s = 1.0/r); + } + else + { + s = f / g; + r = sqrt((s * s) + 1.0); + e[i+1] = g * r; + s *= (c = 1.0/r); + } + g = d[i+1] - p; + r = (d[i] - g) * s + 2.0 * c * b; + p = s * r; + d[i+1] = g + p; + g = c * r - b; + for (k = 0; k < n; k++) + { + f = z[k][i+1]; + z[k][i+1] = s * z[k][i] + c * f; + z[k][i] = c * z[k][i] - s * f; + } + } + d[l] = d[l] - p; + e[l] = g; + e[m] = 0.0; + } + } while (m != l); + } +} + +/* In place projection onto basis vectors */ +void pca_project(double** data, int n, int m, int ncomponents) +{ + int i, j, k, k2; + double **symmat, **symmat2, *evals, *interm; + + //TODO: assert ncomponents < m + + symmat = (double**) malloc(m*sizeof(double*)); + for (i = 0; i < m; i++) + symmat[i] = (double*) malloc(m*sizeof(double)); + + covcol(data, n, m, symmat); + + /********************************************************************* + Eigen-reduction + **********************************************************************/ + + /* Allocate storage for dummy and new vectors. */ + evals = (double*) malloc(m*sizeof(double)); /* Storage alloc. for vector of eigenvalues */ + interm = (double*) malloc(m*sizeof(double)); /* Storage alloc. for 'intermediate' vector */ + //MALLOC_ARRAY(symmat2,m,m,double); + //for (i = 0; i < m; i++) { + // for (j = 0; j < m; j++) { + // symmat2[i][j] = symmat[i][j]; /* Needed below for col. projections */ + // } + //} + tred2(symmat, m, evals, interm); /* Triangular decomposition */ +tqli(evals, interm, m, symmat); /* Reduction of sym. trid. matrix */ +/* evals now contains the eigenvalues, +columns of symmat now contain the associated eigenvectors. */ + +/* + printf("\nEigenvalues:\n"); + for (j = m-1; j >= 0; j--) { + printf("%18.5f\n", evals[j]); } + printf("\n(Eigenvalues should be strictly positive; limited\n"); + printf("precision machine arithmetic may affect this.\n"); + printf("Eigenvalues are often expressed as cumulative\n"); + printf("percentages, representing the 'percentage variance\n"); + printf("explained' by the associated axis or principal component.)\n"); + + printf("\nEigenvectors:\n"); + printf("(First three; their definition in terms of original vbes.)\n"); + for (j = 0; j < m; j++) { + for (i = 1; i <= 3; i++) { + printf("%12.4f", symmat[j][m-i]); } + printf("\n"); } + */ + +/* Form projections of row-points on prin. components. */ +/* Store in 'data', overwriting original data. */ +for (i = 0; i < n; i++) { + for (j = 0; j < m; j++) { + interm[j] = data[i][j]; } /* data[i][j] will be overwritten */ + for (k = 0; k < ncomponents; k++) { + data[i][k] = 0.0; + for (k2 = 0; k2 < m; k2++) { + data[i][k] += interm[k2] * symmat[k2][m-k-1]; } + } +} + +/* +printf("\nProjections of row-points on first 3 prin. comps.:\n"); + for (i = 0; i < n; i++) { + for (j = 0; j < 3; j++) { + printf("%12.4f", data[i][j]); } + printf("\n"); } + */ + +/* Form projections of col.-points on first three prin. components. */ +/* Store in 'symmat2', overwriting what was stored in this. */ +//for (j = 0; j < m; j++) { +// for (k = 0; k < m; k++) { +// interm[k] = symmat2[j][k]; } /*symmat2[j][k] will be overwritten*/ +// for (i = 0; i < 3; i++) { +// symmat2[j][i] = 0.0; +// for (k2 = 0; k2 < m; k2++) { +// symmat2[j][i] += interm[k2] * symmat[k2][m-i-1]; } +// if (evals[m-i-1] > 0.0005) /* Guard against zero eigenvalue */ +// symmat2[j][i] /= sqrt(evals[m-i-1]); /* Rescale */ +// else +// symmat2[j][i] = 0.0; /* Standard kludge */ +// } +// } + +/* + printf("\nProjections of column-points on first 3 prin. comps.:\n"); + for (j = 0; j < m; j++) { + for (k = 0; k < 3; k++) { + printf("%12.4f", symmat2[j][k]); } + printf("\n"); } + */ + + +for (i = 0; i < m; i++) + free(symmat[i]); +free(symmat); +//FREE_ARRAY(symmat2,m); +free(evals); +free(interm); + +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/maths/pca/pca.h Wed Jan 09 10:31:29 2008 +0000 @@ -0,0 +1,16 @@ +#ifndef _PCA_H +#define _PCA_H + +/* + * pca.h + * soundbite + * + * Created by Mark Levy on 08/02/2006. + * Copyright 2006 Centre for Digital Music, Queen Mary, University of London. All rights reserved. + * + */ + +void pca_project(double** data, int n, int m, int ncomponents); + + +#endif \ No newline at end of file
--- a/qm-dsp.pro Wed Nov 21 16:53:51 2007 +0000 +++ b/qm-dsp.pro Wed Jan 09 10:31:29 2008 +0000 @@ -24,11 +24,6 @@ dsp/chromagram/ChromaProcess.h \ dsp/chromagram/ConstantQ.h \ dsp/keydetection/GetKeyMode.h \ - dsp/maths/Correlation.h \ - dsp/maths/Histogram.h \ - dsp/maths/MathAliases.h \ - dsp/maths/MathUtilities.h \ - dsp/maths/Polyfit.h \ dsp/onsets/DetectionFunction.h \ dsp/onsets/PeakPicking.h \ dsp/phasevocoder/PhaseVocoder.h \ @@ -41,14 +36,17 @@ dsp/tonal/ChangeDetectionFunction.h \ dsp/tonal/TCSgram.h \ dsp/tonal/TonalEstimator.h \ - dsp/transforms/FFT.h + dsp/transforms/FFT.h \ + maths/Correlation.h \ + maths/Histogram.h \ + maths/MathAliases.h \ + maths/MathUtilities.h \ + maths/Polyfit.h SOURCES += base/Pitch.cpp \ dsp/chromagram/Chromagram.cpp \ dsp/chromagram/ChromaProcess.cpp \ dsp/chromagram/ConstantQ.cpp \ dsp/keydetection/GetKeyMode.cpp \ - dsp/maths/Correlation.cpp \ - dsp/maths/MathUtilities.cpp \ dsp/onsets/DetectionFunction.cpp \ dsp/onsets/PeakPicking.cpp \ dsp/phasevocoder/PhaseVocoder.cpp \ @@ -61,4 +59,6 @@ dsp/tonal/ChangeDetectionFunction.cpp \ dsp/tonal/TCSgram.cpp \ dsp/tonal/TonalEstimator.cpp \ - dsp/transforms/FFT.cpp + dsp/transforms/FFT.cpp \ + maths/Correlation.cpp \ + maths/MathUtilities.cpp