This commit is contained in:
2019-02-07 15:04:53 +01:00
parent db14034175
commit 3e83b82a5d
4 changed files with 273 additions and 218 deletions

View File

@@ -250,7 +250,22 @@ The resistance of the stage is 8.8 $\Omega$\\
The inductance of the stage is 2.4 mH.\\
Nevertheless simulations with \verb|current_loop.slx| showed, that the current loop only works in the discrete domain. In continous domain neither the amplification nor the shape mached.\\
Therefore the only approach is to use the second order transfer function as approximated in section \ref{sec:measCurStep}.
Therefore the only approach is to use the second order transfer function as approximated in section \ref{sec:measCurStep}.\\
\textbf{TODO:}
A further test will be to 'remove' the current loop. This can be done by setting:$IiGain=0, IpfGain=1, IpbGain=-1$.
The resulting transfer function is:
\[
\frac{Ipf}
{\frac{L}{PwmSF}s +\frac{R}{PwmSF}} =\\
\frac{Ipf \cdot PwmSF}
{L s +R} =\\
\frac{\frac{Ipf \cdot PwmSF}{R}}
{\frac{L}{R} s +1}\\
\\
\]
This is a $PT_1$ element with a time constant of $\frac{L}{R}=\frac{2.4mH}{8.8\Omega}=0.27ms$. But probably due to additional cables etc. the resistance and therefore also the timeconstant is bigger.
\subsection{Mechanical model}

View File

