From 8807ccbd85dba4a26f0c4862c9b0514b88f4432b Mon Sep 17 00:00:00 2001 From: Thierry Zamofing Date: Wed, 31 Oct 2018 16:54:09 +0100 Subject: [PATCH] first result with observer controller --- matlab/StateSpaceControlDesign.m | 158 +++++++++++++++++-------------- matlab/identifyFxFyStage.m | 101 +++++++++++++++----- matlab/observer.slx | Bin 24141 -> 24913 bytes python/MXTuning.py | 6 +- 4 files changed, 169 insertions(+), 96 deletions(-) diff --git a/matlab/StateSpaceControlDesign.m b/matlab/StateSpaceControlDesign.m index a627b6a..cd15116 100644 --- a/matlab/StateSpaceControlDesign.m +++ b/matlab/StateSpaceControlDesign.m @@ -16,43 +16,35 @@ function [ssc]=StateSpaceControlDesign(mot,motid) % % https://www.youtube.com/watch?v=Lax3etc837U - ss_ol=mot.ss; - ss_ol.Name='open loop'; + %ss_ol=mot.ssPlt; + ss_ol_plt=mot.ssPlt; %real plant (model of real plant) + ss_ol_plt.Name='open loop plant'; + ss_ol_mdl=mot.ssMdl;%ssMdl; %simplified model (observable,controlable) for observer + ss_ol_mdl.Name='open loop model'; + + [Ap,Bp,Cp,Dp]=ssdata(ss_ol_plt); + [Am,Bm,Cm,Dm]=ssdata(ss_ol_mdl); + + %sys=ss(sys.A,sys.B,sys.C(3,:),0); % this would reduce the outputs to position only - figure();h=bodeplot(ss_ol); + figure();h=bodeplot(ss_ol_plt,ss_ol_mdl); setoptions(h,'IOGrouping','all') - A=ss_ol.A; - B=ss_ol.B; - C=ss_ol.C; - D=ss_ol.D; - - P=ctrb(A,B); - if rank(A)==rank(P) - disp('sys controlable') - else - disp('sys not controlable') - end - - Q=obsv(A,C); - if rank(A)==rank(Q) - disp('sys observable') - else - disp('sys not observable') - end - % step answer on open loop: t = 0:1E-4:.5; u = ones(size(t)); - x0 = zeros(1,length(ss_ol.A)); + xp0 = zeros(1,length(Ap)); + xm0 = zeros(1,length(Am)); - [y,t,x] = lsim(ss_ol,u,t,x0); - figure();plot(t,y);title('step on open loop'); + [yp,t,x] = lsim(ss_ol_plt,u,t,xp0); + [ym,t,x] = lsim(ss_ol_mdl,u,t,xm0); + figure();plot(t,yp,t,ym,'--');title('step on open loop (plant and model)'); + legend('plt.iqMeas','plt.iqVolts','plt.actPos','mdl.iqMeas','mdl.iqVolts','mdl.actPos') - poles = eig(A); - w0=abs(poles); - ang=angle(-poles); + poles = eig(Am); + %w0=abs(poles); + %ang=angle(-poles); %------------------- %p=w0.*exp(j.*ang) @@ -61,38 +53,57 @@ function [ssc]=StateSpaceControlDesign(mot,motid) %place poles for the controller feedback if motid==1 %2500rad/s = 397Hz -> locate poles here - p1=-3300+2800i; - p2=-2700+500i; - p3=-2500+10i; - %p1=-3300+2800i; - %p2=-1500+500i; - %p3=-1200+10i; - P=[p1 p1' p2 p2' p3 p3']; + %6300rad/s = 1027Hz -> locate poles here + if length(poles)==4 + p1=-6300+2800i; + p2=-6200+1500i; + P=[p1 p1' p2 p2']; + else + p1=-3300+2800i; + p2=-2700+500i; + p3=-2500+10i; + %p1=-3300+2800i; + %p2=-1500+500i; + %p3=-1200+10i; + P=[p1 p1' p2 p2' p3 p3']; + end else %2500rad/s = 397Hz -> locate poles here - p1=-3300+2800i; - p2=-1900+130i; - p3=-2900+80i; - p4=-2300+450i; - p5=-2000+20i; - p6=-1500+10i; - %p1=-3300+2800i; - %p2=-1500+500i; - %p3=-1200+10i; - P=[p1 p1' p2 p2' p3 p3'];% p4 p4' p5 p5' p6 p6']; + %6300rad/s = 1027Hz -> locate poles here + if length(poles)==4 + p1=-6300+2800i; + p2=-6200+1500i; + P=[p1 p1' p2 p2']; + else + p1=-3300+2800i; + p2=-1900+130i; + p3=-2900+80i; + p4=-2300+450i; + p5=-2000+20i; + p6=-1500+10i; + %p1=-3300+2800i; + %p2=-1500+500i; + %p3=-1200+10i; + P=[p1 p1' p2 p2' p3 p3'];% p4 p4' p5 p5' p6 p6']; + end end - K = place(A,B,P); - %K = acker(A,B,P); - V=-1./(C*(A-B*K)^-1*B); %(from Lineare Regelsysteme2 (Glattfelder) page:173 ) + K = place(Am,Bm,P); + %K = acker(Am,Bm,Pm); + V=-1./(Cm*(Am-Bm*K)^-1*Bm); %(from Lineare Regelsysteme2 (Glattfelder) page:173 ) %Nbar(2)=1; %the voltage stuff is crap for now if length(V)>1 V=V(3); % only the position scaling needed end + %prefilter to compensate non observable resonance frequencies + numV=mot.prefilt.Numerator{1}; + denV=mot.prefilt.Denominator{1}; + + % step answer on closed loop with space state controller: t = 0:1E-4:.5; - ss_cl = ss(A-B*K,B*V,C,0,'Name','space state controller','InputName',mot.ss.InputName,'OutputName',mot.ss.OutputName); - [y,t,x]=lsim(ss_cl,V*u,t,x0); + ss_cl = ss(Am-Bm*K,Bm*V,Cm,0,'Name','space state controller','InputName',mot.ssMdl.InputName,'OutputName',mot.ssMdl.OutputName); + [y,t,x]=lsim(ss_cl,V*u,t,xm0); figure();plot(t,y);title('step on closed loop'); @@ -102,29 +113,38 @@ function [ssc]=StateSpaceControlDesign(mot,motid) if motid==1 op1=(p1*5); op2=(p2*5); - op3=(p3*5); - OP=[op1 op1' op2 op2' op3 op3']; + if length(poles)>4 + op3=(p3*5); + OP=[op1 op1' op2 op2' op3 op3']; + else + OP=[op1 op1' op2 op2']; + end + else op1=(p1*2); op2=(p2*2); - op3=(p3*2); - op4=(p4*2); - op5=(p5*2); - op6=(p6*2); - OP=[op1 op1' op2 op2' op3 op3'];% op4 op4' op5 op5' op6 op6']; + if length(poles)>4 + op3=(p3*2); + op4=(p4*2); + op5=(p5*2); + op6=(p6*2); + OP=[op1 op1' op2 op2' op3 op3'];% op4 op4' op5 op5' op6 op6']; + else + OP=[op1 op1' op2 op2']; + end end - L=place(A',C',OP)'; + L=place(Am',Cm',OP)'; %L=acker(A',C',OP)'; - At = [ A-B*K B*K - zeros(size(A)) A-L*C ]; - Bt = [ B*V - zeros(size(B)) ]; - Ct = [ C zeros(size(C)) ]; + At = [ Am-Bm*K Bm*K + zeros(size(Am)) Am-L*Cm ]; + Bt = [ Bm*V + zeros(size(Bm)) ]; + Ct = [ Cm zeros(size(Cm)) ]; % step answer on closed loop with observer controller: - ss_o = ss(At,Bt,Ct,0,'Name','observer controller','InputName',{'desPos'},'OutputName',mot.ss.OutputName); - figure();lsim(ss_o,ones(size(t)),t,[x0 x0]);title('step on closed loop with observer'); + ss_o = ss(At,Bt,Ct,0,'Name','observer controller','InputName',{'desPos'},'OutputName',mot.ssMdl.OutputName); + figure();lsim(ss_o,ones(size(t)),t,[xm0 xm0]);title('step on closed loop with observer'); % *** disctrete observer controller *** @@ -134,7 +154,7 @@ function [ssc]=StateSpaceControlDesign(mot,motid) ss_od .Name='discrete obsvr ctrl'; % step answer on closed loop with disctrete observer controller: t = 0:Ts:.05; - figure();lsim(ss_od ,ones(size(t)),t,[x0 x0]);title('step on closed loop with observer discrete'); + figure();lsim(ss_od ,ones(size(t)),t,[xm0 xm0]);title('step on closed loop with observer discrete'); %plot all bode diagrams of desPos->actPos @@ -148,8 +168,8 @@ function [ssc]=StateSpaceControlDesign(mot,motid) %calculate matrices for the simulink system - Ao=A-L*C; - Bo=[B L]; + Ao=Am-L*Cm; + Bo=[Bm L]; Co=K; Do=zeros(size(Co,1),size(Bo,2)); mdlName='observer'; @@ -157,7 +177,7 @@ function [ssc]=StateSpaceControlDesign(mot,motid) %state space controller ssc=struct(); - for k=["Ts","A","B","C","D","Ao","Bo","Co","Do","V","K","L","ss_cl","ss_o","ss_od"] + for k=["Ts","Ap","Bp","Cp","Dp","Ao","Bo","Co","Do","V","K","L","ss_cl","ss_o","ss_od","numV","denV"] ssc=setfield(ssc,k,eval(k)); end diff --git a/matlab/identifyFxFyStage.m b/matlab/identifyFxFyStage.m index c594ff9..5bf2470 100644 --- a/matlab/identifyFxFyStage.m +++ b/matlab/identifyFxFyStage.m @@ -17,7 +17,8 @@ function [mot1,mot2]=identifyFxFyStage() % meas : a MATLAB idfrd model with data w,mag,phase % mdl : a structure with the python numerators and denominators for the transfer functions % tfc,tf_mdl : various transfer functions - % ss : the final continous state space model of the plant + % ssPlt : the final continous state space model of the plant (not observable, not controlable) + % ssMdl : the simplified continous state space model for the observer (observable, controlable) % % The used data files (generated from Python) are: % (located for now in: /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/18_10_02/ ) @@ -51,7 +52,6 @@ function [mot1,mot2]=identifyFxFyStage() fMdl=load(strcat(path,sprintf('model%d.mat',motid))); obj.mdl=fMdl; - end function tfc=currstep(obj) @@ -61,7 +61,7 @@ function [mot1,mot2]=identifyFxFyStage() s=str2ndOrd(tfc); t=(0:199)*50E-6; [y,t]=step(tfc,t); - f=figure(); + figure(); subplot(1,2,1); plot(t*1000,obj.currstep.OutputData(11:210),'b',t*1000,y*1000,'r'); xlabel('ms') @@ -83,6 +83,22 @@ function [mot1,mot2]=identifyFxFyStage() s=sprintf('k:%g w0:%g damp:%g',k,w0,damp); end + function chkCtrlObsv(ss,s) + P=ctrb(ss.A,ss.B); + if rank(ss.A)==rank(P) + ct='';%controlable + else + ct='not ';%not controlable + end + + Q=obsv(ss.A,ss.C); + if rank(ss.A)==rank(Q) + ob='';%sys observable + else + ob='not ';%not observable + end + disp([s,' is ',ct,'controlable and ',ob,'observable.']); + end function mot=fyStage() mot=loadData('/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/18_10_02/',1); @@ -102,7 +118,7 @@ function [mot1,mot2]=identifyFxFyStage() denc=myNorm(mot.mdl.denc); num1=myNorm(mot.mdl.num1); den1=myNorm(mot.mdl.den1); - num2=myNorm(mot.mdl.num2); + num2=myNorm(mot.mdl.num2); %resonance den2=myNorm(mot.mdl.den2); g1=tf(numc,denc); % iqCmd->iqMeas s1=ss(g1); @@ -114,15 +130,38 @@ function [mot1,mot2]=identifyFxFyStage() s2=ss(g2); s3=append(s1,s2); s3.A(3,2)=s3.C(1,2)*s3.B(3,2); - mot.ss=ss(s3.A,s3.B(:,1),s3.C,0); % single input, remove input iqMeas + mot.ssPlt=ss(s3.A,s3.B(:,1),s3.C,0); % single input, remove input iqMeas + mot.ssPlt.InputName{1}='iqCmd'; + mot.ssPlt.OutputName{1}='iqMeas'; + mot.ssPlt.OutputName{2}='iqVolts'; + mot.ssPlt.OutputName{3}='actPos'; + chkCtrlObsv(mot.ssPlt,'ssPlt fyStage'); + % u +-----------+ y + %iqCmd------->|1 1|-------> iqMeas + % | 2|-------> iqVolts + % | 3|-------> actPos + % +-----------+ + + %simplified model without resonance + g2=tf(num1,den1); %iqMeas->ActPos without resonance frequencies + s2=ss(g2); + s3=append(s1,s2); + s3.A(3,2)=s3.C(1,2)*s3.B(3,2); + mot.ssMdl=ss(s3.A,s3.B(:,1),s3.C,0); % single input, remove input iqMeas + mot.ssMdl.InputName{1}='iqCmd'; + mot.ssMdl.OutputName{1}='iqMeas'; + mot.ssMdl.OutputName{2}='iqVolts'; + mot.ssMdl.OutputName{3}='actPos'; + chkCtrlObsv(mot.ssMdl,'ssMdl fyStage'); + + %filter in front of plant to suppress resonances (inverse of reonance) + den=num2;%num=1; + num=den2;%den=[1 0 0]; + mot.prefilt=tf(num,den); - mot.ss.InputName{1}='iqCmd'; - mot.ss.OutputName{1}='iqMeas'; - mot.ss.OutputName{2}='iqVolts'; - mot.ss.OutputName{3}='actPos'; %h=bodeplot(mot.meas,'r',mot.tf4_2,'b',mot.tf6_4,'g'); %h=bodeplot(mot.meas,'r',mot.tf2_0,'b',mot.tf_mdl,'g',mot.w); - tmp=tf(mot.ss);h=bodeplot(mot.meas,'r',tmp(3,1),'g',mot.w); + t1=tf(mot.ssPlt);t2=tf(mot.ssMdl);h=bodeplot(mot.meas,'r',t1(3,1),'g',t2(3,1),'b',mot.w); setoptions(h,'FreqUnits','Hz','Grid','on'); end @@ -149,24 +188,22 @@ function [mot1,mot2]=identifyFxFyStage() denc=myNorm(mot.mdl.denc); num1=myNorm(mot.mdl.num1); den1=myNorm(mot.mdl.den1); - num2=myNorm(mot.mdl.num2); + num2=myNorm(mot.mdl.num2); %resonance den2=myNorm(mot.mdl.den2); - num3=myNorm(mot.mdl.num3); + num3=myNorm(mot.mdl.num3); %resonance den3=myNorm(mot.mdl.den3); - num4=myNorm(mot.mdl.num4); + num4=myNorm(mot.mdl.num4); %resonance den4=myNorm(mot.mdl.den4); - num5=myNorm(mot.mdl.num5); + num5=myNorm(mot.mdl.num5); %resonance den5=myNorm(mot.mdl.den5); - num=myNorm(mot.mdl.num); - den=myNorm(mot.mdl.den); + %num=myNorm(mot.mdl.num); + %den=myNorm(mot.mdl.den); g1=tf(numc,denc); % iqCmd->iqMeas s1=ss(g1); s1.C=[s1.C; 1E5* 2.4E-3 1E-3*s1.C(2)*8.8]; % add output iqVolts: iqVolts= i_meas*R+i_meas'*L 2.4mH 8.8Ohm (took random scaling values) %tf(s1) % display all transfer functions num=conv(conv(conv(conv(num1,num2),num3),num4),num5);%num=1; den=conv(conv(conv(conv(den1,den2),den3),den4),den5);%den=[1 0 0]; - num=conv(num1,num2);%num=1; - den=conv(den1,den2);%den=[1 0 0]; g2=tf(num,den); %iqMeas->ActPos s2=ss(g2); @@ -177,21 +214,37 @@ function [mot1,mot2]=identifyFxFyStage() s3.A(3,2)=s3.C(1,2)*s3.B(3,2); s3.A(3,2)=s3.C(1,2)*s3.B(3,2); - mot.ss=ss(s3.A,s3.B(:,1),s3.C,0); % single input, remove input iqMeas + mot.ssPlt=ss(s3.A,s3.B(:,1),s3.C,0); % single input, remove input iqMeas - mot.ss.InputName{1}='iqCmd'; - mot.ss.OutputName{1}='iqMeas'; - mot.ss.OutputName{2}='iqVolts'; - mot.ss.OutputName{3}='actPos' ; + mot.ssPlt.InputName{1}='iqCmd'; + mot.ssPlt.OutputName{1}='iqMeas'; + mot.ssPlt.OutputName{2}='iqVolts'; + mot.ssPlt.OutputName{3}='actPos' ; + chkCtrlObsv(mot.ssPlt,'ssPlt fxStage'); % u +-----------+ y %iqCmd------->|1 1|-------> iqMeas % | 2|-------> iqVolts % | 3|-------> actPos % +-----------+ + %simplified model without resonance + g2=tf(num1,den1); %iqMeas->ActPos without resonance frequencies + s2=ss(g2); + s3=append(s1,s2); + s3.A(3,2)=s3.C(1,2)*s3.B(3,2); + mot.ssMdl=ss(s3.A,s3.B(:,1),s3.C,0); % single input, remove input iqMeas + mot.ssMdl.InputName=mot.ssPlt.InputName; + mot.ssMdl.OutputName=mot.ssPlt.OutputName; + chkCtrlObsv(mot.ssMdl,'ssMdl fxStage'); + + %filter in front of plant to suppress resonances (inverse of reonance) + den=conv(conv(conv(num2,num3),num4),num5);%num=1; + num=conv(conv(conv(den2,den3),den4),den5);%den=[1 0 0]; + mot.prefilt=tf(num,den); + %h=bodeplot(mot.meas,'r',mot.tf4_2,'b',mot.tf6_4,'g',mot.tf13_9,'m',mot.tf_py,'b'); %h=bodeplot(mot.meas,'r',mot.tf2_0,'b',mot.tf_mdl,'g',mot.w); - tmp=tf(mot.ss);h=bodeplot(mot.meas,'r',tmp(3,1),'g',mot.w); + t1=tf(mot.ssPlt);t2=tf(mot.ssMdl);h=bodeplot(mot.meas,'r',t1(3,1),'g',t2(3,1),'b',mot.w); setoptions(h,'FreqUnits','Hz','Grid','on'); %controlSystemDesigner('bode',1,mot.tf_py); % <<<<<<<<< This opens a transferfiûnction that can be edited diff --git a/matlab/observer.slx b/matlab/observer.slx index de7a0a14a92f1d205b6025508028d9798a711031..2ad9c104b94167bce4fd18b06a9314740a66aed8 100644 GIT binary patch delta 12613 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 I|5N#Y010ADp8x;= delta 11796 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 diff --git a/python/MXTuning.py b/python/MXTuning.py index ddccd99..53cc6cb 100755 --- a/python/MXTuning.py +++ b/python/MXTuning.py @@ -339,9 +339,9 @@ Examples:'''+''.join(map(lambda s:cmd+s, exampleCmd))+'\n ' #tune.init_stage(); plt.close('all') #tune.custom_chirp() - tune.custom_chirp(motor=1,minFrq=1,maxFrq=3000,tSec=5,mode=0,file='/tmp/cst_chirp0.npz') - tune.custom_chirp(motor=2,minFrq=1,maxFrq=1000,tSec=5,mode=1,file='/tmp/cst_chirp1.npz') - tune.custom_chirp(motor=1,minFrq=1,maxFrq=3000,tSec=5,mode=2,file='/tmp/cst_chirp2.npz') + tune.custom_chirp(motor=1,minFrq=100,maxFrq=3000,amp=10,tSec=5,mode=0,file='/tmp/cst_chirp0.npz') + #tune.custom_chirp(motor=2,minFrq=1,maxFrq=1000,tSec=5,mode=1,file='/tmp/cst_chirp1.npz') + #tune.custom_chirp(motor=1,minFrq=1,maxFrq=3000,tSec=5,mode=2,file='/tmp/cst_chirp2.npz') plt.show() #------------------ Main Code ----------------------------------