30#ifdef MX_INCLUDE_BOOST
31#include <boost/math/tools/minima.hpp>
38#include "../../sys/timeUtils.hpp"
40#include "../../math/constants.hpp"
52template <
typename realT>
53struct clGainOptOptGain_OL;
62template <
typename _realT>
66 typedef std::complex<_realT> complexT;
73 std::vector<realT> _b;
74 std::vector<realT> _a;
76 std::vector<realT> _f;
82 Eigen::Array<realT, -1, -1> _cs;
83 Eigen::Array<realT, -1, -1> _ss;
85 std::vector<std::complex<realT>> _H_dm, _H_wfs, _H_ma, _H_del, _H_con;
101 realT _minFindMaxFact;
104 uintmax_t _minFindMaxIter;
141 void Ti( realT newTi );
152 void tau( realT newTau );
157 void b(
const std::vector<realT> &newB );
162 void b(
const Eigen::Array<realT, -1, -1>
165 void bScale( realT scale )
167 for(
size_t n = 0; n < _b.size(); ++n )
176 void a(
const std::vector<realT> &newA );
181 void a(
const Eigen::Array<realT, -1, -1>
189 void aScale( realT scale )
191 for(
size_t n = 0; n < _a.size(); ++n )
201 void setLeakyIntegrator( realT remember );
213 void f( std::vector<realT> &newF );
236 complexT olXfer(
int fi,
248 complexT olXfer(
int fi );
254 complexT clETF(
int fi,
262 realT clETFPhase(
int fi,
270 realT clETF2(
int fi,
278 complexT clNTF(
int fi,
286 realT clNTF2(
int fi,
295 void clTF2( realT &ETF,
314 realT clVariance( realT &varErr,
316 const std::vector<realT> &PSDerr,
317 const std::vector<realT> &PSDnoise,
328 realT clVariance(
const std::vector<realT> &PSDerr,
329 const std::vector<realT> &PSDnoise,
345 realT maxStableGain( realT &ll,
358 realT maxStableGain(
const realT &ll,
372 realT maxStableGain();
378 realT optGainOpenLoop(
380 const std::vector<realT> &PSDerr,
381 const std::vector<realT> &PSDnoise,
389 realT optGainOpenLoop(
391 const std::vector<realT> &PSDerr,
392 const std::vector<realT> &PSDnoise,
401 int pseudoOpenLoop( std::vector<realT> &PSD,
406 int nyquist( std::vector<realT> &re, std::vector<realT> &im, realT g );
409template <
typename realT>
410clGainOpt<realT>::clGainOpt()
415template <
typename realT>
416clGainOpt<realT>::clGainOpt( realT Ti, realT tau )
424template <
typename realT>
425void clGainOpt<realT>::init()
429 setLeakyIntegrator( 1.0 );
437 _minFindMaxFact = 0.999;
438 _minFindBits = std::numeric_limits<realT>::digits;
439 _minFindMaxIter = 10000;
445template <
typename realT>
446int clGainOpt<realT>::N()
451template <
typename realT>
452void clGainOpt<realT>::N(
int newN )
458template <
typename realT>
459realT clGainOpt<realT>::Ti()
464template <
typename realT>
465void clGainOpt<realT>::Ti( realT newTi )
471template <
typename realT>
472realT clGainOpt<realT>::tau()
477template <
typename realT>
478void clGainOpt<realT>::tau( realT newTau )
484template <
typename realT>
485void clGainOpt<realT>::b(
const std::vector<realT> &newB )
487 if( newB.size() > (
size_t)_cs.cols() )
496template <
typename realT>
497void clGainOpt<realT>::b(
const Eigen::Array<realT, -1, -1> &newB )
499 if( newB.cols() > _cs.cols() )
504 _b.resize( newB.cols() );
506 for(
size_t i = 0; i < _b.size(); ++i )
508 _b[i] = newB( 0, i );
514template <
typename realT>
515void clGainOpt<realT>::a(
const std::vector<realT> &newA )
517 if( newA.size() + 1 > (
size_t)_cs.cols() )
526template <
typename realT>
527void clGainOpt<realT>::a(
const Eigen::Array<realT, -1, -1> &newA )
529 if( newA.cols() + 1 > _cs.cols() )
534 _a.resize( newA.cols() );
536 for(
size_t i = 0; i < _a.size(); ++i )
538 _a[i] = newA( 0, i );
544template <
typename realT>
545void clGainOpt<realT>::setLeakyIntegrator( realT remember )
557template <
typename realT>
558void clGainOpt<realT>::f( realT *newF,
size_t nF )
561 for(
int i = 0; i < nF; ++i )
568template <
typename realT>
569void clGainOpt<realT>::f( std::vector<realT> &newF )
577template <
typename realT>
578realT clGainOpt<realT>::f(
size_t i )
584template <
typename realT>
585std::complex<realT> clGainOpt<realT>::olXfer(
int fi )
591 return olXfer( fi, H_dm, H_del, H_con );
598template <
typename realT>
599std::complex<realT> clGainOpt<realT>::olXfer(
int fi, complexT &H_dm, complexT &H_del, complexT &H_con )
618 size_t jmax = std::max( _a.size() + 1, _b.size() );
620 _cs.resize( _f.size(), jmax );
621 _ss.resize( _f.size(), jmax );
623 for(
size_t i = 0; i < _f.size(); ++i )
628 for(
size_t j = 1; j < jmax; ++j )
641 _H_dm.resize( _f.size(), 0 );
642 _H_wfs.resize( _f.size(), 0 );
643 _H_ma.resize( _f.size(), 0 );
644 _H_del.resize( _f.size(), 0 );
645 _H_con.resize( _f.size(), 0 );
647 size_t jmax = std::min( _a.size(), _b.size() );
650 for(
size_t i = 0; i < _f.size(); ++i )
662 complexT expsT = exp( -s * _Ti );
666 _H_dm[i] = std::complex<realT>( 1, 0 );
670 _H_dm[i] = ( realT( 1 ) - expsT ) / ( s * _Ti );
673 _H_wfs[i] = _H_dm[i];
677 _H_del[i] = exp( -s * _tau );
679 complexT FIR = complexT( _b[0], 0 );
681 complexT IIR = complexT( 0.0, 0.0 );
682 for(
size_t j = 1; j < jmax; ++j )
685 realT cs = _cs( i, j );
686 realT ss = _ss( i, j );
687 FIR += _b[j] * complexT( cs, -ss );
688 IIR += _a[j - 1] * complexT( cs, -ss );
690 complexT expZ = exp( -s * _Ti * realT( j ) );
692 IIR += _a[j - 1] * expZ;
696 for(
size_t jj = jmax; jj < _a.size() + 1; ++jj )
699 realT cs = _cs( i, jj );
700 realT ss = _ss( i, jj );
701 IIR += _a[jj - 1] * complexT( cs, -ss );
703 complexT expZ = exp( -s * _Ti * realT( jj ) );
704 IIR += _a[jj - 1] * expZ;
708 for(
size_t jj = jmax; jj < _b.size(); ++jj )
711 realT cs = _cs( i, jj );
712 realT ss = _ss( i, jj );
713 FIR += _b[jj] * complexT( cs, -ss );
715 complexT expZ = exp( -s * _Ti * realT( jj ) );
716 FIR += _b[jj] * expZ;
720 _H_con[i] = FIR / ( realT( 1.0 ) - IIR );
737 return ( _H_dm[fi] * _H_wfs[fi] * _H_del[fi] * _H_con[fi] );
740template <
typename realT>
741std::complex<realT> clGainOpt<realT>::clETF(
int fi, realT g )
751 return ( realT( 1 ) / ( realT( 1 ) + g * olXfer( fi ) ) );
754template <
typename realT>
755realT clGainOpt<realT>::clETFPhase(
int fi, realT g )
765 return std::arg( ( realT( 1 ) / ( realT( 1 ) + g * olXfer( fi ) ) ) );
768template <
typename realT>
769realT clGainOpt<realT>::clETF2(
int fi, realT g )
779 return norm( realT( 1 ) / ( realT( 1 ) + g * olXfer( fi ) ) );
782template <
typename realT>
783std::complex<realT> clGainOpt<realT>::clNTF(
int fi, realT g )
793 complexT H_dm, H_del, H_con;
795 complexT olX = olXfer( fi, H_dm, H_del, H_con );
797 return -( H_dm * H_del * g * H_con ) / ( realT( 1 ) + g * olX );
800template <
typename realT>
801realT clGainOpt<realT>::clNTF2(
int fi, realT g )
811 complexT H_dm, H_del, H_con;
813 complexT olX = olXfer( fi, H_dm, H_del, H_con );
815 complexT NTF = -( H_dm * H_del * g * H_con ) / ( realT( 1 ) + g * olX );
820template <
typename realT>
821void clGainOpt<realT>::clTF2( realT &ETF, realT &NTF,
int fi, realT g )
834 complexT H_dm, H_del, H_con;
836 complexT olX = olXfer( fi, H_dm, H_del, H_con );
842 ETF = norm( realT( 1 ) / ( realT( 1 ) + g * olX ) );
843 NTF = norm( -( H_dm * H_del * g * H_con ) / ( realT( 1 ) + g * olX ) );
851template <
typename realT>
852realT clGainOpt<realT>::clVariance(
853 realT &varErr, realT &varNoise,
const std::vector<realT> &PSDerr,
const std::vector<realT> &PSDnoise, realT g )
855 if( _f.size() != PSDerr.size() || _f.size() != PSDnoise.size() )
857 std::cerr <<
"clVariance: Frequency grid and PSDs must be same size." << std::endl;
868 for(
size_t i = 0; i < PSDerr.size(); ++i )
877 clTF2( ETF, NTF, i, g );
879 varErr += ETF * PSDerr[i] * df;
880 varNoise += NTF * PSDnoise[i] * df;
883 return varErr + varNoise;
886template <
typename realT>
887realT clGainOpt<realT>::clVariance(
const std::vector<realT> &PSDerr,
const std::vector<realT> &PSDnoise, realT g )
892 return clVariance( varErr, varNoise, PSDerr, PSDnoise, g );
895template <
typename realT>
896realT clGainOpt<realT>::maxStableGain( realT &ll, realT &ul )
898 static_cast<void>( ul );
900 std::vector<realT> re, im;
905 nyquist( re, im, 1.0 );
907 int gi_c = re.size() - 1;
909 for(
int gi = re.size() - 2; gi >= 0; --gi )
911 if( -1.0 / re[gi] < ll )
914 if( ( re[gi] < 0 ) && ( im[gi + 1] >= 0 && im[gi] < 0 ) )
917 if( re[gi] <= re[gi_c] )
922 return -1.0 / re[gi_c];
925template <
typename realT>
926realT maxStableGain(
const realT &ll,
const realT &ul )
931 maxStableGain( rll, rul );
934template <
typename realT>
935realT clGainOpt<realT>::maxStableGain()
938 realT ll = _maxFindMin;
940 return maxStableGain( ll, ul );
947template <
typename realT>
948realT optGainOpenLoop( clGainOptOptGain_OL<realT> &olgo,
951 const realT &minFindMin,
952 const realT &minFindMaxFact,
954 uintmax_t minFindMaxIter,
957#ifdef MX_INCLUDE_BOOST
962 std::pair<realT, realT> brack;
963 brack = boost::math::tools::brent_find_minima<clGainOptOptGain_OL<realT>, realT>(
964 olgo, minFindMin, minFindMaxFact * gmax, minFindBits, minFindMaxIter, iters );
970 std::cerr <<
"optGainOpenLoop: No root found\n";
971 gopt = minFindMaxFact * gmax;
977 static_assert( std::is_fundamental<realT>::value || !std::is_fundamental<realT>::value,
978 "impl::optGainOpenLoop<realT> is not specialized for type realT, and MX_INCLUDE_BOOST is not "
979 "defined, so I can't just use boost." );
985float optGainOpenLoop<float>( clGainOptOptGain_OL<float> &olgo,
988 const float &minFindMin,
989 const float &minFindMaxFact,
991 uintmax_t minFindMaxIter,
995double optGainOpenLoop<double>( clGainOptOptGain_OL<double> &olgo,
998 const double &minFindMin,
999 const double &minFindMaxFact,
1001 uintmax_t minFindMaxIter,
1005long double optGainOpenLoop<long double>( clGainOptOptGain_OL<long double> &olgo,
1007 const long double &gmax,
1008 const long double &minFindMin,
1009 const long double &minFindMaxFact,
1011 uintmax_t minFindMaxIter,
1016__float128 optGainOpenLoop<__float128>( clGainOptOptGain_OL<__float128> &olgo,
1018 const __float128 &gmax,
1019 const __float128 &minFindMin,
1020 const __float128 &minFindMaxFact,
1022 uintmax_t minFindMaxIter,
1028template <
typename realT>
1029realT clGainOpt<realT>::optGainOpenLoop( realT &var,
1030 const std::vector<realT> &PSDerr,
1031 const std::vector<realT> &PSDnoise,
1035 return optGainOpenLoop( var, PSDerr, PSDnoise, gmax, gridSearch );
1038template <
typename realT>
1039realT clGainOpt<realT>::optGainOpenLoop(
1040 realT &var,
const std::vector<realT> &PSDerr,
const std::vector<realT> &PSDnoise, realT &gmax,
bool gridSearch )
1042 clGainOptOptGain_OL<realT> olgo;
1044 olgo.PSDerr = &PSDerr;
1045 olgo.PSDnoise = &PSDnoise;
1048 gmax = maxStableGain();
1050 realT ming = _minFindMin;
1055 realT gstpsz = 0.05;
1056 realT gg = _minFindMaxFact * gmax;
1057 realT var0 = clVariance( PSDerr, PSDnoise, gg );
1060 while( gg > _minFindMin )
1063 realT var1 = clVariance( PSDerr, PSDnoise, gg );
1072 ming = mingg - gstpsz;
1073 maxg = mingg + gstpsz;
1075 if( ming < _minFindMin )
1082 realT val = impl::optGainOpenLoop( olgo, var, maxg, ming, _minFindMaxFact, _minFindBits, _minFindMaxIter, iters );
1084 if( iters >= _minFindMaxIter )
1088 std::cerr <<
"\nclGainOpt<realT>::optGainOpenLoop: minFindMaxIter (" << _minFindMaxIter <<
") reached\n";
1095template <
typename realT>
1096int clGainOpt<realT>::pseudoOpenLoop( std::vector<realT> &PSD, realT g )
1099 for(
int f = 0; f < _f.size(); ++f )
1104 PSD[f] = PSD[f] / e;
1110template <
typename realT>
1111int clGainOpt<realT>::nyquist( std::vector<realT> &re, std::vector<realT> &im, realT g )
1113 re.resize( _f.size() );
1114 im.resize( _f.size() );
1118 for(
size_t f = 0; f < _f.size(); ++f )
1120 etf = g * olXfer( f );
1121 re[f] = real( etf );
1122 im[f] = imag( etf );
1131template <
typename realT>
1132struct clGainOptOptGain_OL
1134 clGainOpt<realT> *go;
1135 const std::vector<realT> *PSDerr;
1136 const std::vector<realT> *PSDnoise;
1138 realT operator()(
const realT &g )
1140 return go->clVariance( *PSDerr, *PSDnoise, g );
1145extern template class clGainOpt<float>;
1147extern template class clGainOpt<double>;
1149extern template class clGainOpt<long double>;
1152extern template class clGainOpt<__float128>;
constexpr floatT six_fifths()
Return 6/5 in the specified precision.