头文件:
/* * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected] * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 or any later version. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. A copy of the GNU General Public License is available at: * http://www.fsf.org/licensing/licenses */ /***************************************************************************** * utilities.h * * Some usable routines converted from "Matlab", which are used in wavelet * transform and time-frequency analysis, such as "filp"(same to reverse), * "shift", "circshift", "fftshift", "dyadup", "wkeep", "wextend" and so on. * * Zhang Ming, 2010-01, Xi'an Jiaotong University. *****************************************************************************/ #ifndef UTILITIES_H #define UTILITIES_H #include <string> #include <vector.h> #include <fft.h> namespace splab { int mod( int, int ); int ceil( int, int ); template<typename Type> Vector<Type> reverse( const Vector<Type>& ); template<typename Type> Vector<Type> flip( const Vector<Type>& ); template<typename Type> Vector<Type> shift( const Vector<Type>& ); template<typename Type> Vector<Type> cirshift( const Vector<Type>& ); template<typename Type> Vector<Type> fftshift( const Vector<Type>& ); template<typename Type> Vector<Type> dyadUp( const Vector<Type>&, int ); template<typename Type> Vector<Type> dyadDown( const Vector<Type>&, int ); template<typename Type> Vector<Type> fftInterp( const Vector<Type>&, int ); template<typename Type> Vector< complex<Type> > fftInterp( const Vector< complex<Type> >&, int ); template<typename Type> Vector<Type> wkeep( const Vector<Type>&, int, int ); template<typename Type> Vector<Type> wkeep( const Vector<Type>&, int, const string &direction="center" ); template<typename Type> Vector<Type> wextend( const Vector<Type>&, int, const string &direction="both", const string &mode="zpd" ); #include <utilities-impl.h> } // namespace splab #endif // UTILITIES_H
实现文件:
/* * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected] * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 or any later version. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. A copy of the GNU General Public License is available at: * http://www.fsf.org/licensing/licenses */ /***************************************************************************** * utilities-impl.h * * Implementation for utilities. * * Zhang Ming, 2010-01 (revised 2010-08), Xi'an Jiaotong University. *****************************************************************************/ /** * Modulus after division. return a integer in the range of 0 to n-1. * e.g. -1%5=-1, mod(-1,5)=4 */ int mod( int m, int n ) { if( n != 0 ) { int r = m % n; if( r < 0 ) r += n; return r; } else { cerr << "The dividend shouldn't be zero." << endl; return 0; } } /** * Rounds the elements of a/b to the nearest integers * greater than or equal to a/b. * e.g. ceil(10,2) = 5, ceil(10,3)=4. */ int ceil( int m, int n ) { if( n != 0 ) { int q = m / n; if( m%n != 0 ) q += 1; return q; } else { cerr << "The dividend shouldn't be zero." << endl; return 0; } } /** * Flip vector left to right. */ template <typename Type> Vector<Type> reverse( const Vector<Type> &v ) { Vector<Type> tmp( v.size() ); typename Vector<Type>::iterator ib = tmp.begin(); typename Vector<Type>::const_iterator ie = v.end(); while( ib != tmp.end() ) *ib++ = *--ie; return tmp; } template <typename Type> inline Vector<Type> flip( const Vector<Type> &v ) { return reverse( v ); } /** * Vector's shift. */ template <typename Type> Vector<Type> shift( const Vector<Type> &v, int shiftsize ) { Vector<Type> tmp( v.dim() ); if( shiftsize >= 0 ) { typename Vector<Type>::iterator itrL = tmp.begin()+shiftsize; typename Vector<Type>::const_iterator itrR = v.begin(); while( itrL != tmp.end() ) *itrL++ = *itrR++; } else { typename Vector<Type>::iterator itrL = tmp.begin(); typename Vector<Type>::const_iterator itrR = v.begin()-shiftsize; while( itrR != v.end() ) *itrL++ = *itrR++; } return tmp; } /** * Vector's circulary shift. */ template <typename Type> Vector<Type> circshift( const Vector<Type> &v, int shiftsize ) { Vector<Type> tmp( v.dim() ); if( shiftsize >= 0 ) { typename Vector<Type>::iterator itrL = tmp.begin()+shiftsize; typename Vector<Type>::const_iterator itrR = v.begin(); while( itrL != tmp.end() ) *itrL++ = *itrR++; itrL = tmp.begin(); while( itrR != v.end() ) *itrL++ = *itrR++; } else { typename Vector<Type>::iterator itrL = tmp.begin(); typename Vector<Type>::const_iterator itrR = v.begin()-shiftsize; while( itrR != v.end() ) *itrL++ = *itrR++; itrR = v.begin(); while( itrL != tmp.end() ) *itrL++ = *itrR++; } return tmp; } /** * Vector's fft shift. */ template <typename Type> inline Vector<Type> fftshift( const Vector<Type> &v ) { int shiftsize = v.dim() - v.dim()/2 - 1; return circshift( v, shiftsize ); } /** * dyadic upsampling * w = dyadup(v, evenodd), where v is a vector, returns an extended * copy of vector v obtained by inserting zeros. Whether the zeros * are inserted as even- or odd-indexed elements of w depends on the * value of positive integer evenodd: * If evenodd is even, then w[2k]=0, w[2k+1]=v[k], w.size()=2*v.size()+1. * If evenodd is odd, then w[2k]=v[k], w[2k+1]=0. w.size()=2*v.size()-1. */ template <typename Type> Vector<Type> dyadUp( const Vector<Type> &v, int evenodd ) { int length = v.dim(); Vector<Type> tmp; if( evenodd%2 == 0 ) { tmp.resize( 2*length+1 ); for( int i=0; i<length; ++i ) { tmp[2*i] = 0; tmp[2*i+1] = v[i]; } tmp[2*length] = 0; } else { tmp.resize( 2*length-1 ); for( int i=0; i<length-1; ++i ) { tmp[2*i] = v[i]; tmp[2*i+1] = 0; } tmp[2*length-2] = v[length-1]; } return tmp; } /** * dyadic downsampling * w = dyadup(v, evenodd), where v is a vector, returns a version of v * that has been downsampled by 2. Whether w contains the even or odd * indexed samples of v depends on the value of positive integer evenodd: * If evenodd is even, then w[k]=v[2*k], w.size()=(v.size()+1)/2. * If evenodd is odd, then w[k]=v[2*k+1], w.size()=v.size()/2. */ template <typename Type> Vector<Type> dyadDown( const Vector<Type> &v, int evenodd ) { int length = v.dim(); Vector<Type> tmp; if( evenodd%2 == 0 ) { tmp.resize( (length+1)/2 ); for( int i=0; i<tmp.dim(); ++i ) tmp[i] = v[2*i]; } else { tmp.resize( length/2 ); for( int i=0; i<tmp.dim(); ++i ) tmp[i] = v[2*i+1]; } return tmp; } /** * Real signal interpolation by the method of padding zeros in frequency domain. * The interpolation factor should be >= 1. */ template <typename Type> Vector<Type> fftInterp( const Vector<Type> &sn, int factor ) { int N = sn.size(), halfN = N/2, offset = (factor-1)*N; Vector< complex<Type> > Sk = fft(sn); Vector< complex<Type> > Xk(factor*N); for( int i=0; i<=halfN; ++i ) Xk[i] = Type(factor)*Sk[i]; for( int i=halfN+1; i<N; ++i ) Xk[offset+i] = Type(factor)*Sk[i]; return ifftc2r(Xk); } /** * Complex signal interpolation by the method of padding zeros in frequency domain. * The interpolation factor should be >= 1. */ template <typename Type> Vector< complex<Type> > fftInterp( const Vector< complex<Type> > &sn, int factor ) { int N = sn.size(), halfN = N/2, offset = (factor-1)*N; Vector< complex<Type> > Sk = fft(sn); Vector< complex<Type> > Xk(factor*N); for( int i=0; i<=halfN; ++i ) Xk[i] = Type(factor)*Sk[i]; for( int i=halfN+1; i<N; ++i ) Xk[offset+i] = Type(factor)*Sk[i]; return ifft(Xk); } /** * Keep part of vector. * For a vector, w = wkeep(v,L,opt) extracts the vector w from the vector v. * The length of w is L. If direction = "center" ("left", "rigth", * respectively), w is the central (left, right, respectively) part of v. * w = wkeep(x,L) is equivalent to w = wkeep(v,L,"center"). * w = wkeep(v,L,first) returns the vector v[first] to v[first+L-1]. */ template <typename Type> Vector<Type> wkeep( const Vector<Type> &v, int length, int first ) { Vector<Type> tmp(length); if( ( 0 < length ) && ( length <= v.dim()-first ) ) { for( int i=0; i<length; ++i ) tmp[i] = v[first+i]; return tmp; } else { cerr << "Invalid length input." << endl; return tmp; } } template <typename Type> Vector<Type> wkeep( const Vector<Type> &v, int length, const string &direction ) { int lv = v.dim(); Vector<Type> tmp(length); if( ( 0 <= length ) && ( length <= lv ) ) { if( direction == "right" ) for( int i=0; i<length; ++i ) tmp[i] = v[lv-length+i]; else if( direction == "left" ) for( int i=0; i<length; ++i ) tmp[i] = v[i]; else { int first = (lv-length)/2; for( int i=0; i<length; ++i ) tmp[i] = v[first+i]; } return tmp; } else { cerr << "Invalid length input." << endl; return tmp; } } /** * extend vector * The extension types are specified by the string "direction", include * "left", "right" and "both". The default type is "both". The valid * extension modes, which specified by strint "mode" are: zero padding * ("zpd"), periodized extension("ppd") and symetirc extension("sym"). * The default mode is "zpd". */ template <typename Type> Vector<Type> wextend( const Vector<Type> &v, int extLength, const string &direction, const string &mode ) { if( extLength >= 0 ) { Vector<Type> tmp; int lv = v.dim(); if( direction == "right" ) { tmp.resize( lv+extLength ); for( int i=0; i<lv; ++i ) tmp[i] = v[i]; if( mode == "sym" ) for( int i=0; i<extLength; ++i ) tmp[lv+i] = v[lv-1-i]; else if( mode == "ppd" ) for( int i=0; i<extLength; ++i ) tmp[lv+i] = v[i]; else for( int i=0; i<extLength; ++i ) tmp[lv+i] = 0; } else if( direction == "left" ) { tmp.resize( lv+extLength ); if( mode == "sym" ) for( int i=0; i<extLength; ++i ) tmp[i] = v[extLength-1-i]; else if( mode == "ppd" ) for( int i=0; i<extLength; ++i ) tmp[i] = v[lv-extLength+i]; else for( int i=0; i<extLength; ++i ) tmp[i] = 0; for( int i=0; i<lv; ++i ) tmp[i+extLength] = v[i]; } else { tmp.resize( lv+2*extLength ); for( int i=0; i<lv; ++i ) tmp[i+extLength] = v[i]; if( mode == "sym" ) for( int i=0; i<extLength; ++i ) { tmp[i] = v[extLength-1-i]; tmp[lv+extLength+i] = v[lv-1-i]; } else if( mode == "ppd" ) for( int i=0; i<extLength; ++i ) { tmp[i] = v[lv-extLength+i]; tmp[lv+extLength+i] = v[i]; } else for( int i=0; i<extLength; ++i ) { tmp[i] = 0; tmp[lv+extLength+i] = 0; } } return tmp; } else { cerr << "The extesion length should be greater zero." << endl; return Vector<Type>(0); } }
测试代码:
/***************************************************************************** * utilities_test.cpp * * Utilities testing. * * Zhang Ming, 2010-01, Xi'an Jiaotong University. *****************************************************************************/ #define BOUNDS_CHECK #include <iostream> #include <iomanip> #include <string> #include <utilities.h> using namespace std; using namespace splab; const int N = 5; int main() { Vector<int> v1(N); for( int i=1; i<=v1.dim(); i++ ) v1(i) = i; cout << "vector v1 : " << v1 << endl; Vector<int> v2(N); for( int i=1; i<=v2.dim(); ++i ) v2(i) = i+N; cout << "vector v2 : " << v2 << endl; int N = 11; double a = 0; double b = 1.0; Vector<double> x = linspace( a, b, N ); cout << N << " points linearly spaced from 0 to 1.0" << x << endl; cout << "Flipping vector v1 from left to right : " << flip(v1) << endl; cout << "Shift vector v1 from left to right : " << shift(v1,2) << endl; cout << "Shift vector v1 from right to left : " << shift(v1,-2) << endl; cout << "Circle shift vector v1 from left to right : " << circshift(v1,2) << endl; cout << "Circle shift vector v1 from right to left : " << circshift(v1,-2) << endl; cout << "FFT shift of vector : " << fftshift(v1) << endl; cout << "Dyadic upsampling of vector v1 by zeros at the even position : " << dyadUp( v1,0 ) << endl; cout << "Dyadic upsampling of vector v1 by zeros at the odd position : " << dyadUp( v1,1 ) << endl; cout << "Dyadic downsampling of vector v1 by zeros at the even position : " << dyadDown( v1,0 ) << endl; cout << "Dyadic downsampling of vector v1 by zeros at the odd position : " << dyadDown( v1,1 ) << endl; Vector<float> sn(N); Vector< complex<float> > cn(N); for( int i=0; i<N; ++i ) { sn[i] = float(sin(i*TWOPI/N)); cn[i] = complex<float>( float(sin(i*TWOPI/N)), float(cos(i*TWOPI/N)) ); } cout << setiosflags(ios::fixed) << setprecision(4); cout << "real signal sn : " << sn << endl; cout << "FFT interpolation of sn by factor fo 2 : " << fftInterp( sn, 2 ) << endl; cout << "complex signal cn : " << cn << endl; cout << "FFT interpolation of sn by factor fo 2 : " << fftInterp( cn, 2 ) << endl; cout << resetiosflags(ios::fixed); int n = 2; string dire = "left"; string mode = "zpd"; cout << "Extending vector v1 in left direction by zeros padding : " << wextend( v1,n,dire,mode ) << endl; mode = "ppd"; cout << "Extending vector v1 in left direction by periodic mode : " << wextend( v1,n,dire,mode ) << endl; mode = "sym"; cout << "Extending vector v1 in left direction by symmetric mode : " << wextend( v1,n,dire,mode ) << endl; dire = "right"; mode = "zpd"; cout << "Extending vector v1 in right direction by zeros padding : " << wextend( v1,n,dire,mode ) << endl; mode = "ppd"; cout << "Extending vector v1 in right direction by periodic mode : " << wextend( v1,n,dire,mode ) << endl; mode = "sym"; cout << "Extending vector v1 in right direction by symmetric mode : " << wextend( v1,n,dire,mode ) << endl; dire = "both"; mode = "zpd"; cout << "Extending vector v1 in both direction by zeros padding : " << wextend( v1,n,dire,mode ) << endl; mode = "ppd"; cout << "Extending vector v1 in both direction by periodic mode : " << wextend( v1,n,dire,mode ) << endl; mode = "sym"; cout << "Extending vector v1 in both direction by symmetric mode : " << wextend( v1,n,dire,mode ) << endl; cout << "Keeping the center part of vector v1 : " << wkeep( v1,3,"center" ) << endl; cout << "Keeping the left part of vector v1 : " << wkeep( v1,3,"left" ) << endl; cout << "Keeping the right part of vector v1 : " << wkeep( v1,3,"right" ) << endl; cout << "Keeping the first(2) to first + L(3) elements of vector v1 : " << wkeep( v1,3,2 ) << endl; cout << "The modulus of 2 divided by 5 is " << mod(2,5) << "." << endl; cout << "The modulus of -1 divided by 5 is " << mod(-1,5) << "." << endl; cout << endl; cout << "The nearest integer >= 10/2 is " << ceil(10,2) << "." << endl; cout << "The nearest integer >= 10/3 is " << ceil(10,3) << "." << endl; cout << endl; cout << "The numbers can be represented by the integer power of 2 " << "from 0 to 1000 are : " << endl; return 0; }
运行结果:
vector v1 : size: 5 by 1 1 2 3 4 5 vector v2 : size: 5 by 1 6 7 8 9 10 11 points linearly spaced from 0 to 1.0size: 11 by 1 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 Flipping vector v1 from left to right : size: 5 by 1 5 4 3 2 1 Shift vector v1 from left to right : size: 5 by 1 0 0 1 2 3 Shift vector v1 from right to left : size: 5 by 1 3 4 5 0 0 Circle shift vector v1 from left to right : size: 5 by 1 4 5 1 2 3 Circle shift vector v1 from right to left : size: 5 by 1 3 4 5 1 2 FFT shift of vector : size: 5 by 1 4 5 1 2 3 Dyadic upsampling of vector v1 by zeros at the even position : size: 11 by 1 0 1 0 2 0 3 0 4 0 5 0 Dyadic upsampling of vector v1 by zeros at the odd position : size: 9 by 1 1 0 2 0 3 0 4 0 5 Dyadic downsampling of vector v1 by zeros at the even position : size: 3 by 1 1 3 5 Dyadic downsampling of vector v1 by zeros at the odd position : size: 2 by 1 2 4 real signal sn : size: 11 by 1 0.0000 0.5406 0.9096 0.9898 0.7557 0.2817 -0.2817 -0.7557 -0.9898 -0.9096 -0.5406 FFT interpolation of sn by factor fo 2 : size: 22 by 1 0.0000 0.2817 0.5406 0.7557 0.9096 0.9898 0.9898 0.9096 0.7557 0.5406 0.2817 -0.0000 -0.2817 -0.5406 -0.7557 -0.9096 -0.9898 -0.9898 -0.9096 -0.7557 -0.5406 -0.2817 complex signal cn : size: 11 by 1 (0.0000,1.0000) (0.5406,0.8413) (0.9096,0.4154) (0.9898,-0.1423) (0.7557,-0.6549) (0.2817,-0.9595) (-0.2817,-0.9595) (-0.7557,-0.6549) (-0.9898,-0.1423) (-0.9096,0.4154) (-0.5406,0.8413) FFT interpolation of sn by factor fo 2 : size: 22 by 1 (0.0000,1.0000) (0.2817,0.9595) (0.5406,0.8413) (0.7557,0.6549) (0.9096,0.4154) (0.9898,0.1423) (0.9898,-0.1423) (0.9096,-0.4154) (0.7557,-0.6549) (0.5406,-0.8413) (0.2817,-0.9595) (0.0000,-1.0000) (-0.2817,-0.9595) (-0.5406,-0.8413) (-0.7557,-0.6549) (-0.9096,-0.4154) (-0.9898,-0.1423) (-0.9898,0.1423) (-0.9096,0.4154) (-0.7558,0.6549) (-0.5406,0.8413) (-0.2817,0.9595) Extending vector v1 in left direction by zeros padding : size: 7 by 1 0 0 1 2 3 4 5 Extending vector v1 in left direction by periodic mode : size: 7 by 1 4 5 1 2 3 4 5 Extending vector v1 in left direction by symmetric mode : size: 7 by 1 2 1 1 2 3 4 5 Extending vector v1 in right direction by zeros padding : size: 7 by 1 1 2 3 4 5 0 0 Extending vector v1 in right direction by periodic mode : size: 7 by 1 1 2 3 4 5 1 2 Extending vector v1 in right direction by symmetric mode : size: 7 by 1 1 2 3 4 5 5 4 Extending vector v1 in both direction by zeros padding : size: 9 by 1 0 0 1 2 3 4 5 0 0 Extending vector v1 in both direction by periodic mode : size: 9 by 1 4 5 1 2 3 4 5 1 2 Extending vector v1 in both direction by symmetric mode : size: 9 by 1 2 1 1 2 3 4 5 5 4 Keeping the center part of vector v1 : size: 3 by 1 2 3 4 Keeping the left part of vector v1 : size: 3 by 1 1 2 3 Keeping the right part of vector v1 : size: 3 by 1 3 4 5 Keeping the first(2) to first + L(3) elements of vector v1 : size: 3 by 1 3 4 5 The modulus of 2 divided by 5 is 2. The modulus of -1 divided by 5 is 4. The nearest integer >= 10/2 is 5. The nearest integer >= 10/3 is 4. The numbers can be represented by the integer power of 2 from 0 to 1000 are : Process returned 0 (0x0) execution time : 0.234 s Press any key to continue.