From 5a05b7355e27a74d374aa107ec6d06ef8a1429fa Mon Sep 17 00:00:00 2001 From: Thierry Zamofing Date: Tue, 12 Feb 2019 16:52:55 +0100 Subject: [PATCH] wip --- MXfastStageDoc/MXfastStage.tex | 107 +++++++++++++--- MXfastStageDoc/Scratch.tex | 5 + cfg/MX1_setup.cfg | 7 +- matlab/StateSpaceControlDesign.m | 14 ++- matlab/documentFunctions.m | 20 +-- matlab/observer.slx | Bin 35134 -> 35281 bytes python/MXTuning.py | 201 ++++++++++++++++++++++++++++--- python/shapepath.py | 6 +- 8 files changed, 306 insertions(+), 54 deletions(-) diff --git a/MXfastStageDoc/MXfastStage.tex b/MXfastStageDoc/MXfastStage.tex index 7738626..684123b 100644 --- a/MXfastStageDoc/MXfastStage.tex +++ b/MXfastStageDoc/MXfastStage.tex @@ -194,12 +194,34 @@ $\rightarrow$ The closed loop response becomes bad above 20Hz (motor 1 ca. -10\% \FloatBarrier \subsubsection{Friction} -\begin{tcolorbox}[width=15cm,colback=red!5!white,colframe=red!75!black,colbacktitle=red!50,coltitle=black,title=TODO] -Record the friction (=current) at a slow move from +lim to -lim.\\ -Analyse the friction depending on the positions and motion directions.\\ -Do the records and analysis at different speeds. -\end{tcolorbox} +To measure the friction, the stage is moved at slow speed from ++lim to -lim. The current is proportional to the force. +Additionally the friction is measured depending on the stage positions and motion directions. This is measured at different speed to see if at these velocities the viscose friction is visible. +\begin{figure}[h!] +\includegraphics[scale=.45]{../python/MXTuning/19_01_29/img/friction10.eps} +\includegraphics[scale=.45]{../python/MXTuning/19_01_29/img/friction11.eps} +\caption{position dependant friction of motor 1} +\label{fig:mot1_frict} +\end{figure} + +\begin{figure}[h!] +\includegraphics[scale=.45]{../python/MXTuning/19_01_29/img/friction20.eps} +\includegraphics[scale=.45]{../python/MXTuning/19_01_29/img/friction21.eps} +\caption{position dependant friction of motor 2} +\label{fig:mot2_frict} +\end{figure} + +Data recording is done with: \verb|./MXTuning.py --dir MXTuning/19_01_29 --mode 16|.\\ +The function parameters are: \verb|pMin=-10000, pMax=10000, speed=(5,10,20,30,60), cnt=2, period=10|. +The recorded data moves from -10000um to 10000um at speed of 5 to 60 mm/s.\\ + +Avg current forward: 111.7 Avg current backward: -105.3\\ +Avg current forward: 95.3 Avg current backward: -130.7\\ + +These values should be used for the $K_{fff}$ parameter of the Servo loop:\\ + +Motor 1,2: $K_{fff}\approx100$\\ \FloatBarrier \subsubsection{using advanced Deltatau Servo Loop} @@ -311,8 +333,7 @@ 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}.\\ -\begin{tcolorbox}[colback=red!5!white,colframe=red!75!black,colbacktitle=red!50,coltitle=black,title=TODO] -A further test will be to 'remove' the current loop. This can be done by setting:$IiGain=0, IpfGain=1, IpbGain=-1$. +A further test is to 'turn of' the current loop. This can be done by setting:$IiGain=0, IpfGain=1, IpbGain=-1$. The resulting transfer function is: \[ \frac{Ipf} @@ -323,8 +344,16 @@ The resulting transfer function is: {\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. -\end{tcolorbox} +This is a $PT_1$ element with a time constant of $\frac{L}{R}=\frac{2.4mH}{8.8\Omega}=0.27ms$. Figures \ref{fig:curr_ol} shows a current step of 3000 \verb|curr_bit| resulting in a current of about 150 \verb|curr_bit|. The rise time matches roughly. So the cable resistance has not a major impact. + +\begin{figure}[h!] +\centering +\includegraphics[scale=.25]{../python/MXTuning/19_01_29/img/curr_step_ol_10.eps} +\includegraphics[scale=.25]{../python/MXTuning/19_01_29/img/curr_step_ol_20.eps} +\caption{voltage step (current open loop)} +\label{fig:curr_ol} +\end{figure} + \subsection{Mechanical model} @@ -610,8 +639,9 @@ Following code calculates parameters for a observer controller, does a simulatio \begin{verbatim} clear;clear global;close all; mot=identifyFxFyStage(7); +sscType=0 for k =1:2 - [ssc]=StateSpaceControlDesign(mot{k});sim('observer'); + [ssc]=StateSpaceControlDesign(mot{k},sscType);sim('observer'); f=figure(); h=plot(desPos_actPos.Time,desPos_actPos.Data,'g'); set(h(1),'color','b'); set(h(2),'color',[0 0.5 0]); print(f,sprintf('figures/sim_cl_observer_%d',mot{k}.id),'-depsc'); @@ -629,10 +659,10 @@ end \begin{figure}[h!] \center -\includegraphics[scale=.45]{../matlab/figures/sim_cl_obs_0_1.eps} -\includegraphics[scale=.45]{../matlab/figures/sim_cl_obs_bode0_1.eps}\\ -\includegraphics[scale=.45]{../matlab/figures/sim_cl_obs_0_2.eps} -\includegraphics[scale=.45]{../matlab/figures/sim_cl_obs_bode0_2.eps} +\includegraphics[scale=.45]{../matlab/figures/sim_cl_observer_1.eps} +\includegraphics[scale=.45]{../matlab/figures/sim_cl_observer_bode1.eps}\\ +\includegraphics[scale=.45]{../matlab/figures/sim_cl_observer_2.eps} +\includegraphics[scale=.45]{../matlab/figures/sim_cl_observer_bode2.eps} \caption{Observer sim: Motor 1 Motor 2} \label{fig:mot_observer_sim} \end{figure} @@ -673,11 +703,56 @@ Finally the real time servo code is compliled for the DeltaTau with:\\ \verb|/epics_ioc_modules/ESB_MX/python/usr_code$ make|\\ -Following lines in gpasciiCommander will activate the user servo loop code: +Following lines in gpasciiCommander will activate the user servo loop code. +\vspace{1pc} -\begin{tcolorbox}[width=15cm,colback=red!5!white,colframe=red!75!black,colbacktitle=red!50,coltitle=black,title=TODO] +Here the full process: + +\begin{tcolorbox}[width=15cm,colback=yellow!5!white,colframe=yellow!75!black,colbacktitle=yellow!50,coltitle=black,title=MATLAB] +\begin{verbatim} +clear;clear global;close all; +mot=identifyFxFyStage(7); +sscType=0; +for k =1:2 + [ssc]=StateSpaceControlDesign(mot{k},sscType); +end +\end{verbatim} \end{tcolorbox} +\begin{tcolorbox}[width=15cm,colback=yellow!5!white,colframe=yellow!75!black,colbacktitle=yellow!50,coltitle=black,title=Shell] +\begin{verbatim} +cd /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python +./MXTuning.py -m512 + +cd /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/usr_code +make + +cd /home/zamofing_t/Documents/prj/SwissFEL/PBTools/pbtools/usr_servo_phase +scp userservo_util userphase_util usrServoSample/usralgo.ko root@SAR-CPPM-EXPMX1:/tmp + + +\end{verbatim} +\end{tcolorbox} + + +\begin{tcolorbox}[width=15cm,colback=yellow!5!white,colframe=yellow!75!black,colbacktitle=yellow!50,coltitle=black,title=DeltaTau Shell] +\begin{verbatim} +root@:/opt/ppmac# +LD_LIBRARY_PATH=/opt/ppmac/libppmac/ /tmp/userservo_util -d 1 +rmmod usralgo +insmod /tmp/usralgo.ko +LD_LIBRARY_PATH=/opt/ppmac/libppmac/ /tmp/userservo_util -l 1 usr_servo_ctrl_2 +LD_LIBRARY_PATH=/opt/ppmac/libppmac/ /tmp/userservo_util -e 1 + +gpascii: +Motor[1].Ctrl =UserAlgo.ServoCtrlAddr[1] +\end{verbatim} +\end{tcolorbox} + + + + + \vspace{1pc} \begin{appendix} diff --git a/MXfastStageDoc/Scratch.tex b/MXfastStageDoc/Scratch.tex index 9111ca6..4de9b08 100644 --- a/MXfastStageDoc/Scratch.tex +++ b/MXfastStageDoc/Scratch.tex @@ -1,6 +1,11 @@ \newpage \section{SCRATCH} +\begin{tcolorbox}[colback=red!5!white,colframe=red!75!black,colbacktitle=red!50,coltitle=black,title=TODO] +Here is still work to do... +\end{tcolorbox} + + \begin{verbatim} clear; clear global; diff --git a/cfg/MX1_setup.cfg b/cfg/MX1_setup.cfg index 6b6105c..2bd5ace 100644 --- a/cfg/MX1_setup.cfg +++ b/cfg/MX1_setup.cfg @@ -49,8 +49,6 @@ !motor(mot=1,dirCur=0,contCur=800,peakCur=2400,timeAtPeak=1,IiGain=5,IpfGain=8,IpbGain=8,JogSpeed=10.,numPhase=3,invDir=True,servo=None,PhasePosSf=1./81250,PhaseFindingDac=100,PhaseFindingTime=50,SlipGain=0,AdvGain=0,PwmSf=10000,FatalFeLimit=200,WarnFeLimit=100,InPosBand=2,homing='enc-index') - - //Stage X Parker MX80L (top stage, mounted on Y stage) //---------------------------------------------------- //Motor[2].pPhaseEnc -> PowerBrick[0].Chan[1].PhaseCapt.a @@ -64,6 +62,11 @@ !motor_servo(mot=2,ctrl='ServoCtrl',Kp=22,Kvfb=350,Ki=0.02,Kvff=240,Kaff=1500,MaxInt=1000) !motor(mot=2,dirCur=0,contCur=800,peakCur=2400,timeAtPeak=1,IiGain=5,IpfGain=8,IpbGain=8,JogSpeed=10.,numPhase=3,invDir=True,servo=None,PhasePosSf=1./81250,PhaseFindingDac=100,PhaseFindingTime=50,SlipGain=0,AdvGain=0,PwmSf=10000,FatalFeLimit=200,WarnFeLimit=100,InPosBand=2,homing='enc-index') +//Tweaks: +//Motor[1].Servo.Kfff=100 +//Motor[2].Servo.Kfff=100 + + //rot stage //--------- diff --git a/matlab/StateSpaceControlDesign.m b/matlab/StateSpaceControlDesign.m index 325b0c5..b7cb4ce 100644 --- a/matlab/StateSpaceControlDesign.m +++ b/matlab/StateSpaceControlDesign.m @@ -41,6 +41,7 @@ function [ssc]=StateSpaceControlDesign(mot,mode) %use_lqr: use lqr instead of pole placement verb=1; use_lqr=0; + MaxDac=2011.968; filt_pos_err=Prefilt(mot,2); %locate poles: 2500rad/s = 397Hz, 6300rad/s = 1027Hz switch mode @@ -214,10 +215,19 @@ function [ssc]=StateSpaceControlDesign(mot,mode) %state space controller ssc=struct(); - for k=["Ts","ss_plt","ss_o","ss_oz","filt_pos_err","filt_pos_err_z","V"] + for k=["Ts","ss_plt","ss_o","ss_oz","filt_pos_err","filt_pos_err_z","V","MaxDac"] ssc=setfield(ssc,k,eval(k)); end - save(sprintf('/tmp/ssc%d.mat',mot.id),'-struct','ssc'); + + mat2py=struct(); + [ozA,ozB,ozC,ozD]=ssdata(ss_oz); + [pos_err_num,pos_err_den]=tfdata(filt_pos_err_z); + for k=["Ts","V","MaxDac","ozA","ozB","ozC","ozD","pos_err_num","pos_err_den"] + mat2py=setfield(mat2py,k,eval(k)); + end + fn=sprintf('/tmp/ssc%d.mat',mot.id); + save(fn,'-struct','mat2py'); + disp(['saved ' fn]); end function pf=Prefilt(mot,mode) diff --git a/matlab/documentFunctions.m b/matlab/documentFunctions.m index afaac54..670656c 100644 --- a/matlab/documentFunctions.m +++ b/matlab/documentFunctions.m @@ -2,7 +2,7 @@ baseDir='/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/matlab/figures'; clear;clear global; -close all;disp('löoad identification data...'); +close all;disp('load identification data...'); mot=identifyFxFyStage(7); close all;disp('simulate stage closed loop...'); @@ -16,21 +16,9 @@ for k =1:2 end close all;disp('simulate observer...'); -for k =1:2 - [ssc]=StateSpaceControlDesign(mot{k});sim('observer'); - f=figure(); h=plot(desPos_actPos.Time,desPos_actPos.Data,'g'); - set(h(1),'color','b'); set(h(2),'color',[0 0.5 0]); - print(f,sprintf('figures/sim_cl_observer_%d',mot{k}.id),'-depsc'); - f=bodeSamples(desPos_actPos); - print(f,sprintf('figures/sim_cl_observer_bode%d',mot{k}.id),'-depsc'); -end -disp('document figure generation done');close all; - - -close all;disp('simulate observer with prefilter...'); -for m =0%0:1 - for k =1:2 - [ssc]=StateSpaceControlDesign(mot{k},m);sim('observer'); +for sscType=0%0:1 + for k=1:2 + [ssc]=StateSpaceControlDesign(mot{k},sscType);sim('observer'); f=figure(); h=plot(desPos_actPos.Time,desPos_actPos.Data,'g'); set(h(1),'color','b'); set(h(2),'color',[0 0.5 0]); print(f,sprintf('figures/sim_cl_obs_%d_%d',m,mot{k}.id),'-depsc'); diff --git a/matlab/observer.slx b/matlab/observer.slx index 69a67642d212d455c8e02d8913e82bb5ee14452e..a199d8bc50115c10e516bff1bbe236e887903022 100644 GIT binary patch delta 13220 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 NXl`isu>X6G{{se1p0EG_ delta 13075 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 transfer function bit 2=4: custom chirp record/plot for DesPos->ActPos transfer function bit 3=8: custom chirp record/plot for various transfer function -bit 4=16: plot the full bode recording -bit 5=32: plot the full bode recording with an approximation model -bit 6=64: plot all raw acquired data files -bit 7=128: custom plots -bit 8=256: generate observer code (after files generated with matlab) +bit 4=16: slow linear move record/plot friction +bit 5=32: plot the full bode recording +bit 6=64: plot the full bode recording with an approximation model +bit 7=128: plot all raw acquired data files +bit 8=256: custom plots +bit 9=512: generate observer code (after files generated with matlab) -> check https://github.com/klauer/ppmac for fast data gathering server which supports phase gathering -> not yet compiling: /home/zamofing_t/Documents/prj/SwissFEL/PowerBrickInspector/ppmac/fast_gather @@ -281,10 +282,10 @@ class MXTuning(Tuning): #[ssc]=StateSpaceControlDesign(mot1); mat=scipy.io.loadmat(fn) motid=int(re.search('(\d)\.mat',fn).group(1)) - A=mat['Aoz'] - B=mat['Boz'] - C=mat['Coz'] - D=mat['Doz'] + A=mat['ozA'] + B=mat['ozB'] + C=mat['ozC'] + D=mat['ozD'] V=mat['V'] u=('DesPos','IqMeas','IqVolts','ActPos') y=('obsvOut',) @@ -348,6 +349,136 @@ class MXTuning(Tuning): EXPORT_SYMBOL(obsvr_servo_ctrl_{motid});'''.format(motid=motid) return (hdr,prog) + def friction(self, motor=1, pMin=-10000, pMax=10000, speed=(5,10,20,30,60), cnt=2, period=10, phase=False, + file='/tmp/gather.npz'): + if os.path.isfile(file): + f=np.load(file) + data=f['data'] + meta=f['meta'].item() + meta['file']=file + else: + gpascii=self.comm.gpascii + gt=self.gather + gt.set_phasemode(phase) + m='Motor[%d].'%motor + address=('ActPos','IqMeas') + address=tuple(map(lambda x: m+x, address)) + gt.set_address(*address) + # gt.set_property(MaxSamples=300000, Period=1) + gt.set_property(Period=period) + + tSrv=gpascii.servo_period + tSrv=2E-4 # seconds + phOsv=gpascii.get_variable('sys.PhaseOverServoPeriod', float) + homePos=gpascii.get_variable('Motor[%d].HomePos'%motor, float) + JogTa=gpascii.get_variable('Motor[%d].JogTa'%motor, float) + gpascii.set_variable('Motor[%d].JogTa'%motor, -5) + + subs={'prgId':999,'mot':motor,'num':100,'phase':'Phase' if phase else '','pMin':pMin,'pMax':pMax} + prog = [''' + &1 + open prog {prgId} + linear abs + jog{mot}={pMin} + dwell 100 + Gather.{phase}Enable=2 + '''.format(**subs),] + + for spd in sorted(speed*cnt): + prog.append(''' + Motor[{mot}].JogSpeed=%d + jog{mot}={pMax} + dwell 0 + jog{mot}={pMin} + dwell 0'''.format(**subs)%spd) + prog.append(''' + dwell 10 + Gather.{phase}Enable=0 + close + &1 + b{prgId}r + '''.format(**subs)) + gpascii.send_block('\n'.join(prog)) + res=gpascii.sync() + res=res.replace(GpasciiChannel.ACK+'\r\n','') + print(res) + t=time.time() + gt.wait_stopped() + print('time %f'%(time.time()-t)) + self.data=data=gt.upload() + gpascii.set_variable('Motor[%d].JogTa'%motor, JogTa) + data[:,0]-=homePos + + meta={'motor':motor,'date':time.asctime(),'ts':tSrv*period if not phase else tSrv*phOsv*period,'address':address} + np.savez_compressed(file, data=data, meta=meta) + meta['file'] = file + ts=meta['ts'] + t=ts*np.arange(data.shape[0]) + fig, ax1 = plt.subplots() + ax2=ax1.twinx() + ax3=ax1.twinx() + ax3.spines["right"].set_position(("axes", 1.12)) + fig.subplots_adjust(right=0.80) + + actPos=data[:,0] + iqMeas=data[:,1] + actVel=np.diff(actPos)/ts/1000. + actVel=np.hstack((actVel, actVel[-1])) + h1,=ax1.plot(t,actPos,'b',label="actPos (um)") + h2,=ax2.plot(t,iqMeas,'g',label="IqMeas (curr_bit)") + h3,=ax3.plot(t,actVel,'r',label="actVel (mm/s)") + ax1.yaxis.label.set_color(h1.get_color()) + ax2.yaxis.label.set_color(h2.get_color()) + ax3.yaxis.label.set_color(h3.get_color()) + ax1.tick_params(axis='y', colors=h1.get_color()) + ax2.tick_params(axis='y', colors=h2.get_color()) + ax3.tick_params(axis='y', colors=h3.get_color()) + + hl=[h1,h2,h3] + ax1.legend(hl, [h.get_label() for h in hl],loc='best') + + sz=100; weights = np.repeat(1.0, sz) / sz + + idx=actVel[:-1]>0 + arg=np.argsort(actPos[idx]) + p1=actPos[idx][arg];c1=iqMeas[idx][arg] + c1 = np.convolve(c1, weights, 'same') + + idx=actVel[:-1]<0 + arg=np.argsort(actPos[idx]) + p2=actPos[idx][arg];c2=iqMeas[idx][arg] + c2 = np.convolve(c2, weights, 'same') + + fig, ax1 = plt.subplots() + hl=[] + hl+=ax1 .plot(actPos,iqMeas,'y-',label='raw') + hl+=ax1 .plot(p1,c1,'g-',label='vel>0') + hl+=ax1 .plot(p2,c2,'r-',label='vel<0') + + #cAll=c1;pAll=p1 + #cAll=cAll-cAll.mean() + #p=np.arange(500,28000,100) #np.arange(500,28000,128) + #c=np.interp(p,pAll,cAll) + #hl+=ax1.plot(p,c,'b.',label='vel<0') + #FfricLut=np.array([p,c]).T + Ffric=np.array([c1.mean(),c2.mean()]) + print 'Avg current forward:',Ffric[0],'Avg current backward:',Ffric[1] + #print 'FfricLut',FfricLut + #print '//positions '+'%g,%g,%g'%tuple(p[0:3]),'...%g,%g,%g'%tuple(p[-3:]) + #print 'float lutCur[%d]={'%len(p) + #for i in range(len(p)): + # print '%g,'%(c[i]), + #print '};' + import scipy.io + #fn='/home/zamofing_t/afs/ESB-MX/data/friction.mat' + #scipy.io.savemat(fn,mdict={'Ffric':Ffric,'FfricLut':FfricLut}) + #print '\n\nuncomment line above to saved to matlab file',fn + + #ax.xaxis.set_label_text(channels[1]) + #ax1.yaxis.set_label_text('current in bits: '+channels[4]) + ax1.legend(loc='best') + plt.show(block=False) + def check_fast_stage(self,file='/tmp/gather.npz'): if os.path.isfile(file): f=np.load(file) @@ -433,6 +564,31 @@ EXPORT_SYMBOL(obsvr_servo_ctrl_{motid});'''.format(motid=motid) scipy.io.savemat(fn, mdict=f) print('save to matlab file:'+fn) + fn=os.path.join(self.baseDir, 'curr_step_ol_%d.npz' % mot) + doSet=not os.path.isfile(fn) + if doSet: + gpascii = self.comm.gpascii + IpfGain=gpascii.get_variable('Motor[%d].IpfGain'%mot,float) + IpbGain=gpascii.get_variable('Motor[%d].IpbGain'%mot,float) + IiGain =gpascii.get_variable('Motor[%d].IiGain' %mot,float) + gpascii.set_variable('Motor[%d].IpfGain'%mot,1) + gpascii.set_variable('Motor[%d].IpbGain'%mot,-1) + gpascii.set_variable('Motor[%d].IiGain' %mot,0) + plt.close('all') + mag=3000 + self.bode_current(motor=mot, magMove=mag, magPhase=500, dwell=10, file=fn) + if doSet: + gpascii = self.comm.gpascii + gpascii.set_variable('Motor[%d].IpfGain'%mot,IpfGain) + gpascii.set_variable('Motor[%d].IpbGain'%mot,IpbGain) + gpascii.set_variable('Motor[%d].IiGain' %mot,IiGain) + self.homed&=~mot + ax,=plt.figure(1).axes + ax.set_ylim(0,200) + ax.set_title('step of 0->3000 with current in open loop') + plt.show(block=False) + save_figs(fn) + if mode&2: motLst = (1, 2) # (2,)# #recType: @@ -508,21 +664,30 @@ EXPORT_SYMBOL(obsvr_servo_ctrl_{motid});'''.format(motid=motid) plt.show(block=False) save_figs(fn) - if mode&16: #plot the full bode recording + if mode&16: #record/plot friction + for mot in (1, 2): + plt.close('all') + fn=os.path.join(self.baseDir, 'friction%d.npz' % mot) + self.init_stage(mot,fn) + self.friction(motor=mot, file=fn); + save_figs(fn) + + + if mode&32: #plot the full bode recording plt.close('all') self.bode_full_plot(mot=1,base=self.baseDir) self.bode_full_plot(mot=2,base=self.baseDir) plt.show(block=False) save_figs(os.path.join(self.baseDir,'bode_full_plot')) - if mode&32: #plot the full bode recording with an approximation model + if mode&64: #plot the full bode recording with an approximation model plt.close('all') self.bode_model_plot(mot=1) self.bode_model_plot(mot=2) plt.show(block=False) save_figs(os.path.join(self.baseDir,'bode_model_plot')) - if mode&64: # plot all raw acquired data files + if mode&128: # plot all raw acquired data files plt.close('all') import glob for fn in glob.glob(os.path.join(self.baseDir,'*.npz')): @@ -541,7 +706,7 @@ EXPORT_SYMBOL(obsvr_servo_ctrl_{motid});'''.format(motid=motid) raw_input('press return') - if mode&128: #custom plots + if mode&256: #custom plots plt.close('all') G1=signal.lti([1/8.8], [2.4E-3/8.8,1]) # num denum print('rise time %e s'%(2.4E-3/8.8)) @@ -588,7 +753,7 @@ EXPORT_SYMBOL(obsvr_servo_ctrl_{motid});'''.format(motid=motid) save_figs(os.path.join(self.baseDir,'iqCmd_TF')) - if mode&256: #generater code + if mode&512: #generater code #before this can be done, the observer controller has to be designed with matlab: #s.a.ESB_MX/matlab/Readme.md #clear; @@ -622,8 +787,10 @@ EXPORT_SYMBOL(obsvr_servo_ctrl_{motid});'''.format(motid=motid) print(fnc+' generated.') print('now compile it looking at PBTools/pbtools/usr_servo_phase/usrServoSample') print('done') - plt.show(block=False) - raw_input('press return') + + if mode&~512: # show and block only if not code generation + plt.show(block=False) + raw_input('press return') def save_figs(fn): @@ -701,7 +868,7 @@ Examples:'''+''.join(map(lambda s:cmd+s, exampleCmd))+'\n ' #plt.ion() #args.host='MOTTEST-CPPM-CRM0573' - args.host=None + #args.host=None if args.host is None: comm=gt=None else: diff --git a/python/shapepath.py b/python/shapepath.py index 2f8146f..aabf3c6 100755 --- a/python/shapepath.py +++ b/python/shapepath.py @@ -323,7 +323,7 @@ class DebugPlot: if mode&8: self.plot_trigger_jitter() - plt.show() + plt.show(block=False) def plot_bode(self,xy=(0,1),mode=25,db=True): '''displays a bode plot of the data @@ -872,6 +872,10 @@ if __name__=='__main__': sp.gather_upload(fnRec=fn+'.npz') dp=DebugPlot(sp);dp.plot_gather(mode=11) + print('done') + plt.show(block=False) + raw_input('press return') + #sp.plot_points(sp.points);plt.show()