diff --git a/python/PBMotionAnalyzer/PBMotionAnalyzer.py b/python/PBMotionAnalyzer/PBMotionAnalyzer.py index 2b1a61f..c34a8bf 100755 --- a/python/PBMotionAnalyzer/PBMotionAnalyzer.py +++ b/python/PBMotionAnalyzer/PBMotionAnalyzer.py @@ -71,44 +71,8 @@ class AboutFrame(wx.Frame): print(k,'=',v) class MAMainFrame(wx.Frame): - - def OpenFile(self,fn_npz): - doc=self.doc - try: - doc.fh=fh=np.load(fn_npz) - except IOError as e: - sys.stderr.write('Unable to open File: '+fn_npz+'\n') - else: - pass - s='content of numpy file: '+fn_npz+'\n' - for k,v in fh.iteritems(): - s+=' '+k+': '+str(v.dtype)+' '+str(v.shape)+'\n' - self.wxTxt.SetLabel(s) - - lenRec=fh['rec'].shape[0] - lenPts=fh['pts'].shape[0] - self.wxTimeCtrl.slider.SetRange(0,lenRec-1) - - ts=fh['meta'].item()['timebase'] - page=int((lenRec-1000/ts)/(lenPts+2)) - self.wxTimeCtrl.slider.SetPageSize(page) - - self.xPosCtrl.slider.SetRange(0,lenPts-1) - -#self.wxTimeCtrl.slider.SetPageSize(100) - #self.wxTree.ShowHirarchy(self.fid) - - def CloseFile(self): - #http://docs.wxwidgets.org/2.8/wx_windowdeletionoverview.html#windowdeletionoverview - #print 'CloseFile' - try: - self.fh.close() - del self.fh - except AttributeError as e: - pass - def __init__(self, parent, title,doc): - wx.Frame.__init__(self, parent, title=title, size=wx.Size(650, 200),style = wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP) + wx.Frame.__init__(self, parent, title=title, size=wx.Size(650, 230),style = wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP) self.doc=doc;doc.view.append(self) imgDir=ut.Path.GetImage() icon = wx.Icon(os.path.join(imgDir,'PBMA.ico'), wx.BITMAP_TYPE_ICO) @@ -130,9 +94,12 @@ class MAMainFrame(wx.Frame): wxTimeCtrl=ut.SliderGroup(self, label='DataPoint', range=(0, 1000)) wxTimeCtrl.SetCallback(MAMainFrame.OnSetTime, wxTimeCtrl) sizer.Add(wxTimeCtrl.sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5) #wxSplt.SplitVertically(wxTree, wxTxt) - wxPosCtrl=ut.SliderGroup(self, label='Position', range=(0, 1000)) - wxPosCtrl.SetCallback(MAMainFrame.OnSetPosition, wxPosCtrl) + wxPosCtrl=ut.SliderGroup(self, label='IdxInPos', range=(0, 1000)) + wxPosCtrl.SetCallback(MAMainFrame.OnSetIdxInPos, wxPosCtrl) sizer.Add(wxPosCtrl.sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5) #wxSplt.SplitVertically(wxTree, wxTxt) + wxTrigCtrl=ut.SliderGroup(self, label='IdxTrigger', range=(0, 1000)) + wxTrigCtrl.SetCallback(MAMainFrame.OnSetIdxTrigger, wxTrigCtrl) + sizer.Add(wxTrigCtrl.sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5) #wxSplt.SplitVertically(wxTree, wxTxt) #wxSplt.SetMinimumPaneSize(320) #wxLstCtrl=HdfAttrListCtrl(wxSplt) #wxSplt.SplitVertically(wxTree, wxLstCtrl) @@ -140,7 +107,8 @@ class MAMainFrame(wx.Frame): self.Centre() self.wxTimeCtrl=wxTimeCtrl - self.xPosCtrl=wxPosCtrl + self.wxPosCtrl=wxPosCtrl + self.wxTrigCtrl=wxTrigCtrl self.wxTxt=wxTxt #self.wxTree=wxTree #self.display=wxTxt @@ -148,6 +116,63 @@ class MAMainFrame(wx.Frame): def __del__(self): self.CloseFile() + def OpenFile(self,fn_npz): + doc=self.doc + try: + doc.fh=fh=np.load(fn_npz) + except IOError as e: + sys.stderr.write('Unable to open File: '+fn_npz+'\n') + else: + pass + s='content of numpy file: '+fn_npz+'\n' + for k,v in fh.iteritems(): + s+=' '+k+': '+str(v.dtype)+' '+str(v.shape)+'\n' + self.wxTxt.SetLabel(s) + + rec=fh['rec'] + pts=fh['pts'] + lenRec=rec.shape[0] + lenPts=pts.shape[0] + #idxTrigger=np.hstack(([0],rec[:,4])) + #doc.idxTrigger=idxTrigger=np.where(np.diff(idxTrigger)==1)[0] + idxTrigger=rec[:,4] + doc.idxTrigger=idxTrigger=np.where(np.diff(idxTrigger)==1)[0]+1 + idxInPos=[] #first point at idx 0 + try:# find approximate distance of 2 points + rng =idxTrigger[2]-idxTrigger[1] + except IndexError: + rng = int(lenRec / lenPts) + idx=rng/2 + + for i in range(lenPts): + l=rec[idx:idx+rng,(3,2)]-pts[i,:] + l2=l[:,0]**2+l[:,1]**2 + ofs=l2.argmin() + print(l2[ofs]) + idx+=ofs + idxInPos.append(idx) + idx+=rng/2 + + doc.idxInPos=idxInPos=np.array(idxInPos) + #jitter=idxInPos-idxTrigger[:idxInPos.shape[0]] + self.wxTimeCtrl.slider.SetRange(0,lenRec-1) + + ts=fh['meta'].item()['timebase'] + page=idxInPos[1]-idxInPos[0] + self.wxTimeCtrl.slider.SetPageSize(page) + + self.wxPosCtrl.slider.SetRange(0,lenPts-1) + self.wxTrigCtrl.slider.SetRange(0,idxTrigger.shape[0]-1) + + def CloseFile(self): + #http://docs.wxwidgets.org/2.8/wx_windowdeletionoverview.html#windowdeletionoverview + #print 'CloseFile' + try: + self.fh.close() + del self.fh + except AttributeError as e: + pass + def OnOpen(self, event): dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), '','numpy files (*.npz;*.npy)|*.npz;*.npy|all (*.*)|*.*', wx.OPEN|wx.FD_CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: @@ -264,36 +289,39 @@ rec @staticmethod def OnSetTime(usrData, value, msg): 'called when the time slider has been changed' - print('OnSetTime', usrData, value, msg) + #print('OnSetTime', usrData, value, msg) view=usrData.slider.Parent doc=view.doc + idx=np.argmin(abs(doc.idxInPos-value)) + view.wxPosCtrl.SetValue(idx) + idx=np.argmin(abs(doc.idxTrigger-value)) + view.wxTrigCtrl.SetValue(idx) doc.Update(view,0,value) - # imgFrm=usrData.slider.Parent - # imgFrm.img.set_array(imgFrm.data[usrData.value,...]) - # data=imgFrm.data - # sl=ut.GetSlice(imgFrm.idxXY,data.shape,imgFrm.wxAxCtrlLst) - - # try: - # tomoNorm=imgFrm.tomoNorm - # except AttributeError: - # imgFrm.canvas.img.set_array(data[sl]) - # else: - # data=data[sl]*tomoNorm - # imgFrm.canvas.img.set_array(data) - - # if imgFrm.mnItemShowMoment.IsChecked(): - # imgFrm.PlotMoments() - # imgFrm.canvas.draw() - pass - @staticmethod - def OnSetPosition(usrData, value, msg): - 'called when the time slider has been changed' - print('OnSetPosition', usrData, value, msg) + def OnSetIdxInPos(usrData, value, msg): + 'called when the idxInPos slider has been changed' + #print('OnSetPosIdx', usrData, value, msg) view = usrData.slider.Parent doc = view.doc - doc.Update(view, 1, value) + value=doc.idxInPos[value] + view.wxTimeCtrl.SetValue(value) + idx=np.argmin(abs(doc.idxTrigger-value)) + view.wxTrigCtrl.SetValue(idx) + doc.Update(view, 0, value) + + @staticmethod + def OnSetIdxTrigger(usrData, value, msg): + 'called when the idxTrigger slider has been changed' + #print('OnSetIdxTrigger', usrData, value, msg) + view = usrData.slider.Parent + doc = view.doc + value=doc.idxTrigger[value] + view.wxTimeCtrl.SetValue(value) + idx=np.argmin(abs(doc.idxInPos-value)) + view.wxPosCtrl.SetValue(idx) + doc.Update(view, 0, value) + if __name__ == '__main__': def GetArgs(): diff --git a/python/shapepath.py b/python/shapepath.py index 1ab3365..f755f4f 100755 --- a/python/shapepath.py +++ b/python/shapepath.py @@ -390,6 +390,8 @@ class ShapePath(MotionBase): except AttributeError as e: print('plot_gather(): '+str(e)+': no data acquired yet') return + ts=meta['timebase'] + t=np.arange(rec.shape[0],dtype=np.uint32) if mode&1: fig=plt.figure('trajectory') ax = fig.add_subplot(1,1,1) @@ -414,10 +416,10 @@ class ShapePath(MotionBase): err=np.sqrt(errx**2+erry**2) hl = [] - hl += ax.plot(errx, 'b-',label='x-error') - hl += ax.plot(erry, 'g-',label='y-error') - hl += ax.plot(err, 'r-',label='error') - ax.xaxis.set_label_text('datapoint (timebase: %g ms per data point)'%meta['timebase']) + hl += ax.plot(t,errx,'b-',label='x-error') + hl += ax.plot(t,erry,'g-',label='y-error') + hl += ax.plot(t,err, 'r-',label='error') + ax.xaxis.set_label_text('ms (timebase: %g ms per data point)'%ts) ax.yaxis.set_label_text('pos-error um') legend = ax.legend(loc='upper right', shadow=True) print('average error x %g um, y %g um, %g um'%(np.abs(errx).mean(),np.abs(erry).mean(),err.mean())) @@ -426,6 +428,39 @@ class ShapePath(MotionBase): self.bode_plot(xy=(3,1),mode=31,db=True) # FX self.bode_plot(xy=(2,0),mode=31,db=True) # FY + if mode&8: + lenRec = rec.shape[0] + lenPts = pts.shape[0] + # idxTrigger=np.hstack(([0],rec[:,4])) + # doc.idxTrigger=idxTrigger=np.where(np.diff(idxTrigger)==1)[0] + idxTrigger = rec[:, 4] + idxTrigger = np.where(np.diff(idxTrigger) == 1)[0] + 1 + idxInPos = [] # first point at idx 0 + try: # find approximate distance of 2 points + rng = idxTrigger[2] - idxTrigger[1] + except IndexError: + rng = int(lenRec / lenPts) + idx = rng / 2 + + for i in range(lenPts): + l = rec[idx:idx + rng, (3, 2)] - pts[i, :] + l2 = l[:, 0] ** 2 + l[:, 1] ** 2 + ofs = l2.argmin() + print(l2[ofs]) + idx += ofs + idxInPos.append(idx) + idx += rng / 2 + + idxInPos = np.array(idxInPos) + jitter=idxInPos-idxTrigger[:idxInPos.shape[0]] + fig = plt.figure('trigger jitter') + ax = fig.add_subplot(1, 1, 1) + hl = [] + hl += ax.plot(jitter*ts, 'b-',label='jitter') + ax.xaxis.set_label_text('position idx') + ax.yaxis.set_label_text('jitter (ms)') + + plt.show() def bode_plot(self,xy=(0,1),mode=25,db=True): @@ -593,11 +628,12 @@ if __name__=='__main__': #sp.gen_grid_points(w=2,h=2,pitch=50,rnd=.2);sp.sort_points(xy);sp.setup_motion(fnPrg=fn+'.prg',mode=1,pt2pt_time=10,acq_per=1) #sp.gen_swissmx_points(width=1000,ofs=(-500,0));sp.setup_motion(fnPrg=fn+'.prg',mode=1,pt2pt_time=40,acq_per=1) - sp.gen_grid_points(w=30,h=30,pitch=50,rnd=.2);sp.sort_points(xy);sp.setup_motion(fnPrg=fn+'.prg',mode=1,pt2pt_time=40) + #sp.gen_grid_points(w=30,h=30,pitch=50,rnd=.2);sp.sort_points(xy);sp.setup_motion(fnPrg=fn+'.prg',mode=1,pt2pt_time=40) #sp.gen_grid_points(w=200,h=200,pitch=50,rnd=.2);sp.sort_points(xy);sp.setup_motion(fnPrg=fn+'.prg',mode=1,pt2pt_time=40) #sp.gen_grid_points(w=2,h=20,pitch=50,rnd=0);sp.setup_motion(fnPrg=fn+'.prg',mode=1,pt2pt_time=10,acq_per=1) #sp.gen_rand_points(n=500, scale=1000);sp.sort_points(xy);sp.setup_motion(fnPrg=fn+'.prg',mode=1,pt2pt_time=10,acq_per=1) + sp.gen_grid_points(w=20,h=20,pitch=10,rnd=0);sp.sort_points(xy);sp.setup_motion(fnPrg=fn+'.prg',mode=1,pt2pt_time=40) #>>>setup gather and sync<<<