@@ -484,9 +484,9 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.9591816"
inkscape:cx="214.19855"
inkscape:cy="140.433"
inkscape:zoom="2.7995642"
inkscape:cx="189.09484"
inkscape:cy="145.66402"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
@@ -535,7 +535,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@@ -1606,12 +1606,12 @@
<g
id="g3960">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.73211181;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.45050514;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect3591"
width="74.421585"
height="99.359833"
x="107.41199"
y="899.23157" />
width="74.703194"
height="69.415634"
x="107.27119"
y="908.53473" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#arrowSimple-3)"
d="m 50.18638,921.41108 56.70939,-2e-5"
@@ -1630,28 +1630,7 @@
id="tspan3607"
sodipodi:role="line">iqCmd</tspan></text>
<g
transform="translate(-405.25244,162.8825)"
id="g3856">
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path3609"
d="m 587.02969,749.59853 56.70939,-2e-5"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99921262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#arrowSimple-3)" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="647.9472"
y="753.73669"
id="text3611"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3613"
x="647.9472"
y="753.73669">iqVolts</tspan></text>
</g>
<g
transform="translate(-405.25244,161.60653)"
transform="translate(-405.25244,142.9158)"
id="g3861">
<path
sodipodi:nodetypes="cc"
@@ -1672,7 +1651,7 @@
y="779.45502">iqMeas (equals force and acceleration)</tspan></text>
</g>
<g
transform="translate(-405.25244,163.03468)"
transform="translate(-405.25244,144.34395)"
id="g3866">
<path
sodipodi:nodetypes="cc"
@@ -1693,7 +1672,7 @@
y="803.9231">actVel</tspan></text>
</g>
<g
transform="translate(-405.25244,162.8825)"
transform="translate(-405.25244,144.19177)"
id="g3871">
<path
sodipodi:nodetypes="cc"
@@ -1716,15 +1695,15 @@
<text
sodipodi:linespacing="125%"
id="text3936"
y="943.24255"
y="937.57361"
x="123.30198"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="943.24255"
y="937.57361"
x="123.30198"
id="tspan3938"
sodipodi:role="line">stage</tspan><tspan
y="961.99255"
y="956.32361"
x="123.30198"
sodipodi:role="line"
id="tspan3986">x or y</tspan></text>

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -1,5 +1,5 @@
function [mot1,mot2]=identifyFxFyStage()
function motCell=identifyFxFyStage(mode)
%loads recorded data of the current step and bode diagrams of the stages then plots the bode diagrams and identifies
%the current step transfer function
%
@@ -7,13 +7,14 @@ function [mot1,mot2]=identifyFxFyStage()
%
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> iqVolts
% | 2|-------> actVel
% | 3|-------> actPos
% +-----------+
%
% the returned motor objects mot1 and mot2 contains:
%
% w,mag,phase : (gathered data with Python)
% currstep : gathered data with Python: file 'curr_step%d.mat'
% w,mag,phase : gathered data with Python: file 'full_bode_mot%d.mat'
% 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
@@ -22,12 +23,21 @@ function [mot1,mot2]=identifyFxFyStage()
% ssMdlNC : model without resonance and current loop
%
% 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/ )
% (located for now in: /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/<date>/ )
% - curr_step[1|2].mat
% - full_bode_mot[1|2].mat
% - model[1|2].mat
%
% loadData reads members currstep,w,mag,phase,meas
%
% mode bits:
% 0 1 : add ss-models and do checks for motor 1 fy
% 1 2 : add ss-models and do checks for setup motor 2 fx
% 2 4 : identify_currstep
% 3 8 : identify_tf2
% The default value for mode is 3
%References:
%create ss from tf MIMO:
%https://ch.mathworks.com/matlabcentral/answers/37152-how-to-convert-tf2ss-for-mimo-system
@@ -43,9 +53,6 @@ function [mot1,mot2]=identifyFxFyStage()
f=load(strcat(path,sprintf('full_bode_mot%d.mat',motid)));
obj.w=f.frq*2*pi; %convert from Hz to rad/s
if motid==2
f.db_mag(1:224)=f.db_mag(225); % reset bad values at low frequencies
end
obj.mag=10.^(f.db_mag/20); %mag not in dB
obj.phase=f.deg_phase*pi/180; %phase in rad
response = obj.mag.*exp(1j*obj.phase);
@@ -55,7 +62,8 @@ function [mot1,mot2]=identifyFxFyStage()
obj.mdl=fMdl;
end
function tfc=currstep(obj)
function tfc=identify_currstep(obj)
%identification of second order transfer function out of the current step recorded data.
opt=tfestOptions;
opt.Display='off';
tfc = tfest(obj.currstep, 2, 0,opt);
@@ -77,6 +85,42 @@ function [mot1,mot2]=identifyFxFyStage()
print(f,sprintf('figures/currstep_%d',obj.id),'-depsc');
end
function tf2=identify_tf2(obj)
opt=tfestOptions;
opt.Display='off';
opt.initializeMethod='iv';
%opt.WeightingFilter=[1,5;30,670]*(2*pi); % Hz->rad/s conversion
opt.WeightingFilter=[1,2;10,100]*(2*pi); % Hz->rad/s conversion
figure();
tf2 = tfest(obj.meas, 2, 0, opt);disp(str2ndOrd(tf2));
subplot(1,1,1);
h=bodeplot(tf2,'r',obj.meas,'b',obj.w);
setoptions(h,'FreqUnits','Hz','Grid','on');
p=getoptions(h);p.YLim{2}=[-360 90];p.YLimMode='manual';setoptions(h,p);
ax=h.getaxes();
legend(ax(1),'Location','sw',{'real','tf2'});
frq=obj.w/(2*pi)
[m1,p1,w1]=bode(obj.meas,obj.w);
[m2,p2,w2]=bode(tf2,obj.w);
m1=20*log10(reshape(m1,[],1));p1=reshape(p1,[],1);
m2=20*log10(reshape(m2,[],1));p2=reshape(p2,[],1);
me=m1-m2;
pe=p1-p2;
figure();
ax1=subplot(2,1,1);
title('remaining mag (dB) and phase error')
semilogx(frq,me,'r');
ax2=subplot(2,1,2);
semilogx(frq,pe,'r');
linkaxes([ax1,ax2],'x')
ax2.YLim=[-90 90];ax2.YLimMode='manual';
ax2.XLim=[frq(1), frq(1000)];ax2.XLimMode='manual';
grid(ax1,'on');grid(ax2,'on');
end
function s=str2ndOrd(tf)
den=tf.Denominator;
num=tf.Numerator;
@@ -101,6 +145,9 @@ function [mot1,mot2]=identifyFxFyStage()
ob='not ';%not observable
end
disp([s,' is ',ct,'controlable and ',ob,'observable.']);
%tf(ss) % display all transfer functions
end
function y=myNorm(y)
@@ -109,206 +156,220 @@ function [mot1,mot2]=identifyFxFyStage()
end
function plotBode(mot)
t1=tf(mot.ssPlt);t2=tf(mot.ssMdl_c1);t3=tf(mot.ssMdl_12);h=bodeplot(mot.meas,'r',t1(3,1),'g',t2(3,1),'b',t3(1,1),'m',mot.w);
figure()
h=bodeplot(mot.meas,'r',mot.ss_plt(3,1),'g',mot.ss_c1(3,1),'b',mot.ss_d1(3,1),'m',mot.ss_1(2,1),'c',mot.ss_0(2,1),'k',mot.w);
setoptions(h,'FreqUnits','Hz','Grid','on');
p=getoptions(h);p.YLim{2}=[-360 90];p.YLimMode='manual';setoptions(h,p);
ax=h.getaxes();
legend(ax(1),'Location','sw',{'real','plant','no res','no cur + 1 res'});
legend(ax(1),'Location','sw',{'real','plant','c1','d1','1','0'});
print(gcf,sprintf('figures/plotBode_%d',mot.id),'-depsc');
end
function mot=fyStage()
motid=1;
%mot=loadData('/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/18_10_02/',motid);
mot=loadData('/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/19_01_29/',motid);
function mot=fyStage(mot)
mot.id=motid;
mot.tfc=currstep(mot);
%current loop iqCmd->iqMeas
tfc=tf(mot.mdl.numc,mot.mdl.denc,'InputName','iqCmd','OutputName','iqMeas');
opt=tfestOptions;
opt.Display='off';
opt.initializeMethod='iv';
opt.WeightingFilter=[1,5;30,670]*(2*pi); % Hz->rad/s conversion
%simplified current loop iqCmd->iqMeas (first order tf)
tfd=tf(mot.mdl.numd,mot.mdl.dend,'InputName','iqCmd','OutputName','iqMeas');
figure();
mot.tf2_0 = tfest(mot.meas, 2, 0, opt);disp(str2ndOrd(mot.tf2_0));
mot.tf_mdl=idtf(mot.mdl.num,mot.mdl.den);
%ss([g1 mot.tf_mdl],'minimal') this doesn't work as expected
%resonance iqMeas->iqForce
tf2=tf(mot.mdl.num2,mot.mdl.den2,'InputName','iqMeas','OutputName','iqForce');
tfc=tf(mot.mdl.numc,mot.mdl.denc); %current loop iqCmd->iqMeas
tf1=tf(mot.mdl.num1,mot.mdl.den1); %current to position
tf2=tf(mot.mdl.num2,mot.mdl.den2); %resonance
%state -space model: ssc:current ssm:mechanics ssa:all (current+mechanics)
% plant
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> iqVolts
% | 3|-------> actPos
% +-----------+
ssc=ss(tfc);
ssc.C=[ssc.C; 1E5* 2.4E-3 1E-3*ssc.C(2)*8.8]; % add output iqVolts: iqVolts= i_meas*R+i_meas'*L 2.4mH 8.8Ohm (took random scaling values)
ssm=ss(tf1*tf2); %iqMeas->ActPos
ssa=append(ssc,ssm);
ssa.A(3,2)=ssa.C(1,2)*ssa.B(3,2);
mot.ssPlt=ss(ssa.A,ssa.B(:,1),ssa.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');
%tf(ssa) % display all transfer functions
%simplified model without resonance
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> iqVolts
% | 3|-------> actPos
% +-----------+
ssm=ss(tf1); %iqMeas->ActPos
ssa=append(ssc,ssm);
ssa.A(3,2)=ssa.C(1,2)*ssa.B(3,2);
mot.ssMdl_c1=ss(ssa.A,ssa.B(:,1),ssa.C,0); % single input, remove input iqMeas
mot.ssMdl_c1.InputName{1}='iqCmd';
mot.ssMdl_c1.OutputName{1}='iqMeas';
mot.ssMdl_c1.OutputName{2}='iqVolts';
mot.ssMdl_c1.OutputName{3}='actPos';
chkCtrlObsv(mot.ssMdl_c1,'ssMdl_c1 fyStage');
%model without current loop, with one resonance
%this assumes that the iqCmd->iqMeas is not relevant for motion
% u +-----------+ y
%iqMeas------>|1 1|-------> actPos
% +-----------+
ssm=ss(tf1*tf2); %iqMeas->ActPos
mot.ssMdl_12=ssm; %iqMeas->ActPos without resonance frequencies
mot.ssMdl_12.InputName{1}='iqMeas';
mot.ssMdl_12.OutputName{1}='actPos';
chkCtrlObsv(mot.ssMdl_12,'ssMdl_12 fyStage');
%model without current loop, no resonance
%this assumes that the iqCmd->iqMeas is not relevant for motion
% u +-----------+ y
%iqMeas------>|1 1|-------> actPos
% +-----------+
ssm=ss(tf1); %iqMeas->ActPos
mot.ssMdl_1=ssm; %iqMeas->ActPos without resonance frequencies
mot.ssMdl_1.InputName{1}='iqMeas';
mot.ssMdl_1.OutputName{1}='actPos';
chkCtrlObsv(mot.ssMdl_1,'ssMdl_1 fyStage');
%current to position iqForce->actPos
tf1_=tf(mot.mdl.num1,mot.mdl.den1,'InputName','iqForce','OutputName','actPos');
ssLst=["tfc","tf1","tf2","tfc*tf1","tf1*tf2","tfc*tf1*tf2"];
%force(=current) to velocity and position iqForce->(actVel,actPos), actVel=s*actPos
tf1=tf({[mot.mdl.num1 0];mot.mdl.num1},mot.mdl.den1,'InputName','iqForce','OutputName',{'actVel','actPos'});
%simplified force(=current) to velocity and position iqForce->(actVel,actPos), actVel=s*actPos
tf0=tf({[mot.mdl.num0 0];mot.mdl.num0},mot.mdl.den0,'InputName','iqForce','OutputName',{'actVel','actPos'});
%check observable/controlable of transfer functions
ssLst=["tfc","tfd","tf0","tf1","tf2","tfc*tf1*tf2","tfc*tf1","tfd*tf1","tf1*tf2"];
sys=[];
for s = ssLst
eval('sys=ss('+s+');')
%t=tf(sys);
%disp(evalc('t'))
chkCtrlObsv(sys,char(s));
end
end
% sample code:
%tfc iqCmd-> iqMeas
%tf2 resonance iqMeas->iqForce
%tf1 iqForce->(actVel,actPos)
%connect(tfc,tf2,'iqCmd','iqForce');
%connect(tfc,tf2,'iqCmd',{'iqMeas','iqForce'});
%connect(tfc,tf2,tf1_,'iqCmd',{'iqMeas','iqForce','actPos'});
%connect(tfc,tf2,tf1_,'iqCmd',{'iqMeas','actPos'});
% best plant approximation
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> actVel
% | 3|-------> actPos
% +-----------+
mot.ss_plt=connect(tfc,tf1,tf2,'iqCmd',{'iqMeas','actVel','actPos'});
chkCtrlObsv(mot.ss_plt,'ss_plt fyStage');
%without resonance
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> actVel
% | 3|-------> actPos
% +-----------+
s=tf1.InputName{1};tf1.InputName{1}='iqMeas';
mot.ss_c1=connect(tfc,tf1,'iqCmd',{'iqMeas','actVel','actPos'});
chkCtrlObsv(mot.ss_c1,'ss_c1 fyStage');
tf1.InputName{1}=s;%restore
%simplified current, without resonance
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> actVel
% | 3|-------> actPos
% +-----------+
s=tf1.InputName{1};tf1.InputName{1}='iqMeas';
mot.ss_d1=connect(tfd,tf1,'iqCmd',{'iqMeas','actVel','actPos'});
chkCtrlObsv(mot.ss_d1,'ss_d1 fyStage');
tf1.InputName{1}=s;%restore
%no current loop, no resonance
% u +-----------+ y
%iqCmd------->|1 1|-------> actVel
% | 2|-------> actPos
% +-----------+
mot.ss_1=ss(tf1);
chkCtrlObsv(mot.ss_1,'ss_1 fyStage');
%simplified mechanics, no current loop, no resonance
% u +-----------+ y
%iqCmd------->|1 1|-------> actVel
% | 2|-------> actPos
% +-----------+
mot.ss_0=ss(tf0);
chkCtrlObsv(mot.ss_0,'ss_0 fyStage');
%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);
plotBode(mot)
end
function mot=fxStage()
motid=2;
%mot=loadData('/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/18_10_02/',motid);
mot=loadData('/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/19_01_29/',motid);
mot.id=motid;
currstep(mot);
function mot=fxStage(mot)
%current loop iqCmd->iqMeas
tfc=tf(mot.mdl.numc,mot.mdl.denc,'InputName','iqCmd','OutputName','iqMeas');
opt=tfestOptions;
opt.Display='off';
opt.initializeMethod='iv';
opt.WeightingFilter=[1,4;10,670]*(2*pi); % Hz->rad/s conversion
%simplified current loop iqCmd->iqMeas (first order tf)
tfd=tf(mot.mdl.numd,mot.mdl.dend,'InputName','iqCmd','OutputName','iqMeas');
figure();
mot.tf2_0 = tfest(mot.meas, 2, 0, opt);disp(str2ndOrd(mot.tf2_0));
mot.tf13_9 = tfest(mot.meas, 13, 9, opt);
mot.tf_mdl=idtf(mot.mdl.num,mot.mdl.den);
tfc=tf(mot.mdl.numc,mot.mdl.denc); %current loop iqCmd->iqMeas
tf1=tf(mot.mdl.num1,mot.mdl.den1); %current to position
tf2=tf(mot.mdl.num2,mot.mdl.den2); %resonance
tf3=tf(mot.mdl.num3,mot.mdl.den3); %resonance
tf4=tf(mot.mdl.num4,mot.mdl.den4); %resonance
tf5=tf(mot.mdl.num5,mot.mdl.den5); %resonance
%state -space model: ssc:current ssm:mechanics ssa:all (current+mechanics)
% plant
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> iqVolts
% | 3|-------> actPos
% +-----------+
ssc=ss(tfc);
ssc.C=[ssc.C; 1E5* 2.4E-3 1E-3*ssc.C(2)*8.8]; % add output iqVolts: iqVolts= i_meas*R+i_meas'*L 2.4mH 8.8Ohm (took random scaling values)
ssm=ss(tf1*tf2*tf3*tf4*tf5); %iqMeas->ActPos
ssa=append(ssc,ssm);
ssa.A(3,2)=ssa.C(1,2)*ssa.B(3,2);
mot.ssPlt=ss(ssa.A,ssa.B(:,1),ssa.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 fxStage');
%simplified model without resonance
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> iqVolts
% | 3|-------> actPos
% +-----------+
ssm=ss(tf1); %iqMeas->ActPos
ssa=append(ssc,ssm);
ssa.A(3,2)=ssa.C(1,2)*ssa.B(3,2);
mot.ssMdl_c1=ss(ssa.A,ssa.B(:,1),ssa.C,0); % single input, remove input iqMeas
mot.ssMdl_c1.InputName{1}='iqCmd';
mot.ssMdl_c1.OutputName{1}='iqMeas';
mot.ssMdl_c1.OutputName{2}='iqVolts';
mot.ssMdl_c1.OutputName{3}='actPos';
chkCtrlObsv(mot.ssMdl_c1,'ssMdl_c1 fxStage');
%model without current loop, with one resonance
%this assumes that the iqCmd->iqMeas is not relevant for motion
% u +-----------+ y
%iqMeas------>|1 1|-------> actPos
% +-----------+
ssm=ss(tf1*tf2); %iqMeas->ActPos
mot.ssMdl_12=ssm; %iqMeas->ActPos without resonance frequencies
mot.ssMdl_12.InputName{1}='iqMeas';
mot.ssMdl_12.OutputName{1}='actPos';
chkCtrlObsv(mot.ssMdl_12,'ssMdl_12 fxStage');
%resonance iqMeas->iqForce
tf2=tf(mot.mdl.num2,mot.mdl.den2,'InputName','iqMeas','OutputName','iqF1');
%resonance iqMeas->iqForce
tf3=tf(mot.mdl.num3,mot.mdl.den3,'InputName','iqF1','OutputName','iqF2');
%resonance iqMeas->iqForce
tf4=tf(mot.mdl.num4,mot.mdl.den4,'InputName','iqF2','OutputName','iqF3');
%resonance iqMeas->iqForce
tf5=tf(mot.mdl.num5,mot.mdl.den5,'InputName','iqF3','OutputName','iqForce');
%model without current loop, no resonance
%this assumes that the iqCmd->iqMeas is not relevant for motion
% u +-----------+ y
%iqMeas------>|1 1|-------> actPos
% +-----------+
ssm=ss(tf1); %iqMeas->ActPos
mot.ssMdl_1=ssm; %iqMeas->ActPos without resonance frequencies
mot.ssMdl_1.InputName{1}='iqMeas';
mot.ssMdl_1.OutputName{1}='actPos';
chkCtrlObsv(mot.ssMdl_1,'ssMdl_1 fxStage');
%current to position iqForce->actPos
tf1_=tf(mot.mdl.num1,mot.mdl.den1,'InputName','iqForce','OutputName','actPos');
ssLst=["tfc","tf1","tf2","tf3","tf4","tf5","tfc*tf1","tf1*tf2","tf1*tf2*tf3","tfc*tf1*tf2"];
%force(=current) to velocity and position iqForce->(actVel,actPos), actVel=s*actPos
tf1=tf({[mot.mdl.num1 0];mot.mdl.num1},mot.mdl.den1,'InputName','iqForce','OutputName',{'actVel','actPos'});
%simplified force(=current) to velocity and position iqForce->(actVel,actPos), actVel=s*actPos
tf0=tf({[mot.mdl.num0 0];mot.mdl.num0},mot.mdl.den0,'InputName','iqForce','OutputName',{'actVel','actPos'});
%check observable/controlable of transfer functions
ssLst=["tfc","tfd","tf0","tf1","tf2","tf3","tf4","tf5",...
"tfc*tf1*tf2","tfc*tf1","tfd*tf1","tf1*tf2","tf1*tf2*tf3"];
sys=[];
for s = ssLst
eval('sys=ss('+s+');')
%t=tf(sys);
%disp(evalc('t'))
chkCtrlObsv(sys,char(s));
end
end
%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);
% best plant approximation
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> actVel
% | 3|-------> actPos
% +-----------+
mot.ss_plt=connect(tfc,tf1,tf2,tf3,tf4,tf5,'iqCmd',{'iqMeas','actVel','actPos'});
chkCtrlObsv(mot.ss_plt,'ss_plt fxStage');
%without resonance
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> actVel
% | 3|-------> actPos
% +-----------+
s=tf1.InputName{1};tf1.InputName{1}='iqMeas';
mot.ss_c1=connect(tfc,tf1,'iqCmd',{'iqMeas','actVel','actPos'});
chkCtrlObsv(mot.ss_c1,'ss_c1 fxStage');
tf1.InputName{1}=s;%restore
%simplified current, without resonance
% u +-----------+ y
%iqCmd------->|1 1|-------> iqMeas
% | 2|-------> actVel
% | 3|-------> actPos
% +-----------+
s=tf1.InputName{1};tf1.InputName{1}='iqMeas';
mot.ss_d1=connect(tfd,tf1,'iqCmd',{'iqMeas','actVel','actPos'});
chkCtrlObsv(mot.ss_d1,'ss_d1 fxStage');
tf1.InputName{1}=s;%restore
%no current loop, no resonance
% u +-----------+ y
%iqCmd------->|1 1|-------> actVel
% | 2|-------> actPos
% +-----------+
mot.ss_1=ss(tf1);
chkCtrlObsv(mot.ss_1,'ss_1 fxStage');
%simplified mechanics, no current loop, no resonance
% u +-----------+ y
%iqCmd------->|1 1|-------> actVel
% | 2|-------> actPos
% +-----------+
mot.ss_0=ss(tf0);
chkCtrlObsv(mot.ss_0,'ss_0 fxStage');
plotBode(mot)
end
close all
mot1=fyStage();
mot2=fxStage();
motCell=cell(2,1);
for motid= 1:2
mot=loadData('/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/19_01_29/',motid);
mot.id=motid;
if bitand(mode,4)
%identification of second order transfer function out of the current step recorded data.
identify_currstep(mot{motid});
end
if bitand(mode,8)
%identification of second order transfer function out of the position recorded data.
identify_tf2(mot);
end
if motid==1 && bitand(mode,1)
mot=fyStage(mot);
end
if motid==2 && bitand(mode,2)
mot=fxStage(mot);
end
motCell{motid}=mot;
end
%controlSystemDesigner('bode',1,mot1.tf_py); % <<<<<<<<< This opens a transferfiûnction that can be edited

