Contents

% 16.323 Project
% Frequency domain shaped LQR control of a Fabry-Perot interferometer bound
% between 2 double pendulum suspended mirrors.
%
% Brett Shapiro
% 4 May 2010

% clear
clc,close all

Initializations

Simulation Paramters

dt = 2^(-14); % simulink simulation sampling of 16384 Hz (actual sampling used by LIGO)
t_end = 128;  % simulink simulation time in seconds (long enough to capture sufficient oscillations of support table motion)

% Double pendulum plant state space model
A = [   0       0       1       0
        0       0       0       1
     -73.83   16.04  -0.001     0
      16.36  -16.36     0    -0.001  ];
B = [   0        0        0
        0        0        0
      57.8  0.02476       0
        0        0    0.02525 ];   Bu = B(:,[2 3]);
C = [ 1   0   0   0
      0   1   0   0 ];
D = zeros(2,3);
P = ss(A,B,C,D);
np = size(A,1); % dimension of plant state

% Passive mirror state space: uncontrolled but with damping. Damping simply
% modeled with added viscosity. Input is ground motion, output is mirror
% motion
P2 = ss(A+[zeros(2,4);zeros(2) -3*eye(2)],B(:,1),C(2,:),0);

% Actuator saturation limits
top_sat    = 1.0e-3; % Newtons
bottom_sat = 0.1e-3; % Newtons

%
Cavity_rms_limit = 1e-12;

% Noise/Disturbance filtering curves
seis_shape = zpk(-2*pi*1*ones(1,4),-2*pi*0.2*ones(1,6),(2e-7)*((2*pi)^2)*(0.2)^6); % ground motion shape, target experimental goal
upcon_shape = zpk(0,-2*pi*5*[1 1],(1e-7)*(2*pi*5)^2); % best 'guess' of what the actuator Barkhausen noise looks like.

LQR Control

