Python : 用matplotlib做游標卡尺模擬
這是我碩士論文要用到的模擬
廢話不多說就直接來了吧
下面是我寫的程式碼
程式碼解釋我哪天有空再來補
存起來的mp4檔在這裡
我這邊是用主尺39 副尺20(即是一般游標卡尺的規格)來做測試影片
紅色的線是對齊的時候
對齊到主尺的副尺刻度線
好了,今天的筆記到此結束
希望有幫助未來遺忘這些的自己,以及需要的人
廢話不多說就直接來了吧
下面是我寫的程式碼
程式碼解釋我哪天有空再來補
''' matplotlib_animation_sample.py This is a 1-D vernier scale simmulation. Before reading codes below, there're some concepts you need to know: 1.accuracy: the accuracy of the vernier is calculate by the formula: abs(round(main_steps/vernier_steps)-main_steps/vernier_steps) means the difference between main_steps/vernier_steps and its closest integer <ex> if main_staps = 39, vernier_steps = 20 the accuracy of the vernier is 4-39/29 = 1/20 = 0.05 mm 2.steps and gap: in vernier scale mechanism "vernier_steps * vernier_gap = main_steps * main_gap" vernier_steps: how many steps between all vernier scale lines main_steps: how many steps between all main scale lines vernier_gap: how many pixels between two vernier scale lines main_gap: how many pixels between two main scale lines in general cases main_gap = 1mm = 1*mm_unit main_steps = the length of the vernier scale (in mm) ''' import sys import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation import math import time #define key parameters if len(sys.argv)==1: # default main_steps = 39 # total 39 steps between all lines in main scale vernier_steps = 20 # total 20 steps between all lines in vernier scale elif len(sys.argv)==2: main_steps = int(sys.argv[1]) vernier_steps = 20 else: main_steps = int(sys.argv[1]) vernier_steps = int(sys.argv[2]) mm_unit = 1000 # 1 mm contains 1000 pixels main_gap = mm_unit # main scale's accuracy is 1mm #parameters follow by key parameters and other global variables vernier_gap = int(main_steps*main_gap/vernier_steps) # design to be int line_height = 5 frame_size = main_steps*main_gap #use vernier length as the frame_size x0 = 0 vernier_pos = 0 vernier_accuracy = 0 vernier_accuracy_dig = 0 #prepare plotting objects fig = plt.figure() ax1 = fig.add_subplot(2,1,1) ax2 = fig.add_subplot(2,1,2) def drawMainScale(plt_pos,frame_size): global x0 ydata = [0,line_height] line_list = [] x0 = int(math.floor(plt_pos)) for x in range(x0,x0+frame_size+1): xdata = [x, x] #start and end pt have same x ln, = ax1.plot(xdata,ydata) ln.set_color('black') line_list.append(ln) return line_list def drawVernierScale(frame_size): ydata = [0,line_height] line_list = [] for x in range(0,frame_size+1): xdata = [x, x] #both start and end pt are in same x ln, = ax2.plot(xdata,ydata) ln.set_color('black') line_list.append(ln) return line_list def drawMatch(pos): vernier_match = pos #print('vernier_match:', vernier_match) dots = 100 xdata = [vernier_match]*dots ydata = np.linspace(0,line_height,dots,endpoint=True) ln, = ax2.plot(xdata,ydata,'rs') return ln def init(): global frame_size,vernier_steps,vernier_accuracy,vernier_accuracy_dig if main_steps%vernier_steps==0: print('your vernier scale is useless') quit() vernier_accuracy = abs(round(main_steps/vernier_steps)-main_steps/vernier_steps) vernier_accuracy_copy = vernier_accuracy while True: vernier_accuracy_copy = vernier_accuracy_copy*10 vernier_accuracy_dig += 1 if vernier_accuracy_copy >=1: break print('vernier_accuracy_dig:',vernier_accuracy_dig) ax1.set_xlim(0, main_steps) ax1.set_ylim(0, 6) ax2.set_xlim(0, vernier_steps) ax2.set_ylim(0, 6) line_list = drawVernierScale(vernier_steps) return line_list def update(i): #i is an int from 0 to frames-1, and keep looping ax1.clear() #avoid memory-leak ax2.clear() ax1.set_xlim(0, main_steps) ax1.set_ylim(0, 6) ax2.set_xlim(0, vernier_steps) ax2.set_ylim(0, 6) global x0, vernier_pos plt_pos = round(i/main_gap,2) ax1.set_xlim(plt_pos, plt_pos + main_steps) line_list = drawVernierScale(vernier_steps) line_list.extend(drawMainScale(plt_pos, main_steps)) match = 0 for x in range(x0,x0+main_steps): if (main_gap*x-i)%vernier_gap==0 : n = (main_gap*x-i)/vernier_gap #frame is moving, so -i is needed if n==0: #x0 is the range at main scale that align by vernier zero vernier_pos = x0 else: #align pos - distance between align pos and vernier zero vernier_pos = x -n*vernier_gap/mm_unit line_list.append(drawMatch(n)) print('i:',i,'x0:',x0,'x:',x,'n:',n,'main_gap*x-i:',main_gap*x-i,'n*vernier_gap/mm_unit',n*vernier_gap/mm_unit,'vernier_pos',vernier_pos) match += 1 analog_pos = i/mm_unit vernier_pos_str = str(round(vernier_pos,vernier_accuracy_dig)) vernier_accuracy_str = str(round(vernier_accuracy,vernier_accuracy_dig)) if match>1: ax1.set_title('analog pos: %.3f (mm)\nvernier pos: N/A (match=%d)' %(analog_pos,match)) else: ax1.set_title('analog pos: %.3f (mm)\nvernier pos:%s (mm)\naccuracy:%s (mm)'\ %(analog_pos,vernier_pos_str,vernier_accuracy_str)) return line_list def main(): ani = FuncAnimation(fig, update, frames = 200000, interval = 20, init_func=init, blit=False) #ani.save('animation.mp4', writer='ffmpeg', fps=30) plt.show() if __name__ == '__main__': main()
存起來的mp4檔在這裡
我這邊是用主尺39 副尺20(即是一般游標卡尺的規格)來做測試影片
紅色的線是對齊的時候
對齊到主尺的副尺刻度線
希望有幫助未來遺忘這些的自己,以及需要的人
留言
張貼留言