% Created 2021-09-02 jeu. 10:03 % Intended LaTeX compiler: pdflatex \documentclass[a4paper, 10pt, DIV=12, parskip=full]{scrreprt} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage{graphicx} \usepackage{grffile} \usepackage{longtable} \usepackage{wrapfig} \usepackage{rotating} \usepackage[normalem]{ulem} \usepackage{amsmath} \usepackage{textcomp} \usepackage{amssymb} \usepackage{capt-of} \usepackage{hyperref} \usepackage[most]{tcolorbox} \usepackage{bm} \usepackage{booktabs} \usepackage{tabularx} \usepackage{array} \usepackage{siunitx} \input{preamble.tex} \addbibresource{ref.bib} \author{Dehaeze Thomas} \date{\today} \title{Designing Complementary filters for sensor fusion using \(\mathcal{H}_\infty\) synthesis - Matlab Computation} \begin{document} \maketitle \tableofcontents \clearpage The present document is a companion file for the journal paper \cite{dehaeze21_new_method_desig_compl_filter}. All the Matlab \cite{matlab20} scripts used in the paper are here shared and explained. This document is divided into the following sections also corresponding to the paper sections: \begin{itemize} \item Section \ref{sec:h_inf_synthesis_complementary_filters}: the shaping of complementary filters is written as an \(\mathcal{H}_\infty\) optimization problem using weighting functions. The weighting function design is discussed and the method is applied for the design of a set of simple complementary filters. \item Section \ref{sec:comp_filters_ligo}: the effectiveness of the proposed complementary filter synthesis strategy is demonstrated by designing complex complementary filters used in the first isolation stage at the LIGO \item Section \ref{sec:closed_loop_complementary_filters}: complementary filters are designed using the classical feedback loop \item Section \ref{sec:three_comp_filters}: the proposed design method is generalized for the design of a set of three complementary filters \item Section \ref{sec:matlab_scripts}: complete Matlab scripts and functions developed are listed \end{itemize} \chapter{H-Infinity synthesis of complementary filters} \label{sec:h_inf_synthesis_complementary_filters} \section{Synthesis Architecture} In order to generate two complementary filters with a wanted shape, the generalized plant of Figure \ref{fig:h_infinity_robust_fusion_plant} can be used. The included weights \(W_1(s)\) and \(W_2(s)\) are used to specify the upper bounds of the complementary filters being generated. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs-journal/h_infinity_robust_fusion_plant.png} \caption{\label{fig:h_infinity_robust_fusion_plant}Generalized plant used for the \(\mathcal{H}_\infty\) synthesis of a set of two complementary fiters} \end{figure} Applied the standard \(\mathcal{H}_\infty\) synthesis on this generalized plant will give a transfer function \(H_2(s)\) (see Figure \ref{fig:h_infinity_robust_fusion_fb}) such that the \(\mathcal{H}_\infty\) norm of the transfer function from \(w\) to \([z_1,\ z_2]\) is less than one \eqref{eq:h_inf_objective}. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs-journal/h_infinity_robust_fusion_fb.png} \caption{\label{fig:h_infinity_robust_fusion_fb}Generalized plant with the synthesized filter obtained after the \(\mathcal{H}_\infty\) synthesis} \end{figure} \begin{equation} \left\| \begin{array}{c} (1 - H_2(s)) W_1(s) \\ H_2(s) W_2(s) \end{array} \right\|_\infty < 1 \label{eq:h_inf_objective} \end{equation} Thus, if the synthesis is successful and the above condition is verified, we can define \(H_1(s)\) to be the complementary of \(H_2(s)\) \eqref{eq:H1_complementary_of_H2} and we have condition \eqref{eq:shaping_comp_filters} verified. \begin{equation} H_1(s) = 1 - H_2(s) \label{eq:H1_complementary_of_H2} \end{equation} \begin{equation} \left\| \begin{array}{c} H_1(s) W_1(s) \\ H_2(s) W_2(s) \end{array} \right\|_\infty < 1 \quad \Longrightarrow \quad \left\{ \begin{array}{c} |H_1(j\omega)| < \frac{1}{|W_1(j\omega)|}, \quad \forall \omega \\ |H_2(j\omega)| < \frac{1}{|W_2(j\omega)|}, \quad \forall \omega \end{array} \right. \label{eq:shaping_comp_filters} \end{equation} We then see that \(W_1(s)\) and \(W_2(s)\) can be used to set the wanted upper bounds of the magnitudes of both \(H_1(s)\) and \(H_2(s)\). The presented synthesis method therefore allows to shape two filters \(H_1(s)\) and \(H_2(s)\) \eqref{eq:shaping_comp_filters} while ensuring their complementary property \eqref{eq:H1_complementary_of_H2}. The complete Matlab script for this part is given in Section \ref{sec:1_synthesis_complementary_filters}. \section{Design of Weighting Function - Proposed formula} A formula is proposed to help the design of the weighting functions: \begin{equation} W(s) = \left( \frac{ \frac{1}{\omega_0} \sqrt{\frac{1 - \left(\frac{G_0}{G_c}\right)^{\frac{2}{n}}}{1 - \left(\frac{G_c}{G_\infty}\right)^{\frac{2}{n}}}} s + \left(\frac{G_0}{G_c}\right)^{\frac{1}{n}} }{ \left(\frac{1}{G_\infty}\right)^{\frac{1}{n}} \frac{1}{\omega_0} \sqrt{\frac{1 - \left(\frac{G_0}{G_c}\right)^{\frac{2}{n}}}{1 - \left(\frac{G_c}{G_\infty}\right)^{\frac{2}{n}}}} s + \left(\frac{1}{G_c}\right)^{\frac{1}{n}} }\right)^n \label{eq:weighting_function_formula} \end{equation} The parameters permits to specify: \begin{itemize} \item the low frequency gain: \(G_0 = lim_{\omega \to 0} |W(j\omega)|\) \item the high frequency gain: \(G_\infty = lim_{\omega \to \infty} |W(j\omega)|\) \item the absolute gain at \(\omega_0\): \(G_c = |W(j\omega_0)|\) \item the absolute slope between high and low frequency: \(n\) \end{itemize} The general shape of a weighting function generated using the formula is shown in figure \ref{fig:weight_formula}. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/weight_formula.png} \caption{\label{fig:weight_formula}Magnitude of the weighting function generated using formula \eqref{eq:weighting_function_formula}} \end{figure} \section{Weighting functions for the design of two complementary filters} \label{sec:weighting_functions_example} The weighting function formula \eqref{eq:weighting_function_formula} is used to generate the upper bounds of two complementary filters that we wish to design. The matlab function \texttt{generateWF} is described in Section \ref{sec:generateWF}. \begin{minted}[]{matlab} %% Design of the Weighting Functions W1 = generateWF('n', 3, 'w0', 2*pi*10, 'G0', 1000, 'Ginf', 1/10, 'Gc', 0.45); W2 = generateWF('n', 2, 'w0', 2*pi*10, 'G0', 1/10, 'Ginf', 1000, 'Gc', 0.45); \end{minted} The inverse magnitude of these two weighting functions are shown in Figure \ref{fig:weights_W1_W2}. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/weights_W1_W2.png} \caption{\label{fig:weights_W1_W2}Inverse magnitude of the design weighting functions} \end{figure} \section{Synthesis of the complementary filters} The generalized plant of Figure \ref{fig:h_infinity_robust_fusion_plant} is defined as follows: \begin{minted}[]{matlab} %% Generalized Plant P = [W1 -W1; 0 W2; 1 0]; \end{minted} And the \(\mathcal{H}_\infty\) synthesis is performed using the \texttt{hinfsyn} command. \begin{minted}[]{matlab} %% H-Infinity Synthesis [H2, ~, gamma, ~] = hinfsyn(P, 1, 1,'TOLGAM', 0.001, 'METHOD', 'ric', 'DISPLAY', 'on'); \end{minted} \begin{verbatim} [H2, ~, gamma, ~] = hinfsyn(P, 1, 1,'TOLGAM', 0.001, 'METHOD', 'ric', 'DISPLAY', 'on'); Test bounds: 0.3223 <= gamma <= 1000 gamma X>=0 Y>=0 rho(XY)<1 p/f 1.795e+01 1.4e-07 0.0e+00 1.481e-16 p 2.406e+00 1.4e-07 0.0e+00 3.604e-15 p 8.806e-01 -3.1e+02 # -1.4e-16 7.370e-19 f 1.456e+00 1.4e-07 0.0e+00 1.499e-18 p 1.132e+00 1.4e-07 0.0e+00 8.587e-15 p 9.985e-01 1.4e-07 0.0e+00 2.331e-13 p 9.377e-01 -7.7e+02 # -6.6e-17 3.744e-14 f 9.676e-01 -2.0e+03 # -5.7e-17 1.046e-13 f 9.829e-01 -6.6e+03 # -1.1e-16 2.949e-13 f 9.907e-01 1.4e-07 0.0e+00 2.374e-19 p 9.868e-01 -1.6e+04 # -6.4e-17 5.331e-14 f 9.887e-01 -5.1e+04 # -1.5e-17 2.703e-19 f 9.897e-01 1.4e-07 0.0e+00 1.583e-11 p Limiting gains... 9.897e-01 1.5e-07 0.0e+00 1.183e-12 p 9.897e-01 6.9e-07 0.0e+00 1.365e-12 p Best performance (actual): 0.9897 \end{verbatim} As shown above, the obtained \(\mathcal{H}_\infty\) norm of the transfer function from \(w\) to \([z_1,\ z_2]\) is found to be less than one meaning the synthesis is successful. We then define the filter \(H_1(s)\) to be the complementary of \(H_2(s)\) \eqref{eq:H1_complementary_of_H2}. \begin{minted}[]{matlab} %% Define H1 to be the complementary of H2 H1 = 1 - H2; \end{minted} The function \texttt{generateCF} can also be used to synthesize the complementary filters. This function is described in Section \ref{sec:generateCF}. \begin{minted}[]{matlab} [H1, H2] = generateCF(W1, W2); \end{minted} \section{Obtained Complementary Filters} The obtained complementary filters are shown below and are found to be of order 5. Their bode plots are shown in figure \ref{fig:hinf_filters_results} and compare with the defined upper bounds. \begin{verbatim} zpk(H1) ans = (s+1.289e05) (s+153.6) (s+3.842)^3 ------------------------------------------------------- (s+1.29e05) (s^2 + 102.1s + 2733) (s^2 + 69.45s + 3272) zpk(H2) ans = 125.61 (s+3358)^2 (s^2 + 46.61s + 813.8) ------------------------------------------------------- (s+1.29e05) (s^2 + 102.1s + 2733) (s^2 + 69.45s + 3272) \end{verbatim} \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/hinf_filters_results.png} \caption{\label{fig:hinf_filters_results}Obtained complementary filters using \(\mathcal{H}_\infty\) synthesis} \end{figure} \chapter{Design of complementary filters used in the Active Vibration Isolation System at the LIGO} \label{sec:comp_filters_ligo} In this section, the proposed method for the design of complementary filters is validated for the design of a set of two complex complementary filters used for the first isolation stage at the LIGO \cite{hua04_low_ligo}. The complete Matlab script for this part is given in Section \ref{sec:2_ligo_complementary_filters}. \section{Specifications} The specifications for the set of complementary filters (\(L_1,H_1\)) used at the LIGO are summarized below (for further details, refer to \cite{hua04_polyp_fir_compl_filter_contr_system}): \begin{itemize} \item From 0 to 0.008 Hz, the magnitude \(|L_1(j\omega)|\) should be less or equal to \(8 \times 10^{-4}\) \item Between 0.008 Hz to 0.04 Hz, the filter \(L_1(s)\) should attenuate the input signal proportional to frequency cubed \item Between 0.04 Hz to 0.1 Hz, the magnitude \(|L_1(j\omega)|\) should be less than \(3\) \item Above 0.1 Hz, the magnitude \(|H_1(j\omega)|\) should be less than \(0.045\) \end{itemize} The specifications are translated into upper bounds of the complementary filters and are shown in Figure \ref{fig:ligo_specifications}. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/ligo_specifications.png} \caption{\label{fig:ligo_specifications}Specification for the LIGO complementary filters} \end{figure} \section{FIR Filter} To replicated the complementary filters developed in \cite{hua04_low_ligo}, the CVX Matlab toolbox \cite{grant14_cvx} is used. The CVX toolbox is initialized and the \texttt{SeDuMi} solver \cite{sturm99_using_sedum} is used. \begin{minted}[]{matlab} %% Initialized CVX cvx_startup; cvx_solver sedumi; \end{minted} We define the frequency vectors on which we will constrain the norm of the FIR filter. \begin{minted}[]{matlab} %% Frequency vectors w1 = 0:4.06e-4:0.008; w2 = 0.008:4.06e-4:0.04; w3 = 0.04:8.12e-4:0.1; w4 = 0.1:8.12e-4:0.83; \end{minted} The order \(n\) of the FIR filter is defined. \begin{minted}[]{matlab} %% Filter order n = 512; \end{minted} \begin{minted}[]{matlab} %% Initialization of filter responses A1 = [ones(length(w1),1), cos(kron(w1'.*(2*pi),[1:n-1]))]; A2 = [ones(length(w2),1), cos(kron(w2'.*(2*pi),[1:n-1]))]; A3 = [ones(length(w3),1), cos(kron(w3'.*(2*pi),[1:n-1]))]; A4 = [ones(length(w4),1), cos(kron(w4'.*(2*pi),[1:n-1]))]; B1 = [zeros(length(w1),1), sin(kron(w1'.*(2*pi),[1:n-1]))]; B2 = [zeros(length(w2),1), sin(kron(w2'.*(2*pi),[1:n-1]))]; B3 = [zeros(length(w3),1), sin(kron(w3'.*(2*pi),[1:n-1]))]; B4 = [zeros(length(w4),1), sin(kron(w4'.*(2*pi),[1:n-1]))]; \end{minted} And the convex optimization is run. \begin{minted}[]{matlab} %% Convex optimization cvx_begin variable y(n+1,1) % t maximize(-y(1)) for i = 1:length(w1) norm([0 A1(i,:); 0 B1(i,:)]*y) <= 8e-3; end for i = 1:length(w2) norm([0 A2(i,:); 0 B2(i,:)]*y) <= 8e-3*(2*pi*w2(i)/(0.008*2*pi))^3; end for i = 1:length(w3) norm([0 A3(i,:); 0 B3(i,:)]*y) <= 3; end for i = 1:length(w4) norm([[1 0]'- [0 A4(i,:); 0 B4(i,:)]*y]) <= y(1); end cvx_end h = y(2:end); \end{minted} \begin{verbatim} cvx_begin variable y(n+1,1) % t maximize(-y(1)) for i = 1:length(w1) norm([0 A1(i,:); 0 B1(i,:)]*y) <= 8e-3; end for i = 1:length(w2) norm([0 A2(i,:); 0 B2(i,:)]*y) <= 8e-3*(2*pi*w2(i)/(0.008*2*pi))^3; end for i = 1:length(w3) norm([0 A3(i,:); 0 B3(i,:)]*y) <= 3; end for i = 1:length(w4) norm([[1 0]'- [0 A4(i,:); 0 B4(i,:)]*y]) <= y(1); end cvx_end Calling SeDuMi 1.34: 4291 variables, 1586 equality constraints For improved efficiency, SeDuMi is solving the dual problem. ------------------------------------------------------------ SeDuMi 1.34 (beta) by AdvOL, 2005-2008 and Jos F. Sturm, 1998-2003. Alg = 2: xz-corrector, Adaptive Step-Differentiation, theta = 0.250, beta = 0.500 eqs m = 1586, order n = 3220, dim = 4292, blocks = 1073 nnz(A) = 1100727 + 0, nnz(ADA) = 1364794, nnz(L) = 683190 it : b*y gap delta rate t/tP* t/tD* feas cg cg prec 0 : 4.11E+02 0.000 1 : -2.58E+00 1.25E+02 0.000 0.3049 0.9000 0.9000 4.87 1 1 3.0E+02 2 : -2.36E+00 3.90E+01 0.000 0.3118 0.9000 0.9000 1.83 1 1 6.6E+01 3 : -1.69E+00 1.31E+01 0.000 0.3354 0.9000 0.9000 1.76 1 1 1.5E+01 4 : -8.60E-01 7.10E+00 0.000 0.5424 0.9000 0.9000 2.48 1 1 4.8E+00 5 : -4.91E-01 5.44E+00 0.000 0.7661 0.9000 0.9000 3.12 1 1 2.5E+00 6 : -2.96E-01 3.88E+00 0.000 0.7140 0.9000 0.9000 2.62 1 1 1.4E+00 7 : -1.98E-01 2.82E+00 0.000 0.7271 0.9000 0.9000 2.14 1 1 8.5E-01 8 : -1.39E-01 2.00E+00 0.000 0.7092 0.9000 0.9000 1.78 1 1 5.4E-01 9 : -9.99E-02 1.30E+00 0.000 0.6494 0.9000 0.9000 1.51 1 1 3.3E-01 10 : -7.57E-02 8.03E-01 0.000 0.6175 0.9000 0.9000 1.31 1 1 2.0E-01 11 : -5.99E-02 4.22E-01 0.000 0.5257 0.9000 0.9000 1.17 1 1 1.0E-01 12 : -5.28E-02 2.45E-01 0.000 0.5808 0.9000 0.9000 1.08 1 1 5.9E-02 13 : -4.82E-02 1.28E-01 0.000 0.5218 0.9000 0.9000 1.05 1 1 3.1E-02 14 : -4.56E-02 5.65E-02 0.000 0.4417 0.9045 0.9000 1.02 1 1 1.4E-02 15 : -4.43E-02 2.41E-02 0.000 0.4265 0.9004 0.9000 1.01 1 1 6.0E-03 16 : -4.37E-02 8.90E-03 0.000 0.3690 0.9070 0.9000 1.00 1 1 2.3E-03 17 : -4.35E-02 3.24E-03 0.000 0.3641 0.9164 0.9000 1.00 1 1 9.5E-04 18 : -4.34E-02 1.55E-03 0.000 0.4788 0.9086 0.9000 1.00 1 1 4.7E-04 19 : -4.34E-02 8.77E-04 0.000 0.5653 0.9169 0.9000 1.00 1 1 2.8E-04 20 : -4.34E-02 5.05E-04 0.000 0.5754 0.9034 0.9000 1.00 1 1 1.6E-04 21 : -4.34E-02 2.94E-04 0.000 0.5829 0.9136 0.9000 1.00 1 1 9.9E-05 22 : -4.34E-02 1.63E-04 0.015 0.5548 0.9000 0.0000 1.00 1 1 6.6E-05 23 : -4.33E-02 9.42E-05 0.000 0.5774 0.9053 0.9000 1.00 1 1 3.9E-05 24 : -4.33E-02 6.27E-05 0.000 0.6658 0.9148 0.9000 1.00 1 1 2.6E-05 25 : -4.33E-02 3.75E-05 0.000 0.5972 0.9187 0.9000 1.00 1 1 1.6E-05 26 : -4.33E-02 1.89E-05 0.000 0.5041 0.9117 0.9000 1.00 1 1 8.6E-06 27 : -4.33E-02 9.72E-06 0.000 0.5149 0.9050 0.9000 1.00 1 1 4.5E-06 28 : -4.33E-02 2.94E-06 0.000 0.3021 0.9194 0.9000 1.00 1 1 1.5E-06 29 : -4.33E-02 9.73E-07 0.000 0.3312 0.9189 0.9000 1.00 2 2 5.3E-07 30 : -4.33E-02 2.82E-07 0.000 0.2895 0.9063 0.9000 1.00 2 2 1.6E-07 31 : -4.33E-02 8.05E-08 0.000 0.2859 0.9049 0.9000 1.00 2 2 4.7E-08 32 : -4.33E-02 1.43E-08 0.000 0.1772 0.9059 0.9000 1.00 2 2 8.8E-09 iter seconds digits c*x b*y 32 49.4 6.8 -4.3334083581e-02 -4.3334090214e-02 |Ax-b| = 3.7e-09, [Ay-c]_+ = 1.1E-10, |x|= 1.0e+00, |y|= 2.6e+00 Detailed timing (sec) Pre IPM Post 3.902E+00 4.576E+01 1.035E-02 Max-norms: ||b||=1, ||c|| = 3, Cholesky |add|=0, |skip| = 0, ||L.L|| = 4.26267. ------------------------------------------------------------ Status: Solved Optimal value (cvx_optval): -0.0433341 h = y(2:end); \end{verbatim} Finally, the filter response is computed over the frequency vector defined and the result is shown on figure \ref{fig:fir_filter_ligo} which is very close to the filters obtain in \cite{hua04_low_ligo}. \begin{minted}[]{matlab} %% Combine the frequency vectors to form the obtained filter w = [w1 w2 w3 w4]; H = [exp(-j*kron(w'.*2*pi,[0:n-1]))]*h; \end{minted} \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/fir_filter_ligo.png} \caption{\label{fig:fir_filter_ligo}FIR Complementary filters obtain after convex optimization} \end{figure} \section{Weighting function design} The weightings function that will be used for the \(\mathcal{H}_\infty\) synthesis of the complementary filters are now designed. These weights will determine the order of the obtained filters. Here are the requirements on the filters: \begin{itemize} \item reasonable order \item to be as close as possible to the specified upper bounds \item stable and minimum phase \end{itemize} The weighting function for the High Pass filter is defined as follows: \begin{minted}[]{matlab} %% Design of the weight for the high pass filter w1 = 2*pi*0.008; x1 = 0.35; w2 = 2*pi*0.04; x2 = 0.5; w3 = 2*pi*0.05; x3 = 0.5; % Slope of +3 from w1 wH = 0.008*(s^2/w1^2 + 2*x1/w1*s + 1)*(s/w1 + 1); % Little bump from w2 to w3 wH = wH*(s^2/w2^2 + 2*x2/w2*s + 1)/(s^2/w3^2 + 2*x3/w3*s + 1); % No Slope at high frequencies wH = wH/(s^2/w3^2 + 2*x3/w3*s + 1)/(s/w3 + 1); % Little bump between w2 and w3 w0 = 2*pi*0.045; xi = 0.1; A = 2; n = 1; wH = wH*((s^2 + 2*w0*xi*A^(1/n)*s + w0^2)/(s^2 + 2*w0*xi*s + w0^2))^n; wH = 1/wH; wH = minreal(ss(wH)); \end{minted} And the weighting function for the Low pass filter is taken as a Chebyshev Type I filter. \begin{minted}[]{matlab} %% Design of the weight for the low pass filter n = 20; % Filter order Rp = 1; % Peak to peak passband ripple Wp = 2*pi*0.102; % Edge frequency % Chebyshev Type I filter design [b,a] = cheby1(n, Rp, Wp, 'high', 's'); wL = 0.04*tf(a, b); wL = 1/wL; wL = minreal(ss(wL)); \end{minted} The inverse magnitude of the weighting functions are shown in Figure \ref{fig:ligo_weights}. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/ligo_weights.png} \caption{\label{fig:ligo_weights}Weights for the \(\mathcal{H}_\infty\) synthesis} \end{figure} \section{Synthesis of the complementary filters} The generalized plant of figure \ref{fig:h_infinity_robust_fusion_plant} is defined. \begin{minted}[]{matlab} %% Generalized plant for the H-infinity Synthesis P = [0 wL; wH -wH; 1 0]; \end{minted} And the standard \(\mathcal{H}_\infty\) synthesis using the \texttt{hinfsyn} command is performed. \begin{minted}[]{matlab} %% Standard H-Infinity synthesis [Hl, ~, gamma, ~] = hinfsyn(P, 1, 1,'TOLGAM', 0.001, 'METHOD', 'ric', 'DISPLAY', 'on'); \end{minted} \begin{verbatim} [Hl, ~, gamma, ~] = hinfsyn(P, 1, 1,'TOLGAM', 0.001, 'METHOD', 'ric', 'DISPLAY', 'on'); Resetting value of Gamma min based on D_11, D_12, D_21 terms Test bounds: 0.3276 < gamma <= 1.8063 gamma hamx_eig xinf_eig hamy_eig yinf_eig nrho_xy p/f 1.806 1.4e-02 -1.7e-16 3.6e-03 -4.8e-12 0.0000 p 1.067 1.3e-02 -4.2e-14 3.6e-03 -1.9e-12 0.0000 p 0.697 1.3e-02 -3.0e-01# 3.6e-03 -3.5e-11 0.0000 f 0.882 1.3e-02 -9.5e-01# 3.6e-03 -1.2e-34 0.0000 f 0.975 1.3e-02 -2.7e+00# 3.6e-03 -1.6e-12 0.0000 f 1.021 1.3e-02 -8.7e+00# 3.6e-03 -4.5e-16 0.0000 f 1.044 1.3e-02 -6.5e-14 3.6e-03 -3.0e-15 0.0000 p 1.032 1.3e-02 -1.8e+01# 3.6e-03 0.0e+00 0.0000 f 1.038 1.3e-02 -3.8e+01# 3.6e-03 0.0e+00 0.0000 f 1.041 1.3e-02 -8.3e+01# 3.6e-03 -2.9e-33 0.0000 f 1.042 1.3e-02 -1.9e+02# 3.6e-03 -3.4e-11 0.0000 f 1.043 1.3e-02 -5.3e+02# 3.6e-03 -7.5e-13 0.0000 f Gamma value achieved: 1.0439 \end{verbatim} The obtained \(\mathcal{H}_\infty\) norm is found to be close than one meaning the synthesis is successful. The high pass filter \(H_H(s)\) is defined to be the complementary of the synthesized low pass filter \(H_L(s)\): \begin{equation} H_H(s) = 1 - H_L(s) \end{equation} \begin{minted}[]{matlab} %% High pass filter as the complementary of the low pass filter Hh = 1 - Hl; \end{minted} The size of the filters is shown to be equal to the sum of the weighting functions orders. \begin{verbatim} size(Hh), size(Hl) State-space model with 1 outputs, 1 inputs, and 27 states. State-space model with 1 outputs, 1 inputs, and 27 states. \end{verbatim} The magnitude of the obtained filters as well as the requirements are shown in Figure \ref{fig:hinf_synthesis_ligo_results}. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/hinf_synthesis_ligo_results.png} \caption{\label{fig:hinf_synthesis_ligo_results}Obtained complementary filters using the \(\mathcal{H}_\infty\) synthesis} \end{figure} \section{Comparison of the FIR filters and synthesized filters} Let's now compare the FIR filters designed in \cite{hua04_low_ligo} with the with complementary filters obtained with the \(\mathcal{H}_\infty\) synthesis. This is done in Figure \ref{fig:comp_fir_ligo_hinf}, and both set of filters are found to be very close to each other. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/comp_fir_ligo_hinf.png} \caption{\label{fig:comp_fir_ligo_hinf}Comparison between the FIR filters developped for LIGO and the \(\mathcal{H}_\infty\) complementary filters} \end{figure} \chapter{``Closed-Loop'' complementary filters} \label{sec:closed_loop_complementary_filters} In this section, the classical feedback architecture shown in Figure \ref{fig:feedback_sensor_fusion} is used for the design of complementary filters. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs-journal/feedback_sensor_fusion.png} \caption{\label{fig:feedback_sensor_fusion}``Closed-Loop'' complementary filters} \end{figure} The complete Matlab script for this part is given in Section \ref{sec:3_closed_loop_complementary_filters}. \section{Weighting Function design} Weighting functions using the \texttt{generateWF} Matlab function are designed to specify the upper bounds of the complementary filters to be designed. These weighting functions are the same as the ones used in Section \ref{sec:weighting_functions_example}. \begin{minted}[]{matlab} %% Design of the Weighting Functions W1 = generateWF('n', 3, 'w0', 2*pi*10, 'G0', 1000, 'Ginf', 1/10, 'Gc', 0.45); W2 = generateWF('n', 2, 'w0', 2*pi*10, 'G0', 1/10, 'Ginf', 1000, 'Gc', 0.45); \end{minted} \section{Generalized plant} The generalized plant of Figure \ref{fig:feedback_synthesis_architecture_generalized_plant} is defined below: \begin{minted}[]{matlab} %% Generalized plant for "closed-loop" complementary filter synthesis P = [ W1 0 1; -W1 W2 -1]; \end{minted} \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs-journal/feedback_synthesis_architecture_generalized_plant.png} \caption{\label{fig:feedback_synthesis_architecture_generalized_plant}Generalized plant used for the \(\mathcal{H}_\infty\) synthesis of ``closed-loop'' complementary filters} \end{figure} \section{Synthesis of the closed-loop complementary filters} And the standard \(\mathcal{H}_\infty\) synthesis is performed. \begin{minted}[]{matlab} %% Standard H-Infinity Synthesis [L, ~, gamma, ~] = hinfsyn(P, 1, 1,'TOLGAM', 0.001, 'METHOD', 'ric', 'DISPLAY', 'on'); \end{minted} \begin{verbatim} Test bounds: 0.3191 <= gamma <= 1.669 gamma X>=0 Y>=0 rho(XY)<1 p/f 7.299e-01 -1.5e-19 -2.4e+01 # 1.555e-18 f 1.104e+00 0.0e+00 1.6e-07 2.037e-19 p 8.976e-01 -3.2e-16 -1.4e+02 # 5.561e-16 f 9.954e-01 0.0e+00 1.6e-07 1.041e-15 p 9.452e-01 -1.1e-15 -3.8e+02 # 4.267e-15 f 9.700e-01 -6.5e-16 -1.6e+03 # 9.876e-15 f 9.826e-01 0.0e+00 1.6e-07 8.775e-39 p 9.763e-01 -5.0e-16 -6.2e+03 # 3.519e-14 f 9.795e-01 0.0e+00 1.6e-07 6.971e-20 p 9.779e-01 -1.9e-31 -2.2e+04 # 5.600e-18 f 9.787e-01 0.0e+00 1.6e-07 5.546e-19 p Limiting gains... 9.789e-01 0.0e+00 1.6e-07 1.084e-13 p 9.789e-01 0.0e+00 9.7e-07 1.137e-13 p Best performance (actual): 0.9789 \end{verbatim} \section{Synthesized filters} The obtained filter \(L(s)\) can then be included in the feedback architecture shown in Figure \ref{fig:hinf_filters_results_mixed_sensitivity}. The closed-loop transfer functions from \(\hat{x}_1\) to \(\hat{x}\) and from \(\hat{x}_2\) to \(\hat{x}\) corresponding respectively to the sensitivity and complementary sensitivity transfer functions are defined below: \begin{minted}[]{matlab} %% Complementary filters H1 = inv(1 + L); H2 = 1 - H1; \end{minted} \begin{verbatim} zpk(H1) = (s+3.842)^3 (s+153.6) (s+1.289e05) ------------------------------------------------------- (s+1.29e05) (s^2 + 102.1s + 2733) (s^2 + 69.45s + 3272) zpk(H2) = 125.61 (s+3358)^2 (s^2 + 46.61s + 813.8) ------------------------------------------------------- (s+1.29e05) (s^2 + 102.1s + 2733) (s^2 + 69.45s + 3272) \end{verbatim} The bode plots of the synthesized complementary filters are compared with the upper bounds in Figure \ref{fig:hinf_filters_results_mixed_sensitivity}. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/hinf_filters_results_mixed_sensitivity.png} \caption{\label{fig:hinf_filters_results_mixed_sensitivity}Bode plot of the obtained complementary filters} \end{figure} \chapter{Synthesis of three complementary filters} \label{sec:three_comp_filters} In this section, the proposed synthesis method of complementary filters is generalized for the synthesis of a set of three complementary filters. The complete Matlab script for this part is given in Section \ref{sec:4_three_complementary_filters}. \section{Synthesis Architecture} The synthesis objective is to shape three filters that are complementary. This corresponds to the conditions \eqref{eq:obj_three_cf} where \(W_1(s)\), \(W_2(s)\) and \(W_3(s)\) are weighting functions used to specify the maximum wanted magnitude of the three complementary filters. \begin{equation} \begin{aligned} & |H_1(j\omega)| < \frac{1}{|W_1(j\omega)|}, \quad \forall\omega \\ & |H_2(j\omega)| < \frac{1}{|W_2(j\omega)|}, \quad \forall\omega \\ & |H_3(j\omega)| < \frac{1}{|W_3(j\omega)|}, \quad \forall\omega \\ & H_1(s) + H_2(s) + H_3(s) = 1 \end{aligned} \label{eq:obj_three_cf} \end{equation} This synthesis can be done by performing the standard \(\mathcal{H}_\infty\) synthesis with on the generalized plant in Figure \ref{fig:comp_filter_three_hinf}. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs-journal/comp_filter_three_hinf_fb.png} \caption{\label{fig:comp_filter_three_hinf}Generalized architecture for generating 3 complementary filters} \end{figure} After synthesis, filter \(H_2(s)\) and \(H_3(s)\) are obtained as shown in Figure \ref{fig:comp_filter_three_hinf}. The last filter \(H_1(s)\) is defined as the complementary of the two others as in \eqref{eq:H1_complementary_of_H2_H3}. \begin{equation} H_1(s) = 1 - H_2(s) - H_3(s) \label{eq:H1_complementary_of_H2_H3} \end{equation} \section{Weights} The three weighting functions are defined as shown below. \begin{minted}[]{matlab} %% Design of the Weighting Functions W1 = generateWF('n', 2, 'w0', 2*pi*1, 'G0', 1/10, 'Ginf', 1000, 'Gc', 0.5); W2 = 0.22*(1 + s/2/pi/1)^2/(sqrt(1e-4) + s/2/pi/1)^2*(1 + s/2/pi/10)^2/(1 + s/2/pi/1000)^2; W3 = generateWF('n', 3, 'w0', 2*pi*10, 'G0', 1000, 'Ginf', 1/10, 'Gc', 0.5); \end{minted} Their inverse magnitudes are displayed in Figure \ref{fig:three_weighting_functions}. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/three_weighting_functions.png} \caption{\label{fig:three_weighting_functions}Three weighting functions used for the \(\mathcal{H}_\infty\) synthesis of the complementary filters} \end{figure} \section{H-Infinity Synthesis} The generalized plant in Figure \ref{fig:comp_filter_three_hinf} containing the weighting functions is defined below. \begin{minted}[]{matlab} %% Generalized plant for the synthesis of 3 complementary filters P = [W1 -W1 -W1; 0 W2 0 ; 0 0 W3; 1 0 0]; \end{minted} And the standard \(\mathcal{H}_\infty\) synthesis using the \texttt{hinfsyn} command is performed. \begin{minted}[]{matlab} %% Standard H-Infinity Synthesis [H, ~, gamma, ~] = hinfsyn(P, 1, 2,'TOLGAM', 0.001, 'METHOD', 'ric', 'DISPLAY', 'on'); \end{minted} \begin{verbatim} Resetting value of Gamma min based on D_11, D_12, D_21 terms Test bounds: 0.1000 < gamma <= 1050.0000 gamma hamx_eig xinf_eig hamy_eig yinf_eig nrho_xy p/f 1.050e+03 3.2e+00 4.5e-13 6.3e-02 -1.2e-11 0.0000 p 525.050 3.2e+00 1.3e-13 6.3e-02 0.0e+00 0.0000 p 262.575 3.2e+00 2.1e-12 6.3e-02 -1.5e-13 0.0000 p 131.337 3.2e+00 1.1e-12 6.3e-02 -7.2e-29 0.0000 p 65.719 3.2e+00 2.0e-12 6.3e-02 0.0e+00 0.0000 p 32.909 3.2e+00 7.4e-13 6.3e-02 -5.9e-13 0.0000 p 16.505 3.2e+00 1.4e-12 6.3e-02 0.0e+00 0.0000 p 8.302 3.2e+00 1.6e-12 6.3e-02 0.0e+00 0.0000 p 4.201 3.2e+00 1.6e-12 6.3e-02 0.0e+00 0.0000 p 2.151 3.2e+00 1.6e-12 6.3e-02 0.0e+00 0.0000 p 1.125 3.2e+00 2.8e-12 6.3e-02 0.0e+00 0.0000 p 0.613 3.0e+00 -2.5e+03# 6.3e-02 0.0e+00 0.0000 f 0.869 3.1e+00 -2.9e+01# 6.3e-02 0.0e+00 0.0000 f 0.997 3.2e+00 1.9e-12 6.3e-02 0.0e+00 0.0000 p 0.933 3.1e+00 -6.9e+02# 6.3e-02 0.0e+00 0.0000 f 0.965 3.1e+00 -3.0e+03# 6.3e-02 0.0e+00 0.0000 f 0.981 3.1e+00 -8.6e+03# 6.3e-02 0.0e+00 0.0000 f 0.989 3.2e+00 -2.7e+04# 6.3e-02 0.0e+00 0.0000 f 0.993 3.2e+00 -5.7e+05# 6.3e-02 0.0e+00 0.0000 f 0.995 3.2e+00 2.2e-12 6.3e-02 0.0e+00 0.0000 p 0.994 3.2e+00 1.6e-12 6.3e-02 0.0e+00 0.0000 p 0.994 3.2e+00 1.0e-12 6.3e-02 0.0e+00 0.0000 p Gamma value achieved: 0.9936 \end{verbatim} The two synthesized filters \(H_2(s)\) and \(H_3(s)\) are defined below: And the third filter \(H_1(s)\) is defined using \eqref{eq:H1_complementary_of_H2_H3}. \begin{minted}[]{matlab} %% H1 is defined as the complementary filter of H2 and H3 H1 = 1 - H2 - H3; \end{minted} The bode plots of the three obtained complementary filters are shown in Figure \ref{fig:three_complementary_filters_results}. \begin{figure}[htbp] \centering \includegraphics[scale=1]{figs/three_complementary_filters_results.png} \caption{\label{fig:three_complementary_filters_results}The three complementary filters obtained after \(\mathcal{H}_\infty\) synthesis} \end{figure} \chapter{Matlab Scripts} \label{sec:matlab_scripts} \section{\texttt{1\_synthesis\_complementary\_filters.m}} \label{sec:1_synthesis_complementary_filters} This scripts corresponds to section 3 of \cite{dehaeze21_new_method_desig_compl_filter}. \begin{minted}[linenos,firstnumber=1]{matlab} %% Clear Workspace and Close figures clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); %% Initialize Frequency Vector freqs = logspace(-1, 3, 1000); %% Weighting Function Design % Parameters n = 3; w0 = 2*pi*10; G0 = 1e-3; G1 = 1e1; Gc = 2; % Formulas W = (((1/w0)*sqrt((1-(G0/Gc)^(2/n))/(1-(Gc/G1)^(2/n)))*s + (G0/Gc)^(1/n))/((1/G1)^(1/n)*(1/w0)*sqrt((1-(G0/Gc)^(2/n))/(1-(Gc/G1)^(2/n)))*s + (1/Gc)^(1/n)))^n; %% Magnitude of the weighting function with parameters figure; hold on; plot(freqs, abs(squeeze(freqresp(W, freqs, 'Hz'))), 'k-'); plot([1e-3 1e0], [G0 G0], 'k--', 'LineWidth', 1) text(1e0, G0, '$\quad G_0$') plot([1e1 1e3], [G1 G1], 'k--', 'LineWidth', 1) text(1e1,G1,'$G_{\infty}\quad$','HorizontalAlignment', 'right') plot([w0/2/pi w0/2/pi], [1 2*Gc], 'k--', 'LineWidth', 1) text(w0/2/pi,1,'$\omega_c$','VerticalAlignment', 'top', 'HorizontalAlignment', 'center') plot([w0/2/pi/2 2*w0/2/pi], [Gc Gc], 'k--', 'LineWidth', 1) text(w0/2/pi/2, Gc, '$G_c \quad$','HorizontalAlignment', 'right') text(w0/5/pi/2, abs(evalfr(W, j*w0/5)), 'Slope: $n \quad$', 'HorizontalAlignment', 'right') text(w0/2/pi, abs(evalfr(W, j*w0)), '$\bullet$', 'HorizontalAlignment', 'center') set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); ylabel('Magnitude'); hold off; xlim([freqs(1), freqs(end)]); ylim([5e-4, 20]); yticks([1e-4, 1e-3, 1e-2, 1e-1, 1, 1e1]); %% Design of the Weighting Functions W1 = generateWF('n', 3, 'w0', 2*pi*10, 'G0', 1000, 'Ginf', 1/10, 'Gc', 0.45); W2 = generateWF('n', 2, 'w0', 2*pi*10, 'G0', 1/10, 'Ginf', 1000, 'Gc', 0.45); %% Plot of the Weighting function magnitude figure; tiledlayout(1, 1, 'TileSpacing', 'None', 'Padding', 'None'); ax1 = nexttile(); hold on; set(gca,'ColorOrderIndex',1) plot(freqs, 1./abs(squeeze(freqresp(W1, freqs, 'Hz'))), '--', 'DisplayName', '$|W_1|^{-1}$'); set(gca,'ColorOrderIndex',2) plot(freqs, 1./abs(squeeze(freqresp(W2, freqs, 'Hz'))), '--', 'DisplayName', '$|W_2|^{-1}$'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]', 'FontSize', 10); ylabel('Magnitude', 'FontSize', 10); hold off; xlim([freqs(1), freqs(end)]); xticks([0.1, 1, 10, 100, 1000]); ylim([8e-4, 20]); yticks([1e-3, 1e-2, 1e-1, 1, 1e1]); yticklabels({'', '$10^{-2}$', '', '$10^0$', ''}); ax1.FontSize = 9; leg = legend('location', 'south', 'FontSize', 8); leg.ItemTokenSize(1) = 18; %% Generalized Plant P = [W1 -W1; 0 W2; 1 0]; %% H-Infinity Synthesis [H2, ~, gamma, ~] = hinfsyn(P, 1, 1,'TOLGAM', 0.001, 'METHOD', 'ric', 'DISPLAY', 'on'); %% Define H1 to be the complementary of H2 H1 = 1 - H2; %% Bode plot of the complementary filters figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); % Magnitude ax1 = nexttile([2, 1]); hold on; set(gca,'ColorOrderIndex',1) plot(freqs, 1./abs(squeeze(freqresp(W1, freqs, 'Hz'))), '--', 'DisplayName', '$|W_1|^{-1}$'); set(gca,'ColorOrderIndex',2) plot(freqs, 1./abs(squeeze(freqresp(W2, freqs, 'Hz'))), '--', 'DisplayName', '$|W_2|^{-1}$'); set(gca,'ColorOrderIndex',1) plot(freqs, abs(squeeze(freqresp(H1, freqs, 'Hz'))), '-', 'DisplayName', '$H_1$'); set(gca,'ColorOrderIndex',2) plot(freqs, abs(squeeze(freqresp(H2, freqs, 'Hz'))), '-', 'DisplayName', '$H_2$'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); set(gca, 'XTickLabel',[]); ylabel('Magnitude'); ylim([8e-4, 20]); yticks([1e-3, 1e-2, 1e-1, 1, 1e1]); yticklabels({'', '$10^{-2}$', '', '$10^0$', ''}) leg = legend('location', 'south', 'FontSize', 8, 'NumColumns', 2); leg.ItemTokenSize(1) = 18; % Phase ax2 = nexttile; hold on; set(gca,'ColorOrderIndex',1) plot(freqs, 180/pi*phase(squeeze(freqresp(H1, freqs, 'Hz'))), '-'); set(gca,'ColorOrderIndex',2) plot(freqs, 180/pi*phase(squeeze(freqresp(H2, freqs, 'Hz'))), '-'); hold off; set(gca, 'XScale', 'log'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); yticks([-180:90:180]); ylim([-180, 200]) yticklabels({'-180', '', '0', '', '180'}) linkaxes([ax1,ax2],'x'); xlim([freqs(1), freqs(end)]); \end{minted} \section{\texttt{2\_ligo\_complementary\_filters.m}} \label{sec:2_ligo_complementary_filters} This scripts corresponds to section 4 of \cite{dehaeze21_new_method_desig_compl_filter}. \begin{minted}[linenos,firstnumber=1]{matlab} %% Clear Workspace and Close figures clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); %% Initialize Frequency Vector freqs = logspace(-3, 0, 1000); %% Upper bounds for the complementary filters figure; hold on; set(gca,'ColorOrderIndex',1) plot([0.0001, 0.008], [8e-3, 8e-3], ':', 'DisplayName', 'Spec. on $H_H$'); set(gca,'ColorOrderIndex',1) plot([0.008 0.04], [8e-3, 1], ':', 'HandleVisibility', 'off'); set(gca,'ColorOrderIndex',1) plot([0.04 0.1], [3, 3], ':', 'HandleVisibility', 'off'); set(gca,'ColorOrderIndex',2) plot([0.1, 10], [0.045, 0.045], ':', 'DisplayName', 'Spec. on $H_L$'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); ylabel('Magnitude'); hold off; xlim([freqs(1), freqs(end)]); ylim([1e-4, 10]); leg = legend('location', 'southeast', 'FontSize', 8); leg.ItemTokenSize(1) = 18; %% Initialized CVX cvx_startup; cvx_solver sedumi; %% Frequency vectors w1 = 0:4.06e-4:0.008; w2 = 0.008:4.06e-4:0.04; w3 = 0.04:8.12e-4:0.1; w4 = 0.1:8.12e-4:0.83; %% Filter order n = 512; %% Initialization of filter responses A1 = [ones(length(w1),1), cos(kron(w1'.*(2*pi),[1:n-1]))]; A2 = [ones(length(w2),1), cos(kron(w2'.*(2*pi),[1:n-1]))]; A3 = [ones(length(w3),1), cos(kron(w3'.*(2*pi),[1:n-1]))]; A4 = [ones(length(w4),1), cos(kron(w4'.*(2*pi),[1:n-1]))]; B1 = [zeros(length(w1),1), sin(kron(w1'.*(2*pi),[1:n-1]))]; B2 = [zeros(length(w2),1), sin(kron(w2'.*(2*pi),[1:n-1]))]; B3 = [zeros(length(w3),1), sin(kron(w3'.*(2*pi),[1:n-1]))]; B4 = [zeros(length(w4),1), sin(kron(w4'.*(2*pi),[1:n-1]))]; %% Convex optimization cvx_begin variable y(n+1,1) % t maximize(-y(1)) for i = 1:length(w1) norm([0 A1(i,:); 0 B1(i,:)]*y) <= 8e-3; end for i = 1:length(w2) norm([0 A2(i,:); 0 B2(i,:)]*y) <= 8e-3*(2*pi*w2(i)/(0.008*2*pi))^3; end for i = 1:length(w3) norm([0 A3(i,:); 0 B3(i,:)]*y) <= 3; end for i = 1:length(w4) norm([[1 0]'- [0 A4(i,:); 0 B4(i,:)]*y]) <= y(1); end cvx_end h = y(2:end); %% Combine the frequency vectors to form the obtained filter w = [w1 w2 w3 w4]; H = [exp(-j*kron(w'.*2*pi,[0:n-1]))]*h; %% Bode plot of the obtained complementary filters figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); % Magnitude ax1 = nexttile([2, 1]); hold on; set(gca,'ColorOrderIndex',1) plot(w, abs(1-H), '-', 'DisplayName', '$L_1$'); plot([0.1, 10], [0.045, 0.045], 'k:', 'DisplayName', 'Spec. on $L_1$'); set(gca,'ColorOrderIndex',2) plot(w, abs(H), '-', 'DisplayName', '$H_1$'); plot([0.0001, 0.008], [8e-3, 8e-3], 'k--', 'DisplayName', 'Spec. on $H_1$'); plot([0.008 0.04], [8e-3, 1], 'k--', 'HandleVisibility', 'off'); plot([0.04 0.1], [3, 3], 'k--', 'HandleVisibility', 'off'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); set(gca, 'XTickLabel',[]); ylabel('Magnitude'); hold off; ylim([5e-3, 10]); leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2); leg.ItemTokenSize(1) = 16; % Phase ax2 = nexttile; hold on; plot(w, 180/pi*unwrap(angle(1-H)), '-'); plot(w, 180/pi*unwrap(angle(H)), '-'); hold off; xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); set(gca, 'XScale', 'log'); yticks([-360:180:180]); ylim([-380, 200]); linkaxes([ax1,ax2],'x'); xlim([1e-3, 1]); %% Design of the weight for the high pass filter w1 = 2*pi*0.008; x1 = 0.35; w2 = 2*pi*0.04; x2 = 0.5; w3 = 2*pi*0.05; x3 = 0.5; % Slope of +3 from w1 wH = 0.008*(s^2/w1^2 + 2*x1/w1*s + 1)*(s/w1 + 1); % Little bump from w2 to w3 wH = wH*(s^2/w2^2 + 2*x2/w2*s + 1)/(s^2/w3^2 + 2*x3/w3*s + 1); % No Slope at high frequencies wH = wH/(s^2/w3^2 + 2*x3/w3*s + 1)/(s/w3 + 1); % Little bump between w2 and w3 w0 = 2*pi*0.045; xi = 0.1; A = 2; n = 1; wH = wH*((s^2 + 2*w0*xi*A^(1/n)*s + w0^2)/(s^2 + 2*w0*xi*s + w0^2))^n; wH = 1/wH; wH = minreal(ss(wH)); %% Design of the weight for the low pass filter n = 20; % Filter order Rp = 1; % Peak to peak passband ripple Wp = 2*pi*0.102; % Edge frequency % Chebyshev Type I filter design [b,a] = cheby1(n, Rp, Wp, 'high', 's'); wL = 0.04*tf(a, b); wL = 1/wL; wL = minreal(ss(wL)); %% Magnitude of the designed Weights and initial specifications figure; hold on; set(gca,'ColorOrderIndex',1); plot(freqs, abs(squeeze(freqresp(inv(wL), freqs, 'Hz'))), '-', 'DisplayName', '$|W_L|^{-1}$'); plot([0.1, 10], [0.045, 0.045], 'k:', 'DisplayName', 'Spec. on $L_1$'); set(gca,'ColorOrderIndex',2); plot(freqs, abs(squeeze(freqresp(inv(wH), freqs, 'Hz'))), '-', 'DisplayName', '$|W_H|^{-1}$'); plot([0.0001, 0.008], [8e-3, 8e-3], 'k--', 'DisplayName', 'Spec. on $H_1$'); plot([0.008 0.04], [8e-3, 1], 'k--', 'HandleVisibility', 'off'); plot([0.04 0.1], [3, 3], 'k--', 'HandleVisibility', 'off'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); ylabel('Magnitude'); hold off; xlim([freqs(1), freqs(end)]); ylim([5e-3, 10]); leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2); leg.ItemTokenSize(1) = 16; %% Generalized plant for the H-infinity Synthesis P = [0 wL; wH -wH; 1 0]; %% Standard H-Infinity synthesis [Hl, ~, gamma, ~] = hinfsyn(P, 1, 1,'TOLGAM', 0.001, 'METHOD', 'ric', 'DISPLAY', 'on'); %% High pass filter as the complementary of the low pass filter Hh = 1 - Hl; %% Minimum realization of the filters Hh = minreal(Hh); Hl = minreal(Hl); %% Bode plot of the obtained filters and comparison with the upper bounds figure; hold on; set(gca,'ColorOrderIndex',1); plot(freqs, abs(squeeze(freqresp(Hl, freqs, 'Hz'))), '-', 'DisplayName', '$L_1^\prime$'); plot([0.1, 10], [0.045, 0.045], 'k:', 'DisplayName', 'Spec. on $L_1$'); set(gca,'ColorOrderIndex',2); plot(freqs, abs(squeeze(freqresp(Hh, freqs, 'Hz'))), '-', 'DisplayName', '$H_1^\prime$'); plot([0.0001, 0.008], [8e-3, 8e-3], 'k--', 'DisplayName', 'Spec. on $H_1$'); plot([0.008 0.04], [8e-3, 1], 'k--', 'HandleVisibility', 'off'); plot([0.04 0.1], [3, 3], 'k--', 'HandleVisibility', 'off'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); ylabel('Magnitude'); hold off; xlim([freqs(1), freqs(end)]); ylim([5e-3, 10]); leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2); leg.ItemTokenSize(1) = 16; %% Comparison of the complementary filters obtained with H-infinity and with CVX figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); % Magnitude ax1 = nexttile([2, 1]); hold on; set(gca,'ColorOrderIndex',1); plot(freqs, abs(squeeze(freqresp(Hl, freqs, 'Hz'))), '-', ... 'DisplayName', '$L_1(s)$ - $\mathcal{H}_\infty$'); set(gca,'ColorOrderIndex',2); plot(freqs, abs(squeeze(freqresp(Hh, freqs, 'Hz'))), '-', ... 'DisplayName', '$H_1(s)$ - $\mathcal{H}_\infty$'); set(gca,'ColorOrderIndex',1); plot(w, abs(1-H), '--', ... 'DisplayName', '$L_1(s)$ - FIR'); set(gca,'ColorOrderIndex',2); plot(w, abs(H), '--', ... 'DisplayName', '$H_1(s)$ - FIR'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Magnitude'); set(gca, 'XTickLabel',[]); ylim([5e-3, 10]); leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2); leg.ItemTokenSize(1) = 16; % Phase ax2 = nexttile; hold on; set(gca,'ColorOrderIndex',1); plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Hl, freqs, 'Hz')))), '-'); set(gca,'ColorOrderIndex',2); plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Hh, freqs, 'Hz')))), '-'); set(gca,'ColorOrderIndex',1); plot(w, 180/pi*unwrap(angle(1-H)), '--'); set(gca,'ColorOrderIndex',2); plot(w, 180/pi*unwrap(angle(H)), '--'); set(gca, 'XScale', 'log'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks([-360:180:180]); ylim([-380, 200]); linkaxes([ax1,ax2],'x'); xlim([freqs(1), freqs(end)]); \end{minted} \section{\texttt{3\_closed\_loop\_complementary\_filters.m}} \label{sec:3_closed_loop_complementary_filters} This scripts corresponds to section 5.1 of \cite{dehaeze21_new_method_desig_compl_filter}. \begin{minted}[linenos,firstnumber=1]{matlab} %% Clear Workspace and Close figures clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); %% Initialize Frequency Vector freqs = logspace(-1, 3, 1000); %% Design of the Weighting Functions W1 = generateWF('n', 3, 'w0', 2*pi*10, 'G0', 1000, 'Ginf', 1/10, 'Gc', 0.45); W2 = generateWF('n', 2, 'w0', 2*pi*10, 'G0', 1/10, 'Ginf', 1000, 'Gc', 0.45); %% Generalized plant for "closed-loop" complementary filter synthesis P = [ W1 0 1; -W1 W2 -1]; %% Standard H-Infinity Synthesis [L, ~, gamma, ~] = hinfsyn(P, 1, 1,'TOLGAM', 0.001, 'METHOD', 'ric', 'DISPLAY', 'on'); %% Complementary filters H1 = inv(1 + L); H2 = 1 - H1; %% Bode plot of the obtained Complementary filters with upper-bounds freqs = logspace(-1, 3, 1000); figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); % Magnitude ax1 = nexttile([2, 1]); hold on; set(gca,'ColorOrderIndex',1) plot(freqs, 1./abs(squeeze(freqresp(W1, freqs, 'Hz'))), '--', 'DisplayName', '$|W_1|^{-1}$'); set(gca,'ColorOrderIndex',2) plot(freqs, 1./abs(squeeze(freqresp(W2, freqs, 'Hz'))), '--', 'DisplayName', '$|W_2|^{-1}$'); set(gca,'ColorOrderIndex',1) plot(freqs, abs(squeeze(freqresp(H1, freqs, 'Hz'))), '-', 'DisplayName', '$H_1$'); set(gca,'ColorOrderIndex',2) plot(freqs, abs(squeeze(freqresp(H2, freqs, 'Hz'))), '-', 'DisplayName', '$H_2$'); plot(freqs, abs(squeeze(freqresp(L, freqs, 'Hz'))), 'k--', 'DisplayName', '$|L|$'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); set(gca, 'XTickLabel',[]); ylabel('Magnitude'); ylim([1e-3, 1e3]); yticks([1e-3, 1e-2, 1e-1, 1, 1e1, 1e2, 1e3]); yticklabels({'', '$10^{-2}$', '', '$10^0$', '', '$10^2$', ''}); leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 3); leg.ItemTokenSize(1) = 18; % Phase ax2 = nexttile; hold on; set(gca,'ColorOrderIndex',1) plot(freqs, 180/pi*phase(squeeze(freqresp(H1, freqs, 'Hz'))), '-'); set(gca,'ColorOrderIndex',2) plot(freqs, 180/pi*phase(squeeze(freqresp(H2, freqs, 'Hz'))), '-'); hold off; set(gca, 'XScale', 'log'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); yticks([-180:90:180]); ylim([-180, 200]) yticklabels({'-180', '', '0', '', '180'}) linkaxes([ax1,ax2],'x'); xlim([freqs(1), freqs(end)]); \end{minted} \section{\texttt{4\_three\_complementary\_filters.m}} \label{sec:4_three_complementary_filters} This scripts corresponds to section 5.2 of \cite{dehaeze21_new_method_desig_compl_filter}. \begin{minted}[linenos,firstnumber=1]{matlab} %% Clear Workspace and Close figures clear; close all; clc; %% Intialize Laplace variable s = zpk('s'); freqs = logspace(-2, 3, 1000); %% Design of the Weighting Functions W1 = generateWF('n', 2, 'w0', 2*pi*1, 'G0', 1/10, 'Ginf', 1000, 'Gc', 0.5); W2 = 0.22*(1 + s/2/pi/1)^2/(sqrt(1e-4) + s/2/pi/1)^2*(1 + s/2/pi/10)^2/(1 + s/2/pi/1000)^2; W3 = generateWF('n', 3, 'w0', 2*pi*10, 'G0', 1000, 'Ginf', 1/10, 'Gc', 0.5); %% Inverse magnitude of the weighting functions figure; hold on; set(gca,'ColorOrderIndex',1) plot(freqs, 1./abs(squeeze(freqresp(W1, freqs, 'Hz'))), '--', 'DisplayName', '$|W_1|^{-1}$'); set(gca,'ColorOrderIndex',2) plot(freqs, 1./abs(squeeze(freqresp(W2, freqs, 'Hz'))), '--', 'DisplayName', '$|W_2|^{-1}$'); set(gca,'ColorOrderIndex',3) plot(freqs, 1./abs(squeeze(freqresp(W3, freqs, 'Hz'))), '--', 'DisplayName', '$|W_3|^{-1}$'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); ylabel('Magnitude'); hold off; xlim([freqs(1), freqs(end)]); ylim([2e-4, 1.3e1]) leg = legend('location', 'northeast', 'FontSize', 8); leg.ItemTokenSize(1) = 18; %% Generalized plant for the synthesis of 3 complementary filters P = [W1 -W1 -W1; 0 W2 0 ; 0 0 W3; 1 0 0]; %% Standard H-Infinity Synthesis [H, ~, gamma, ~] = hinfsyn(P, 1, 2,'TOLGAM', 0.001, 'METHOD', 'ric', 'DISPLAY', 'on'); %% Synthesized H2 and H3 filters H2 = tf(H(1)); H3 = tf(H(2)); %% H1 is defined as the complementary filter of H2 and H3 H1 = 1 - H2 - H3; %% Bode plot of the obtained complementary filters figure; tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None'); % Magnitude ax1 = nexttile([2, 1]); hold on; set(gca,'ColorOrderIndex',1) plot(freqs, 1./abs(squeeze(freqresp(W1, freqs, 'Hz'))), '--', 'DisplayName', '$|W_1|^{-1}$'); set(gca,'ColorOrderIndex',2) plot(freqs, 1./abs(squeeze(freqresp(W2, freqs, 'Hz'))), '--', 'DisplayName', '$|W_2|^{-1}$'); set(gca,'ColorOrderIndex',3) plot(freqs, 1./abs(squeeze(freqresp(W3, freqs, 'Hz'))), '--', 'DisplayName', '$|W_3|^{-1}$'); set(gca,'ColorOrderIndex',1) plot(freqs, abs(squeeze(freqresp(H1, freqs, 'Hz'))), '-', 'DisplayName', '$H_1$'); set(gca,'ColorOrderIndex',2) plot(freqs, abs(squeeze(freqresp(H2, freqs, 'Hz'))), '-', 'DisplayName', '$H_2$'); set(gca,'ColorOrderIndex',3) plot(freqs, abs(squeeze(freqresp(H3, freqs, 'Hz'))), '-', 'DisplayName', '$H_3$'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Magnitude'); set(gca, 'XTickLabel',[]); ylim([1e-4, 20]); leg = legend('location', 'northeast', 'FontSize', 8); leg.ItemTokenSize(1) = 18; % Phase ax2 = nexttile; hold on; set(gca,'ColorOrderIndex',1) plot(freqs, 180/pi*phase(squeeze(freqresp(H1, freqs, 'Hz')))); set(gca,'ColorOrderIndex',2) plot(freqs, 180/pi*phase(squeeze(freqresp(H2, freqs, 'Hz')))); set(gca,'ColorOrderIndex',3) plot(freqs, 180/pi*phase(squeeze(freqresp(H3, freqs, 'Hz')))); hold off; xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); set(gca, 'XScale', 'log'); yticks([-180:90:180]); ylim([-220, 220]); linkaxes([ax1,ax2],'x'); xlim([freqs(1), freqs(end)]); \end{minted} \section{\texttt{generateWF}: Generate Weighting Functions} \label{sec:generateWF} This function is used to easily generate weighting functions from classical requirements. \begin{minted}[]{matlab} function [W] = generateWF(args) % createWeight - % % Syntax: [W] = generateWeight(args) % % Inputs: % - n - Weight Order (integer) % - G0 - Low frequency Gain % - G1 - High frequency Gain % - Gc - Gain of the weight at frequency w0 % - w0 - Frequency at which |W(j w0)| = Gc [rad/s] % % Outputs: % - W - Generated Weighting Function %% Argument validation arguments args.n (1,1) double {mustBeInteger, mustBePositive} = 1 args.G0 (1,1) double {mustBeNumeric, mustBePositive} = 0.1 args.Ginf (1,1) double {mustBeNumeric, mustBePositive} = 10 args.Gc (1,1) double {mustBeNumeric, mustBePositive} = 1 args.w0 (1,1) double {mustBeNumeric, mustBePositive} = 1 end % Verification of correct relation between G0, Gc and Ginf mustBeBetween(args.G0, args.Gc, args.Ginf); %% Initialize the Laplace variable s = zpk('s'); %% Create the weighting function according to formula W = (((1/args.w0)*sqrt((1-(args.G0/args.Gc)^(2/args.n))/(1-(args.Gc/args.Ginf)^(2/args.n)))*s + ... (args.G0/args.Gc)^(1/args.n))/... ((1/args.Ginf)^(1/args.n)*(1/args.w0)*sqrt((1-(args.G0/args.Gc)^(2/args.n))/(1-(args.Gc/args.Ginf)^(2/args.n)))*s + ... (1/args.Gc)^(1/args.n)))^args.n; %% Custom validation function function mustBeBetween(a,b,c) if ~((a > b && b > c) || (c > b && b > a)) eid = 'createWeight:inputError'; msg = 'Gc should be between G0 and Ginf.'; throwAsCaller(MException(eid,msg)) end \end{minted} \section{\texttt{generateCF}: Generate Complementary Filters} \label{sec:generateCF} This function is used to easily synthesize a set of two complementary filters using the \(\mathcal{H}_\infty\) synthesis. \begin{minted}[]{matlab} function [H1, H2] = generateCF(W1, W2, args) % createWeight - % % Syntax: [H1, H2] = generateCF(W1, W2, args) % % Inputs: % - W1 - Weighting Function for H1 % - W2 - Weighting Function for H2 % - args: % - method - H-Infinity solver ('lmi' or 'ric') % - display - Display synthesis results ('on' or 'off') % % Outputs: % - H1 - Generated H1 Filter % - H2 - Generated H2 Filter %% Argument validation arguments W1 W2 args.method char {mustBeMember(args.method,{'lmi', 'ric'})} = 'ric' args.display char {mustBeMember(args.display,{'on', 'off'})} = 'on' end %% The generalized plant is defined P = [W1 -W1; 0 W2; 1 0]; %% The standard H-infinity synthesis is performed [H2, ~, gamma, ~] = hinfsyn(P, 1, 1,'TOLGAM', 0.001, 'METHOD', args.method, 'DISPLAY', args.display); %% H1 is defined as the complementary of H2 H1 = 1 - H2; \end{minted} \printbibliography \end{document}