Frequency dependent cost functions

    % cost function for state two (mirror position)
    zx2 = -2*pi*1; px2 = -2*pi*[0;40]; kx2 = 1e1;
    [numx2 denx2] = zp2tf(zx2,px2,kx2); bx2_0 = numx2(1);
    numx2=numx2(2:end);denx2=denx2(2:end);
    nx2 = length(px2); % dimension of the state 2 weighting filter
    Afwx2 = [-denx2' [eye(nx2-1);zeros(1,nx2-1)]];
    Bfwx2 = [zeros(nx2,np/2-1) (numx2-denx2*bx2_0)' zeros(nx2,np/2)];
    Cfwx2 = [1 zeros(1,nx2-1)];
    Dfwx2 = [zeros(1,np/2-1) bx2_0 zeros(1,np/2)];
    Wx2 = ss(Afwx2,Bfwx2,Cfwx2,Dfwx2);

% Global control weighting parameters
r = 1e-15;  % broadband control effort weight (weights importance of state error verse control effort; relative control effort weighting done with cost filters)
crf = 5;    % crossover of control filter costs in Hz. Also approximate crossover of input loop gains.
crg = 1.35; % crossover gap between control effort cost filters.
% Top mass control cost function
    Rs1 = 80; % dB gain change of elliptical filter
    [zu1,pu1,ku1] = ellip(6,1,Rs1,2*pi*crf*crg,'high','s'); zu1 = [0;0;zu1]; pu1 = [pu1;-2*pi*0.1*[1;1;1]]; ku1 = 2000*sqrt(r)*ku1;
    [numu1 denu1] = zp2tf(zu1,pu1,ku1); bu1_0 = numu1(1);
    numu1=numu1(2:end);denu1=denu1(2:end);
    nu1 = length(pu1); % dimension of the top mass weighting filter
    Afwu1 = [-denu1' [eye(nu1-1);zeros(1,nu1-1)]];
    Bfwu1 = (numu1-denu1*bu1_0)';
    Cfwu1 = [1 zeros(1,nu1-1);zeros(1,nu1)];
    Dfwu1 = [bu1_0;sqrt(r)];
    Wu1 = ss(Afwu1,Bfwu1,Cfwu1,Dfwu1);
% Bottom mass control cost function
    Rs2 = 60; % dB gain change of elliptical filter
    [zu2,pu2,ku2] = ellip(6,1,Rs2,2*pi*crf/crg,'low','s'); zu2 = [zu2]; pu2 = [pu2;-2*pi*0.1*[0.1;0.1;1;1]]; ku2 = 2000*sqrt(r)*ku2; %#ok<NBRAK>
    [numu2 denu2] = zp2tf(zu2,pu2,ku2); bu2_0 = numu2(1);
    numu2=numu2(2:end);denu2=denu2(2:end);
    nu2 = length(pu2); % dimension of the bottom mass weighting filter
    Afwu2 = [-denu2' [eye(nu2-1);zeros(1,nu2-1)]];
    Bfwu2 = (numu2-denu2*bu2_0)';
    Cfwu2 = [1 zeros(1,nu2-1);zeros(1,nu2)];
    Dfwu2 = [bu2_0;sqrt(r)];
    Wu2 = ss(Afwu2,Bfwu2,Cfwu2,Dfwu2);

% Superplant with plant and weighting functions
Ass = [      A        zeros(np,nx2)    zeros(np,nu1)    zeros(np,nu2)
           Bfwx2           Afwx2       zeros(nx2,nu1)   zeros(nx2,nu2)
       zeros(nu1,np)  zeros(nu1,nx2)       Afwu1        zeros(nu1,nu2)
       zeros(nu2,np)  zeros(nu2,nx2)   zeros(nu2,nu1)       Afwu2     ];
Bss = [         Bu
            zeros(nx2,np/2)
         Bfwu1    zeros(nu1,np/2-1)
       zeros(nu2,np/2-1)   Bfwu2   ];
Css = [zeros(1,np/2-1) 1 zeros(1,np/2+nx2+nu1+nu2)];Dss = zeros(1,np/2);
Pss = ss(Ass,Bss,Css,Dss);

% LQR Weights
    Jss = [Dfwx2'*Dfwx2 Dfwx2'*Cfwx2                   zeros(np,nu1+nu2+np/2)              ;
           Cfwx2'*Dfwx2 Cfwx2'*Cfwx2                  zeros(nx2,nu1+nu2+np/2)              ;
               zeros(nu1,np+nx2)     Cfwu1'*Cfwu1 zeros(nu1,nu2) Cfwu1'*Dfwu1 zeros(nu1,1) ;
             zeros(nu2,np+nx2+nu1)                Cfwu2'*Cfwu2   zeros(nu2,1) Cfwu2'*Dfwu2 ;
                zeros(1,np+nx2)      Dfwu1'*Cfwu1  zeros(1,nu2)  Dfwu1'*Dfwu1       0      ;
              zeros(1,np+nx2+nu1)                  Dfwu2'*Cfwu2        0      Dfwu2'*Dfwu2 ;]; % convenient compilation of all weights in one matrix
    nJ = size(Jss,1);
    Q = Jss(1:nJ-np/2,1:nJ-np/2);        % weight on super plant states
    R = Jss(nJ-np/2+1:nJ,nJ-np/2+1:nJ);  % Weight on super plant control
    N = Jss(1:nJ-np/2,nJ-np/2+1:nJ);     % Super plant cross term weights

% LQR feedback gain
K = lqr(Ass,Bss,Q,R,N);

% Generating estimator
Ckn = [0 1 0 0]; % only have test mass position measurement
% L = lqr(A',Ckn',diag([1 1 1 1]),2e-10)'; % lqr defined estimatorgain
L = place(A',Ckn',2*pi*[pair(100,150) pair(100,120)])'; % butterworth-ish pattern
Pest = ss(A-L*Ckn,[L Bu],eye(4),zeros(4,3)); % estimator state space

% Generating overall control law
Kx = K(:,1:4); Kw = K(:,5:end); % Components of K feedback gain. Kx is for the plantr states, Kw is for the augmented states.
S = [zeros(nu1,nx2) Afwu1 zeros(nu1,nu2);zeros(nu2,nx2) zeros(nu2,nu1) Afwu2]; % A matrix for combined weighting function filter
T = [Bfwu1 zeros(nu1,1);zeros(nu2,1) Bfwu2]; % B matrix for combined weighting function filter
AA = [(A-L*Ckn-Bu*Kx) -Bu*Kw; zeros(nx2,np) Afwx2 zeros(nx2,nu1+nu2);-T*Kx (S-T*Kw)];
BB = [L;Bfwx2(:,np/2);zeros(nu1+nu2,1)];
CC = K;
DD = [0;0];
SuperControl = ss(AA,BB,CC,DD); % SIMO compensator block.

% Breaking SuperControl into the two feedback filters
u1_filt = SuperControl(1,1); % top mass controller
u2_filt = SuperControl(2,1); % bottom mass controller

Plotting

f = 0.01:0.005:1000; w = 2*pi*f;
figure % loop gain plot
bode(P(2,2)*u1_filt,w),hold on
bode(P(2,3)*u2_filt,w)
bode(P(2,2)*u1_filt+P(2,3)*u2_filt,w),grid on
title('System Loop Gain with Frequency Weighting')
legend('u_1','u_2','Sum')
bform % format bode plot

figure % cost function plot
bode(Wu1(1,1)),hold on
bode(Wu2(1,1))
bode(Wx2(1,2))
bode(ss([],[],[],sqrt(r))),grid on
title('Cost Function Plot')
legend('u_1','u_2','x_2','u broadband')
bform % format bode plot

Standard LQR for comparison

Kstandard = lqr(A,Bu,diag([0 1 0 0]),diag(5*[r 10000*r]));
SuperControl_standard = ss(A-L*Ckn-Bu*Kstandard,L,Kstandard,[0;0]);
u1_filt_standard = SuperControl_standard(1,1); % top mass controller
u2_filt_standard = SuperControl_standard(2,1); % bottom mass controller

figure % loop gain plot
bode(P(2,2)*u1_filt_standard,w),hold on
bode(P(2,3)*u2_filt_standard,w)
bode(P(2,2)*u1_filt_standard+P(2,3)*u2_filt_standard,w),grid on
title('System Loop Gain with standard LQR')
legend('u_1','u_2','Sum')
bform % format bode plot

Cavity_Simulation_File % Simulink file. On my computer it takes about 2 minutes to run.

Plotting Simulink simulation results: RUN THIS CODE ONLY AFTER RUNNING

SIMULINK

I chose not to upload the data in .mat files because they collectively are about 60 MB

err = err_sim;
iter = length(err.signals.values);
[ph1,fh] = periodogram(err.signals.values(1:iter-1),hanning(iter-1),iter-1,1/dt); %#ok<NASGU>
err = err_sim1;
iter = length(err.signals.values);
[ph2,fh] = periodogram(err.signals.values(1:iter-1),hanning(iter-1),iter-1,1/dt);

figure,loglog(fh,sqrt(ph2),fh,sqrt(ph1),[10 10000],[1e-18 1e-21],'LineWidth',3),grid on
set(gca,'XLim',[0.1 8000],'YLim',[1e-25 1e-12],'FontSize',15)
legend('Standard LQR','Frequency LQR','Requirement')
xlabel('Frequency (Hz)')
ylabel('Calibrated Cavity Error (m/\surdHz)')
title('Calibrated Cavity Error with Frequency and Standard LQR Control')

t = 0:dt:t_end;
figure
plot(t,err_sim.signals.values,t,err_sim1.signals.values,[0 t_end],Cavity_rms_limit*[1 1],'r',[0 t_end],-Cavity_rms_limit*[1 1],'r','LineWidth',3),grid on
set(gca,'FontSize',15,'XLim',[0 t_end],'YLim',Cavity_rms_limit*1.1*[-1 1])
legend('Frequency LQR','Standard LQR','RMS Requirement')
xlabel('Time (seconds)')
ylabel('Displacement (N)')
title('Cavity Error Signal')

figure
plot(t,u1.signals.values,t,u1b.signals.values,[0 t_end],top_sat*[1 1],'r',[0 t_end],-top_sat*[1 1],'r','LineWidth',3),grid on
set(gca,'FontSize',15,'XLim',[0 t_end],'YLim',top_sat*1.1*[-1 1])
legend('Frequency LQR','Standard LQR','Saturation Limit')
xlabel('Time (seconds)')
ylabel('Force (N)')
title('Top Mass Actuation')

figure
plot(t,u2.signals.values,t,u2b.signals.values,'LineWidth',3),grid on%,[0 t_end],bottom_sat*[1 1],'r',[0 t_end],-bottom_sat*[1 1],'r','LineWidth',3),grid on
set(gca,'FontSize',15,'XLim',[0 t_end],'YLim',bottom_sat*[-1 1]/10)
legend('Frequency LQR','Standard LQR')
xlabel('Time (seconds)')
ylabel('Force (N)')
title('Bottom Mass Actuation')