View File

@@ -157,8 +157,8 @@ class MXTuning(Tuning):
(mdl0,'mdl0'),
),w)
d={'num':num.coeffs,'num1':num1.coeffs,'num2':num2.coeffs,'numc':numc.coeffs,
'den':den.coeffs,'den1':den1.coeffs,'den2':den2.coeffs,'denc':denc.coeffs}
d={'num':num.coeffs,'num1':num1.coeffs,'num2':num2.coeffs,'numc':numc.coeffs,'num0':num0.coeffs,'numd':numd.coeffs,
'den':den.coeffs,'den1':den1.coeffs,'den2':den2.coeffs,'denc':denc.coeffs,'den0':den0.coeffs,'dend':dend.coeffs}
fn=os.path.join(self.baseDir,'model%d.mat'%mot)
import scipy.io
scipy.io.savemat(fn, mdict=d)
@@ -256,8 +256,8 @@ class MXTuning(Tuning):
),w)
d={'num':num.coeffs,'num1':num1.coeffs,'num2':num2.coeffs,'num3':num3.coeffs,'num4':num4.coeffs,'num5':num5.coeffs,'numc':numc.coeffs,
'den':den.coeffs,'den1':den1.coeffs,'den2':den2.coeffs,'den3':den3.coeffs,'den4':den4.coeffs,'den5':den5.coeffs,'denc':denc.coeffs}
d={'num':num.coeffs,'num1':num1.coeffs,'num2':num2.coeffs,'num3':num3.coeffs,'num4':num4.coeffs,'num5':num5.coeffs,'numc':numc.coeffs,'num0':num0.coeffs,'numd':numd.coeffs,
'den':den.coeffs,'den1':den1.coeffs,'den2':den2.coeffs,'den3':den3.coeffs,'den4':den4.coeffs,'den5':den5.coeffs,'denc':denc.coeffs,'den0':den0.coeffs,'dend':dend.coeffs}
fn=os.path.join(self.baseDir,'model%d.mat'%mot)
import scipy.io
scipy.io.savemat(fn, mdict=d)