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>
74 std::vector<realT>
m_b;
75 std::vector<realT>
m_a;
77 std::vector<realT>
m_f;
83 Eigen::Array<
realT, -1, -1> m_cs;
84 Eigen::Array<
realT, -1, -1> m_ss;
86 std::vector<std::complex<realT>> m_H_dm;
87 std::vector<std::complex<realT>> m_H_wfs;
88 std::vector<std::complex<realT>> m_H_ma;
89 std::vector<std::complex<realT>> m_H_del;
90 std::vector<std::complex<realT>> m_H_con;
146 void Ti( realT newTi );
162 void b(
const std::vector<realT> &newB );
167 void b(
const Eigen::Array<realT, -1, -1>
183 const std::vector<realT> &
b()
188 void bScale( realT scale );
193 void a(
const std::vector<realT> &newA );
198 void a(
const Eigen::Array<realT, -1, -1> &newA
212 const std::vector<realT> &
a()
217 void aScale( realT scale );
242 void f( std::vector<realT> &newF );
345 const std::vector<realT> &PSDerr,
346 const std::vector<realT> &PSDnoise,
358 const std::vector<realT> &PSDnoise,
408 const std::vector<realT> &PSDerr,
409 const std::vector<realT> &PSDnoise,
419 const std::vector<realT> &PSDerr,
420 const std::vector<realT> &PSDnoise,
436 int nyquist( std::vector<realT> &re, std::vector<realT> &im, realT g );
439template <
typename realT>
445template <
typename realT>
454template <
typename realT>
459 setLeakyIntegrator( 1.0 );
467 m_minFindMaxFact = 0.999;
468 m_minFindBits = std::numeric_limits<realT>::digits;
469 m_minFindMaxIter = 10000;
475template <
typename realT>
481template <
typename realT>
493template <
typename realT>
499template <
typename realT>
511template <
typename realT>
517template <
typename realT>
520 if( m_tau == newTau )
529template <
typename realT>
532 if( newB.size() > (
size_t)m_cs.cols() )
541template <
typename realT>
544 if( newB.cols() > m_cs.cols() )
549 m_b.resize( newB.cols() );
551 for(
size_t i = 0; i < m_b.size(); ++i )
553 m_b[i] = newB( 0, i );
559template <
typename realT>
562 for(
size_t n = 0; n < m_b.size(); ++n )
570template <
typename realT>
573 if( newA.size() + 1 > (
size_t)m_cs.cols() )
582template <
typename realT>
585 if( newA.cols() + 1 > m_cs.cols() )
590 m_a.resize( newA.cols() );
592 for(
size_t i = 0; i < m_a.size(); ++i )
594 m_a[i] = newA( 0, i );
600template <
typename realT>
603 for(
size_t n = 0; n < m_a.size(); ++n )
611template <
typename realT>
614 if(m_remember != rem)
624template <
typename realT>
630template <
typename realT>
633 if(m_b.size() != 1 || m_a.size() != 1 || m_b[0] != 1.0 || m_a[0] != 1.0 || m_remember != remember)
651 m_remember = remember;
657template <
typename realT>
661 for(
int i = 0; i < nF; ++i )
670template <
typename realT>
679template <
typename realT>
686template <
typename realT>
693 return olXfer( fi, H_dm, H_del, H_con );
700template <
typename realT>
720 size_t jmax = std::max( m_a.size() + 1, m_b.size() );
722 m_cs.resize( m_f.size(), jmax );
723 m_ss.resize( m_f.size(), jmax );
725 for(
size_t i = 0; i < m_f.size(); ++i )
730 for(
size_t j = 1; j < jmax; ++j )
743 m_H_dm.resize( m_f.size(), 0 );
744 m_H_wfs.resize( m_f.size(), 0 );
745 m_H_ma.resize( m_f.size(), 0 );
746 m_H_del.resize( m_f.size(), 0 );
747 m_H_con.resize( m_f.size(), 0 );
749 size_t jmax = std::min( m_a.size(), m_b.size() );
752 for(
size_t i = 0; i < m_f.size(); ++i )
768 m_H_dm[i] = std::complex<realT>( 1, 0 );
772 m_H_dm[i] = (
realT( 1 ) - expsT ) / ( s * m_Ti );
775 m_H_wfs[i] = m_H_dm[i];
779 m_H_del[i] = exp( -s * m_tau );
784 for(
size_t j = 1; j < jmax; ++j )
787 realT cs = m_cs( i, j );
788 realT ss = m_ss( i, j );
789 FIR += m_b[j] *
complexT( cs, -ss );
790 IIR += m_remember * m_a[j - 1] *
complexT( cs, -ss );
793 FIR += m_b[j] * expZ;
794 IIR += m_remember * m_a[j - 1] * expZ;
798 for(
size_t jj = jmax; jj < m_a.size() + 1; ++jj )
801 realT cs = m_cs( i, jj );
802 realT ss = m_ss( i, jj );
803 IIR += m_remember * m_a[jj - 1] *
complexT( cs, -ss );
806 IIR += m_remember * m_a[jj - 1] * expZ;
810 for(
size_t jj = jmax; jj < m_b.size(); ++jj )
813 realT cs = m_cs( i, jj );
814 realT ss = m_ss( i, jj );
815 FIR += m_b[jj] *
complexT( cs, -ss );
818 FIR += m_b[jj] * expZ;
822 m_H_con[i] = FIR / (
realT( 1.0 ) - IIR );
840 return ( m_H_dm[fi] * m_H_wfs[fi] * m_H_del[fi] * m_H_con[fi] );
843template <
typename realT>
854 return (
realT( 1 ) / (
realT( 1 ) + g * olXfer( fi ) ) );
857template <
typename realT>
868 return std::arg( (
realT( 1 ) / (
realT( 1 ) + g * olXfer( fi ) ) ) );
871template <
typename realT>
882 return norm(
realT( 1 ) / (
realT( 1 ) + g * olXfer( fi ) ) );
885template <
typename realT>
898 complexT olX = olXfer( fi, H_dm, H_del, H_con );
900 return -( H_dm * H_del * g * H_con ) / (
realT( 1 ) + g * olX );
903template <
typename realT>
916 complexT olX = olXfer( fi, H_dm, H_del, H_con );
918 complexT NTF = -( H_dm * H_del * g * H_con ) / (
realT( 1 ) + g * olX );
923template <
typename realT>
939 complexT olX = olXfer( fi, H_dm, H_del, H_con );
945 ETF = norm(
realT( 1 ) / (
realT( 1 ) + g * olX ) );
946 NTF = norm( -( H_dm * H_del * g * H_con ) / (
realT( 1 ) + g * olX ) );
954template <
typename realT>
956 realT &varErr,
realT &varNoise,
const std::vector<realT> &PSDerr,
const std::vector<realT> &PSDnoise,
realT g )
958 if( m_f.size() != PSDerr.size() || m_f.size() != PSDnoise.size() )
960 std::cerr <<
"clVariance: Frequency grid and PSDs must be same size." << std::endl;
969 df = m_f[1] - m_f[0];
971 for(
size_t i = 0; i < PSDerr.size(); ++i )
980 clTF2( ETF, NTF, i, g );
982 varErr += ETF * PSDerr[i] * df;
983 varNoise += NTF * PSDnoise[i] * df;
986 return varErr + varNoise;
989template <
typename realT>
995 return clVariance( varErr, varNoise, PSDerr, PSDnoise, g );
998template <
typename realT>
1001 static_cast<void>( ul );
1003 std::vector<realT> re, im;
1008 nyquist( re, im, 1.0 );
1010 int gi_c = re.size() - 1;
1012 for(
int gi = re.size() - 2; gi >= 0; --gi )
1014 if( -1.0 / re[gi] < ll )
1017 if( ( re[gi] < 0 ) && ( im[gi + 1] >= 0 && im[gi] < 0 ) )
1020 if( re[gi] <= re[gi_c] )
1025 return -1.0 / re[gi_c];
1028template <
typename realT>
1029realT maxStableGain(
const realT &ll,
const realT &ul )
1034 maxStableGain( rll, rul );
1037template <
typename realT>
1041 realT ll = m_maxFindMin;
1043 return maxStableGain( ll, ul );
1050template <
typename realT>
1054 const realT &minFindMin,
1055 const realT &minFindMaxFact,
1057 uintmax_t minFindMaxIter,
1060#ifdef MX_INCLUDE_BOOST
1065 std::pair<realT, realT> brack;
1066 brack = boost::math::tools::brentm_findm_minima<clGainOptOptGain_OL<realT>, realT>( olgo,
1068 minFindMaxFact *
gmax,
1077 std::cerr <<
"optGainOpenLoop: No root found\n";
1078 gopt = minFindMaxFact *
gmax;
1084 staticm_assert( std::is_fundamental<realT>::value || !std::is_fundamental<realT>::value,
1085 "impl::optGainOpenLoop<realT> is not specialized for type realT, and MX_INCLUDE_BOOST is not "
1086 "defined, so I can't just use boost." );
1092float optGainOpenLoop<float>( clGainOptOptGain_OL<float> &olgo,
1095 const float &minFindMin,
1096 const float &minFindMaxFact,
1098 uintmax_t minFindMaxIter,
1102double optGainOpenLoop<double>( clGainOptOptGain_OL<double> &olgo,
1105 const double &minFindMin,
1106 const double &minFindMaxFact,
1108 uintmax_t minFindMaxIter,
1112long double optGainOpenLoop<long double>( clGainOptOptGain_OL<long double> &olgo,
1114 const long double &
gmax,
1115 const long double &minFindMin,
1116 const long double &minFindMaxFact,
1118 uintmax_t minFindMaxIter,
1123_m_float128 optGainOpenLoop<_m_float128>( clGainOptOptGain_OL<_m_float128> &olgo,
1125 const _m_float128 &
gmax,
1126 const _m_float128 &minFindMin,
1127 const _m_float128 &minFindMaxFact,
1129 uintmax_t minFindMaxIter,
1135template <
typename realT>
1137 const std::vector<realT> &PSDerr,
1138 const std::vector<realT> &PSDnoise,
1142 return optGainOpenLoop( var, PSDerr, PSDnoise,
gmax, gridSearch );
1145template <
typename realT>
1147 realT &var,
const std::vector<realT> &PSDerr,
const std::vector<realT> &PSDnoise,
realT &
gmax,
bool gridSearch )
1151 olgo.PSDerr = &PSDerr;
1152 olgo.PSDnoise = &PSDnoise;
1155 gmax = maxStableGain();
1157 realT ming = m_minFindMin;
1162 realT gstpsz = 0.05;
1164 realT var0 = clVariance( PSDerr, PSDnoise, gg );
1167 while( gg > m_minFindMin )
1170 realT var1 = clVariance( PSDerr, PSDnoise, gg );
1179 ming = mingg - gstpsz;
1180 maxg = mingg + gstpsz;
1182 if( ming < m_minFindMin )
1183 ming = m_minFindMin;
1190 impl::optGainOpenLoop( olgo, var, maxg, ming, m_minFindMaxFact, m_minFindBits, m_minFindMaxIter, iters );
1192 if( iters >= m_minFindMaxIter )
1196 std::cerr <<
"\nclGainOpt<realT>::optGainOpenLoop: minFindMaxIter (" << m_minFindMaxIter <<
") reached\n";
1203template <
typename realT>
1207 for(
int f = 0; f < m_f.size(); ++f )
1212 PSD[f] = PSD[f] / e;
1218template <
typename realT>
1221 re.resize( m_f.size() );
1222 im.resize( m_f.size() );
1226 for(
size_t f = 0; f < m_f.size(); ++f )
1228 etf = g * olXfer( f );
1229 re[f] = real( etf );
1230 im[f] = imag( etf );
1239template <
typename realT>
1243 const std::vector<realT> *PSDerr;
1244 const std::vector<realT> *PSDnoise;
1246 realT operator()(
const realT &g )
1248 return go->
clVariance( *PSDerr, *PSDnoise, g );
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
#define gmax(A, B)
max(A,B) - larger (most +ve) of two numbers (generic) (defined in the SOFA library sofam....
Bisection worker struct for finding optimum closed loop gain from open loop PSDs.
A class to manage optimizing closed-loop gains.
complexT olXfer(int fi)
Calculate the open-loop transfer function.
realT clVariance(const std::vector< realT > &PSDerr, const std::vector< realT > &PSDnoise, realT g)
Calculate the closed loop variance given open-loop PSDs and gain.
void f(std::vector< realT > &newF)
Set the vector of frequencies.
void Ti(realT newTi)
Set the loop sampling interval.
realT f(size_t i)
Get the i-th value of frequency.
void init()
Initialize this instance.
realT maxStableGain()
Find the maximum stable gain for the loop parameters.
void a(const std::vector< realT > &newA)
Set the vector of IIR coefficients.
clGainOpt(realT Ti, realT tau)
C'tor setting the loop timings.
void N(int newN)
Set the number of integrations in the moving average.
void b(const Eigen::Array< realT, -1, -1 > &newB)
Set the vector of FIR coefficients.
realT a(size_t i)
Get a single IIR coefficient.
int pseudoOpenLoop(std::vector< realT > &PSD, realT g)
Calculate the pseudo open-loop PSD given a closed loop PSD.
realT b(size_t i)
Get a single FIR coefficient.
complexT clNTF(int fi, realT g)
Return the closed loop noise transfer function (NTF) at frequency f for gain g.
void tau(realT newTau)
Set the loop delay.
std::vector< realT > m_f
Vector of frequencies.
void b(const std::vector< realT > &newB)
Set the vector of FIR coefficients.
realT optGainOpenLoop(realT &var, const std::vector< realT > &PSDerr, const std::vector< realT > &PSDnoise, bool gridSearch)
Return the optimum closed loop gain given an open loop PSD.
realT optGainOpenLoop(realT &var, const std::vector< realT > &PSDerr, const std::vector< realT > &PSDnoise, realT &gmax, bool gridSearch)
Return the optimum closed loop gain given an open loop PSD.
realT clNTF2(int fi, realT g)
Return the norm of the closed loop noise transfer function (NTF) at frequency f for gain g.
std::vector< realT > m_b
Vector of FIR coefficients.
realT Ti()
Get the loop sampling interval.
realT maxStableGain(realT &ll, realT &ul)
Find the maximum stable gain for the loop parameters.
realT m_tau
The loop delay.
void a(const Eigen::Array< realT, -1, -1 > &newA)
Set the vector of IIR coefficients.
int N()
Get the number of integrations in the (optional) moving average.
realT remember()
Get the remember factor.
const std::vector< realT > & b()
Get the vector of FIR coefficients.
realT clVariance(realT &varErr, realT &varNoise, const std::vector< realT > &PSDerr, const std::vector< realT > &PSDnoise, realT g)
Calculate the closed loop variance given open-loop PSDs and gain.
bool m_changed
True if any of the members which make up the basic transfer functions are changed.
realT m_minFindMaxFact
The maximum value, as a multiplicative factor of maximum gain.
size_t f_size()
Get the size of the frequency vector.
realT m_maxFindMin
The Minimum value for the maximum stable gain finding algorithm.
void remember(const realT &rem)
Set the remember factor for a leaky integrator.
complexT clETF(int fi, realT g)
Return the closed loop error transfer function (ETF) at frequency f for gain g.
clGainOpt()
Default c'tor.
complexT olXfer(int fi, complexT &H_dm, complexT &H_del, complexT &H_con)
Calculate the open-loop transfer function.
_realT realT
The real data type.
realT tau()
Get the loop delay.
void f(realT *newF, size_t nF)
Set the vector of frequencies.
std::complex< _realT > complexT
The complex data type.
uintmax_t m_minFindMaxIter
The maximum iterations allowed for minimization.
realT clETFPhase(int fi, realT g)
Return the closed loop error transfer function (ETF) phase at frequency f for gain g.
int m_N
Number of integrations in the (optional) moving average. Default is 1.
realT m_Ti
The loop sampling interval.
const std::vector< realT > & a()
Get the vector of IIR coefficients.
realT maxStableGain(const realT &ll, const realT &ul)
Find the maximum stable gain for the loop parameters.
void setLeakyIntegrator(realT remember)
Set the FIR and IIR coefficients so that the control law is a leaky integrator.
realT m_remember
The leaky integrator forget factor.
bool m_fChanged
True if frequency or max size of m_a and m_b changes.
realT m_minFindMin
The Minimum value for the minimum finding algorithm.
realT clETF2(int fi, realT g)
Return the norm of the closed loop error transfer function (ETF) at frequency f for gain g.
void clTF2(realT &ETF, realT &NTF, int fi, realT g)
Return the norm of the closed loop transfer functions at frequency f for gain g.
std::vector< realT > m_a
Vector of IIR coefficients.