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(
const 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>
721 size_t jmax = std::max( m_a.size() + 1, m_b.size() );
723 m_cs.resize( m_f.size(), jmax );
724 m_ss.resize( m_f.size(), jmax );
726 for(
size_t i = 0; i < m_f.size(); ++i )
731 for(
size_t j = 1; j < jmax; ++j )
744 m_H_dm.resize( m_f.size(), 0 );
745 m_H_wfs.resize( m_f.size(), 0 );
746 m_H_ma.resize( m_f.size(), 0 );
747 m_H_del.resize( m_f.size(), 0 );
748 m_H_con.resize( m_f.size(), 0 );
750 size_t jmax = std::min( m_a.size(), m_b.size() );
753 for(
size_t i = 0; i < m_f.size(); ++i )
774 m_H_dm[i] = std::complex<realT>( 1, 0 );
778 m_H_dm[i] = (
realT( 1 ) - expsT ) / ( s * m_Ti );
781 m_H_wfs[i] = m_H_dm[i];
785 m_H_del[i] = exp( -s * m_tau );
790 for(
size_t j = 1; j < jmax; ++j )
793 realT cs = m_cs( i, j );
794 realT ss = m_ss( i, j );
795 FIR += m_b[j] *
complexT( cs, -ss );
796 IIR += m_remember * m_a[j - 1] *
complexT( cs, -ss );
799 FIR += m_b[j] * expZ;
800 IIR += m_remember * m_a[j - 1] * expZ;
804 for(
size_t jj = jmax; jj < m_a.size() + 1; ++jj )
808 realT cs = m_cs( i, jj );
809 realT ss = m_ss( i, jj );
810 IIR += m_remember * m_a[jj - 1] *
complexT( cs, -ss );
813 IIR += m_remember * m_a[jj - 1] * expZ;
817 for(
size_t jj = jmax; jj < m_b.size(); ++jj )
820 realT cs = m_cs( i, jj );
821 realT ss = m_ss( i, jj );
822 FIR += m_b[jj] *
complexT( cs, -ss );
825 FIR += m_b[jj] * expZ;
829 m_H_con[i] = FIR / (
realT( 1.0 ) - IIR );
847 return ( m_H_dm[fi] * m_H_wfs[fi] * m_H_del[fi] * m_H_con[fi] );
850template <
typename realT>
861 return (
realT( 1 ) / (
realT( 1 ) + g * olXfer( fi ) ) );
864template <
typename realT>
875 return std::arg( (
realT( 1 ) / (
realT( 1 ) + g * olXfer( fi ) ) ) );
878template <
typename realT>
889 return norm(
realT( 1 ) / (
realT( 1 ) + g * olXfer( fi ) ) );
892template <
typename realT>
905 complexT olX = olXfer( fi, H_dm, H_del, H_con );
907 return -( H_dm * H_del * g * H_con ) / (
realT( 1 ) + g * olX );
910template <
typename realT>
923 complexT olX = olXfer( fi, H_dm, H_del, H_con );
925 complexT NTF = -( H_dm * H_del * g * H_con ) / (
realT( 1 ) + g * olX );
930template <
typename realT>
946 complexT olX = olXfer( fi, H_dm, H_del, H_con );
952 ETF = norm(
realT( 1 ) / (
realT( 1 ) + g * olX ) );
953 NTF = norm( -( H_dm * H_del * g * H_con ) / (
realT( 1 ) + g * olX ) );
961template <
typename realT>
963 realT &varErr,
realT &varNoise,
const std::vector<realT> &PSDerr,
const std::vector<realT> &PSDnoise,
realT g )
965 if( m_f.size() != PSDerr.size() || m_f.size() != PSDnoise.size() )
967 std::cerr <<
"clVariance: Frequency grid and PSDs must be same size." << std::endl;
976 df = m_f[1] - m_f[0];
978 for(
size_t i = 0; i < PSDerr.size(); ++i )
987 clTF2( ETF, NTF, i, g );
989 varErr += ETF * PSDerr[i] * df;
990 varNoise += NTF * PSDnoise[i] * df;
993 return varErr + varNoise;
996template <
typename realT>
1002 return clVariance( varErr, varNoise, PSDerr, PSDnoise, g );
1005template <
typename realT>
1008 static_cast<void>( ul );
1010 std::vector<realT> re, im;
1015 nyquist( re, im, 1.0 );
1017 int gi_c = re.size() - 1;
1019 for(
int gi = re.size() - 2; gi >= 0; --gi )
1021 if( -1.0 / re[gi] < ll )
1024 if( ( re[gi] < 0 ) && ( im[gi + 1] >= 0 && im[gi] < 0 ) )
1027 if( re[gi] <= re[gi_c] )
1032 return -1.0 / re[gi_c];
1035template <
typename realT>
1036realT maxStableGain(
const realT &ll,
const realT &ul )
1041 maxStableGain( rll, rul );
1044template <
typename realT>
1048 realT ll = m_maxFindMin;
1050 return maxStableGain( ll, ul );
1057template <
typename realT>
1061 const realT &minFindMin,
1062 const realT &minFindMaxFact,
1064 uintmax_t minFindMaxIter,
1067#ifdef MX_INCLUDE_BOOST
1072 std::pair<realT, realT> brack;
1073 brack = boost::math::tools::brentm_findm_minima<clGainOptOptGain_OL<realT>, realT>( olgo,
1075 minFindMaxFact *
gmax,
1084 std::cerr <<
"optGainOpenLoop: No root found\n";
1085 gopt = minFindMaxFact *
gmax;
1091 static_assert( std::is_fundamental<realT>::value || !std::is_fundamental<realT>::value,
1092 "impl::optGainOpenLoop<realT> is not specialized for type realT, and MX_INCLUDE_BOOST is not "
1093 "defined, so I can't just use boost." );
1099float optGainOpenLoop<float>( clGainOptOptGain_OL<float> &olgo,
1102 const float &minFindMin,
1103 const float &minFindMaxFact,
1105 uintmax_t minFindMaxIter,
1109double optGainOpenLoop<double>( clGainOptOptGain_OL<double> &olgo,
1112 const double &minFindMin,
1113 const double &minFindMaxFact,
1115 uintmax_t minFindMaxIter,
1119long double optGainOpenLoop<long double>( clGainOptOptGain_OL<long double> &olgo,
1121 const long double &
gmax,
1122 const long double &minFindMin,
1123 const long double &minFindMaxFact,
1125 uintmax_t minFindMaxIter,
1130_m_float128 optGainOpenLoop<_m_float128>( clGainOptOptGain_OL<_m_float128> &olgo,
1132 const _m_float128 &
gmax,
1133 const _m_float128 &minFindMin,
1134 const _m_float128 &minFindMaxFact,
1136 uintmax_t minFindMaxIter,
1142template <
typename realT>
1144 const std::vector<realT> &PSDerr,
1145 const std::vector<realT> &PSDnoise,
1149 return optGainOpenLoop( var, PSDerr, PSDnoise,
gmax, gridSearch );
1152template <
typename realT>
1154 realT &var,
const std::vector<realT> &PSDerr,
const std::vector<realT> &PSDnoise,
realT &
gmax,
bool gridSearch )
1158 olgo.PSDerr = &PSDerr;
1159 olgo.PSDnoise = &PSDnoise;
1163 gmax = maxStableGain();
1166 realT ming = m_minFindMin;
1171 realT gstpsz = 0.05;
1173 realT var0 = clVariance( PSDerr, PSDnoise, gg );
1176 while( gg > m_minFindMin )
1179 realT var1 = clVariance( PSDerr, PSDnoise, gg );
1188 ming = mingg - gstpsz;
1189 maxg = mingg + gstpsz;
1191 if( ming < m_minFindMin )
1192 ming = m_minFindMin;
1199 impl::optGainOpenLoop( olgo, var, maxg, ming, m_minFindMaxFact, m_minFindBits, m_minFindMaxIter, iters );
1201 if( iters >= m_minFindMaxIter )
1205 std::cerr <<
"\nclGainOpt<realT>::optGainOpenLoop: minFindMaxIter (" << m_minFindMaxIter <<
") reached\n";
1212template <
typename realT>
1216 for(
int f = 0; f < m_f.size(); ++f )
1221 PSD[f] = PSD[f] / e;
1227template <
typename realT>
1230 re.resize( m_f.size() );
1231 im.resize( m_f.size() );
1235 for(
size_t f = 0; f < m_f.size(); ++f )
1237 etf = g * olXfer( f );
1238 re[f] = real( etf );
1239 im[f] = imag( etf );
1248template <
typename realT>
1252 const std::vector<realT> *PSDerr;
1253 const std::vector<realT> *PSDnoise;
1255 realT operator()(
const realT &g )
1257 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 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.
void f(const std::vector< realT > &newF)
Set the vector of frequencies.
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.