30 #ifdef MX_INCLUDE_BOOST
31 #include <boost/math/tools/minima.hpp>
34 #include <type_traits>
36 #include <Eigen/Dense>
38 #include "../../sys/timeUtils.hpp"
40 #include "../../math/constants.hpp"
52 template<
typename realT>
53 struct clGainOptOptGain_OL;
62 template<
typename _realT>
66 typedef std::complex<_realT> complexT;
74 std::vector<realT> _b;
75 std::vector<realT> _a;
77 std::vector<realT> _f;
83 Eigen::Array<realT, -1, -1> _cs;
84 Eigen::Array<realT, -1, -1> _ss;
86 std::vector<std::complex<realT> > _H_dm, _H_wfs, _H_ma, _H_del, _H_con;
102 realT _minFindMaxFact;
104 uintmax_t _minFindMaxIter;
142 void Ti( realT newTi );
153 void tau( realT newTau );
158 void b(
const std::vector<realT> & newB );
163 void b(
const Eigen::Array<realT, -1, -1> & newB );
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> & newA );
183 realT a(
size_t i) {
return _a[i];}
185 void aScale( realT scale)
187 for(
size_t n=0; n < _a.size(); ++n)
197 void setLeakyIntegrator( realT remember );
202 void f ( realT * newF,
209 void f ( std::vector<realT> & newF );
232 complexT olXfer(
int fi,
244 complexT olXfer(
int fi );
251 complexT clETF(
int fi,
259 realT clETFPhase(
int fi,
267 realT clETF2(
int fi,
275 complexT clNTF(
int fi,
283 realT clNTF2(
int fi,
292 void clTF2( realT & ETF,
311 realT clVariance( realT & varErr,
313 std::vector<realT> & PSDerr,
314 std::vector<realT> & PSDnoise,
325 realT clVariance( std::vector<realT> & PSDerr,
326 std::vector<realT> & PSDnoise,
343 realT maxStableGain( realT & ll,
356 realT maxStableGain(
const realT & ll,
370 realT maxStableGain();
376 realT optGainOpenLoop( realT & var,
377 std::vector<realT> & PSDerr,
378 std::vector<realT> & PSDnoise
385 realT optGainOpenLoop( realT & var,
386 std::vector<realT> & PSDerr,
387 std::vector<realT> & PSDnoise,
395 int pseudoOpenLoop( std::vector<realT> & PSD,
399 int nyquist( std::vector<realT> & re,
400 std::vector<realT> & im,
405 template<
typename realT>
406 clGainOpt<realT>::clGainOpt()
411 template<
typename realT>
412 clGainOpt<realT>::clGainOpt(realT Ti, realT tau)
420 template<
typename realT>
421 void clGainOpt<realT>::init()
425 setLeakyIntegrator(1.0);
433 _minFindMaxFact = 0.999;
434 _minFindBits = std::numeric_limits<realT>::digits;
435 _minFindMaxIter = 1000;
442 template<
typename realT>
443 int clGainOpt<realT>::N()
448 template<
typename realT>
449 void clGainOpt<realT>::N(
int newN )
455 template<
typename realT>
456 realT clGainOpt<realT>::Ti()
461 template<
typename realT>
462 void clGainOpt<realT>::Ti( realT newTi)
468 template<
typename realT>
469 realT clGainOpt<realT>::tau()
474 template<
typename realT>
475 void clGainOpt<realT>::tau(realT newTau)
481 template<
typename realT>
482 void clGainOpt<realT>::b(
const std::vector<realT> & newB)
484 if( newB.size() > (
size_t) _cs.cols() )
493 template<
typename realT>
494 void clGainOpt<realT>::b(
const Eigen::Array<realT, -1, -1> & newB)
496 if( newB.cols() > _cs.cols() )
501 _b.resize( newB.cols());
503 for(
size_t i=0; i< _b.size(); ++i)
511 template<
typename realT>
512 void clGainOpt<realT>::a (
const std::vector<realT> & newA)
514 if( newA.size()+1 > (
size_t) _cs.cols())
523 template<
typename realT>
524 void clGainOpt<realT>::a(
const Eigen::Array<realT, -1, -1> & newA)
526 if( newA.cols() +1 > _cs.cols())
531 _a.resize( newA.cols());
533 for(
size_t i=0; i< _a.size(); ++i)
541 template<
typename realT>
542 void clGainOpt<realT>::setLeakyIntegrator(realT remember)
554 template<
typename realT>
555 void clGainOpt<realT>::f(realT * newF,
size_t nF)
558 for(
int i=0; i< nF; ++i) _f[i] = newF[i];
564 template<
typename realT>
565 void clGainOpt<realT>::f(std::vector<realT> & newF)
573 template<
typename realT>
574 realT clGainOpt<realT>::f(
size_t i)
580 template<
typename realT>
581 std::complex<realT> clGainOpt<realT>::olXfer(
int fi)
587 return olXfer(fi, H_dm, H_del, H_con);
594 template<
typename realT>
595 std::complex<realT> clGainOpt<realT>::olXfer(
int fi, complexT & H_dm, complexT & H_del, complexT & H_con)
614 size_t jmax = std::max(_a.size()+1, _b.size());
616 _cs.resize(_f.size(), jmax);
617 _ss.resize(_f.size(), jmax);
619 for(
size_t i=0; i< _f.size(); ++i)
624 for(
size_t j = 1; j<jmax; ++j)
626 _cs(i,j) = cos(math::two_pi<realT>()*_f[i]*_Ti*realT(j));
627 _ss(i,j) = sin(math::two_pi<realT>()*_f[i]*_Ti*realT(j));
637 _H_dm.resize(_f.size(), 0);
638 _H_wfs.resize(_f.size(), 0);
639 _H_ma.resize(_f.size(), 0);
640 _H_del.resize(_f.size(), 0);
641 _H_con.resize(_f.size(), 0);
643 size_t jmax = std::min(_a.size(), _b.size());
646 for(
size_t i=0; i<_f.size(); ++i)
649 if(_f[i] <= 0)
continue;
651 if(_f[i] < 0)
continue;
654 complexT s = complexT(0.0, math::two_pi<realT>()*_f[i]);
656 complexT expsT = exp(-s*_Ti);
660 _H_dm[i] = std::complex<realT>(1,0);
664 _H_dm[i] = (realT(1) - expsT)/(s*_Ti);
667 _H_wfs[i] = _H_dm[i];
671 _H_del[i] = exp(-s*_tau);
673 complexT FIR = complexT(_b[0],0);
675 complexT IIR = complexT(0.0, 0.0);
676 for(
size_t j = 1; j < jmax; ++j)
681 FIR += _b[j]*complexT(cs, -ss);
682 IIR += _a[j-1]*complexT(cs, -ss);
684 complexT expZ = exp( -s*_Ti*realT(j));
690 for(
size_t jj=jmax; jj< _a.size()+1; ++jj)
693 realT cs = _cs(i,jj);
694 realT ss = _ss(i,jj);
695 IIR += _a[jj-1]*complexT(cs, -ss);
697 complexT expZ = exp( -s*_Ti*realT(jj));
698 IIR += _a[jj-1]*expZ;
702 for(
size_t jj=jmax; jj<_b.size(); ++jj)
705 realT cs = _cs(i,jj);
706 realT ss = _ss(i,jj);
707 FIR += _b[jj]*complexT(cs, -ss);
709 complexT expZ = exp( -s*_Ti*realT(jj));
714 _H_con[i] = FIR/( realT(1.0) - IIR);
731 return ( _H_dm[fi]*_H_wfs[fi]*_H_del[fi]*_H_con[fi]);
735 template<
typename realT>
736 std::complex<realT> clGainOpt<realT>::clETF(
int fi, realT g)
739 if(_f[fi] <= 0)
return 0;
741 if(_f[fi] < 0)
return 0;
744 return (realT(1)/( realT(1) + g*olXfer(fi)));
747 template<
typename realT>
748 realT clGainOpt<realT>::clETFPhase(
int fi, realT g)
751 if(_f[fi] <= 0)
return 0;
753 if(_f[fi] < 0)
return 0;
756 return std::arg((realT(1)/( realT(1) + g*olXfer(fi))));
759 template<
typename realT>
760 realT clGainOpt<realT>::clETF2(
int fi, realT g)
763 if(_f[fi] <= 0)
return 0;
765 if(_f[fi] < 0)
return 0;
768 return norm(realT(1)/( realT(1) + g*olXfer(fi)));
771 template<
typename realT>
772 std::complex<realT> clGainOpt<realT>::clNTF(
int fi,
777 if(_f[fi] <= 0)
return 0;
779 if(_f[fi] < 0)
return 0;
782 complexT H_dm, H_del, H_con;
784 complexT olX = olXfer(fi, H_dm, H_del, H_con);
786 return -(H_dm*H_del*g*H_con)/(realT(1) + g*olX);
790 template<
typename realT>
791 realT clGainOpt<realT>::clNTF2(
int fi,
796 if(_f[fi] <= 0)
return 0;
798 if(_f[fi] < 0)
return 0;
801 complexT H_dm, H_del, H_con;
803 complexT olX = olXfer(fi, H_dm, H_del, H_con);
805 complexT NTF = -(H_dm*H_del*g*H_con)/(realT(1) + g*olX);
810 template<
typename realT>
811 void clGainOpt<realT>::clTF2( realT & ETF,
828 complexT H_dm, H_del, H_con;
830 complexT olX = olXfer(fi, H_dm, H_del, H_con);
836 ETF = norm(realT(1)/( realT(1) + g*olX));
837 NTF = norm(-(H_dm*H_del*g*H_con) /( realT(1) + g*olX) );
845 template<
typename realT>
846 realT clGainOpt<realT>::clVariance( realT & varErr,
848 std::vector<realT> & PSDerr,
849 std::vector<realT> & PSDnoise,
853 if(_f.size() != PSDerr.size() || _f.size() != PSDnoise.size())
855 std::cerr <<
"clVariance: Frequency grid and PSDs must be same size." << std::endl;
866 for(
size_t i=0; i< PSDerr.size(); ++i)
875 clTF2(ETF, NTF, i, g);
877 varErr += ETF*PSDerr[i]*df;
878 varNoise += NTF*PSDnoise[i]*df;
881 return varErr + varNoise;
884 template<
typename realT>
885 realT clGainOpt<realT>::clVariance( std::vector<realT> & PSDerr,
886 std::vector<realT> & PSDnoise,
893 return clVariance(varErr, varNoise, PSDerr, PSDnoise, g );
897 template<
typename realT>
898 realT clGainOpt<realT>::maxStableGain( realT & ll, realT & ul)
900 static_cast<void>(ul);
902 std::vector<realT> re, im;
904 if(ll == 0) ll = _maxFindMin;
906 nyquist( re, im, 1.0);
908 int gi_c = re.size()-1;
910 for(
int gi=re.size()-2; gi >= 0; --gi)
912 if( -1.0/re[gi] < ll)
continue;
914 if( ( re[gi] < 0) && ( im[gi+1] >= 0 && im[gi] < 0) )
917 if( re[gi] <= re[gi_c] ) gi_c = gi;
921 return -1.0/ re[gi_c];
925 template<
typename realT>
926 realT maxStableGain(
const realT & ll,
const realT & ul)
931 maxStableGain(rll, rul);
934 template<
typename realT>
935 realT clGainOpt<realT>::maxStableGain()
938 realT ll = _maxFindMin;
940 return maxStableGain(ll, ul);
947 template<
typename realT>
948 realT optGainOpenLoop( clGainOptOptGain_OL<realT> & olgo,
952 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>(olgo, minFindMin, minFindMaxFact*gmax, minFindBits, minFindMaxIter);
969 std::cerr <<
"optGainOpenLoop: No root found\n";
970 gopt = minFindMaxFact*gmax;
976 static_assert(std::is_fundamental<realT>::value || !std::is_fundamental<realT>::value,
"impl::optGainOpenLoop<realT> is not specialized for type realT, and MX_INCLUDE_BOOST is not defined, so I can't just use boost.");
982 float optGainOpenLoop<float>( clGainOptOptGain_OL<float> & olgo,
986 float & minFindMaxFact,
988 uintmax_t minFindMaxIter
992 double optGainOpenLoop<double>( clGainOptOptGain_OL<double> & olgo,
996 double & minFindMaxFact,
998 uintmax_t minFindMaxIter
1002 long double optGainOpenLoop<long double>( clGainOptOptGain_OL<long double> & olgo,
1005 long double & minFindMin,
1006 long double & minFindMaxFact,
1008 uintmax_t minFindMaxIter
1013 __float128 optGainOpenLoop<__float128>( clGainOptOptGain_OL<__float128> & olgo,
1016 __float128 & minFindMin,
1017 __float128 & minFindMaxFact,
1019 uintmax_t minFindMaxIter
1025 template<
typename realT>
1026 realT clGainOpt<realT>::optGainOpenLoop( realT & var,
1027 std::vector<realT> & PSDerr,
1028 std::vector<realT> & PSDnoise)
1031 return optGainOpenLoop(var, PSDerr, PSDnoise, gmax);
1035 template<
typename realT>
1036 realT clGainOpt<realT>::optGainOpenLoop( realT & var,
1037 std::vector<realT> & PSDerr,
1038 std::vector<realT> & PSDnoise,
1041 clGainOptOptGain_OL<realT> olgo;
1043 olgo.PSDerr = &PSDerr;
1044 olgo.PSDnoise = &PSDnoise;
1046 if(gmax <= 0) gmax = maxStableGain();
1048 return impl::optGainOpenLoop( olgo, var, gmax, _minFindMin, _minFindMaxFact, _minFindBits, _minFindMaxIter);
1051 template<
typename realT>
1052 int clGainOpt<realT>::pseudoOpenLoop( std::vector<realT> & PSD, realT g)
1055 for(
int f=0; f< _f.size(); ++f)
1059 if(e > 0) PSD[f] = PSD[f]/ e;
1065 template<
typename realT>
1066 int clGainOpt<realT>::nyquist( std::vector<realT> & re,
1067 std::vector<realT> & im,
1071 re.resize(_f.size());
1072 im.resize(_f.size());
1076 for(
size_t f=0; f< _f.size(); ++f)
1089 template<
typename realT>
1090 struct clGainOptOptGain_OL
1092 clGainOpt<realT> * go;
1093 std::vector<realT> * PSDerr;
1094 std::vector<realT> * PSDnoise;
1096 realT operator()(
const realT & g)
1098 return go->clVariance(*PSDerr, *PSDnoise, g);
1105 class clGainOpt<float>;
1108 class clGainOpt<double>;
1111 class clGainOpt<long double>;
1115 class clGainOpt<__float128>;