# 均勻帶電圓環的電場 > 作者:王一哲 > 日期:2019/12/1 <br /> ## 前言 這是一個選修物理上第6章靜電學的題目,但是題目只會問圓心處或是圓心上一段距離處的電場,因為這些位置才能利用對稱性計算電場量值,如果想計算其它位置的電場該怎麼辦?由於我們在 VPython 教學〈[靜電力及簡諧](https://hackmd.io/@yizhewang/SJHKW2SzX?type=view#%E7%A8%8B%E5%BC%8F-19-3)〉程式 19-3 已經寫過類似的東西,應該可以從這支程式開始修改。 <br /> ## 用 VPython 計算空間中各處的電場 [GlowScript 版本](https://www.glowscript.org/#/user/yizhe/folder/Public/program/ChragedCircleVPython) ```python= from vpython import * """ 1. 參數設定, 設定變數及初始值 """ Q, R, N = 2E-11, 1, 100 # 帶電圓環總電量, 半徑, 分割數量 q, r = Q/N, 0.01*R # 分割後小球電量, 半徑 L = 4.1*R # 畫面寬度 ke = 8.988E9 # 靜電力常數 num = 100 # 將顯示的空間每邊切成 N 等份 """ 2. 產生帶電球體類別, 回傳帶電球體產生的電場 """ class Ball: def __init__(self, pos, radius, color, charge): self.pos = pos self.radius = radius self.color = color self.charge = charge self.ball = sphere(pos=self.pos, radius=self.radius, charge=self.charge, color=self.color) def electric(self, pos2): return ke*self.charge / mag2(pos2-self.pos) * norm(pos2-self.pos) """ 3. 畫面設定 """ # 產生動畫視窗 scene = canvas(title="Electric Field (Circle)", width=600, height=600, x=0, y=0, background=color.black, center=vec(0, 0, 0), range=L) # 產生帶電圓環上計算電場用的小球 balls = [Ball(pos=vec(R*cos(i*2*pi/N), R*sin(i*2*pi/N), 0), radius=r, color=color.white, charge=q) for i in range(N)] # 計算畫箭頭的位置 locations = [] # 直線, 儲存資料後用 plot 繪圖 ''' for i in range(num+1): locations.append(vec(L/num*i - L/2, 0, 0)) ''' # 平面, 儲存資料後用 streamplot 繪圖 for i in range(num+1): for j in range(num+1): locations.append(vec(L/num*i - L/2, L/num*j - L/2, 0)) # 立體, 展示用, 但是箭頭太多, 不容易看清楚 ''' for i in range(num+1): for j in range(num+1): for k in range(num+1): locations.append(vec(L/num*i - L/2, L/num*j - L/2, L/num*k - L/2)) ''' # 依序讀取串列 locations 的元素, 在對應的位置產生箭頭 fields = [arrow(pos=location, axis=vec(0, 0, 0), color=color.green) for location in locations] with open("ElectricFieldCircleData.csv", "w", encoding="UTF-8") as file: file.write("x, y, E, Ex, Ey\n") # 更新箭頭的長度及方向, 記錄電場強度最大值, 量值接近最大值偏紅色, 量值接近 0 偏綠色 fmax = 0 for field in fields: for ball in balls: field.axis += ball.electric(field.pos) with open("ElectricFieldCircleData.csv", "a", encoding="UTF-8") as file: file.write(str(field.pos.x) + "," + str(field.pos.y) + "," + str(field.axis.mag) + "," + str(field.axis.x) + "," + str(field.axis.y) + "\n") if(field.axis.mag >= fmax): fmax = field.axis.mag for field in fields: field.color = vec(field.axis.mag/fmax, 1 - field.axis.mag/fmax, 0) ``` <br /> 在這支程式中,我試著用箭頭畫出各處的電場量值及方向,可以產生3種資料: 1. 1維:沿著x軸方向各點的電場,使用第40、41行程式碼,並將第44 ~ 53行改為註解。 2. 2維:xy平面各點的電場,使用第44 ~ 46行程式碼,並將第40、41行及第50 ~ 53行改為註解。 3. 3維:空間中各點的電場,使用第50 ~ 53行程式碼,並將第40 ~ 46行改為註解。 當箭頭數量較少時,會缺少某些位置的電場;但是當箭頭數量較多時,畫面會太雜亂,幾乎看不出任何東西。因此,我決定只用這支程式產生資料,將資料存成文字檔案,再用另一支程式繪圖。 <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/zPz5ZWv.png"> <div style="text-align:center">空間中各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/zUWbWLZ.png"> <div style="text-align:center">xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/8Fvttgy.png"> <div style="text-align:center">x軸上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/eWr6qKj.png"> <div style="text-align:center">xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R,但箭頭數量太多</div> <br /> ## 用streamplot繪製xy平面上各點的電場 ```python= import numpy as np import matplotlib.pyplot as plt x, y, E0, Ex, Ey = np.loadtxt("ElectricFieldCircleData.csv", delimiter=',', usecols=(0, 1, 2, 3, 4), unpack=True, encoding="UTF-8", skiprows=1) num = 101 x = x.reshape(num, num)[:, 0] y = y.reshape(num, num)[0, :] E0 = E0.reshape(num, num).transpose() Ex = Ex.reshape(num, num).transpose() Ey = Ey.reshape(num, num).transpose() # 限制資料的最大值 E0 = np.clip(E0, 0, 1*np.sqrt(2)) Ex = np.clip(Ex, -1, 1) Ey = np.clip(Ey, -1, 1) # 開啟繪圖視窗 fig = plt.figure(figsize=(8, 6), dpi=100) # 開啟圖片物件 ax = fig.gca() # 設定圖片標題 ax.set_title("Electric Field Around a Charged Circle", fontsize=16) # 設定座標軸標籤 ax.set_xlabel(r"$x \mathrm{(m)}$", fontsize=14) ax.set_ylabel(r"$y \mathrm{(m)}$", fontsize=14) # 用顏色代表每個點的 E0 數值 con = ax.pcolormesh(x, y, E0, shading="gouraud", cmap=plt.cm.coolwarm) # 顯示數值及色階對應方式 fig.colorbar(con, shrink=0.5, aspect=5) # 畫電力線 ax.streamplot(x, y, Ex, Ey, linewidth=1, color='black', density=2, arrowstyle='->', arrowsize=1.5) # 儲存圖片 plt.savefig("ElectricFieldCircle.png") # 顯示圖片 plt.show() ``` <br /> 1. 第4、5行:假設資料存在ElectricFieldCircleData.csv,我先用 **numpy.loadtxt** 將資料讀出來並儲存到x、y、E0、Ex、Ey這5個1維陣列。由於我使用了每一欄的資料,理論上可以省略 usecols=(0, 1, 2, 3, 4)。 2. 第7 ~ 12行:為了符合 **matplotlib.streamplot** 要求的資料格式,需要改變陣列格式。 1. 將x變為2維陣列,再取出每一列第0欄的資料,重新指定給x並變成1維陣列。如果沒有修改資料格式,執行時會出現錯誤訊息 **ValueError: The rows of 'x' must be equal**。 2. 將y變為2維陣列,再取出第0列每一欄的資料,重新指定給y並變成1維陣列。如果沒有修改資料格式,執行時會出現錯誤訊息 **ValueError: The rows of 'x' must be equal**。 3. 將E0、Ex、Ey變為2維陣列並轉置,如果沒有轉置,資料對應的x、y位置會跑掉。 3. 第14 ~ 16行:因為很靠近圓環處的電場量值會特別大,為了看出其它位置的電場強度差異,需要限制資料的最大值。 4. 第19 ~ 36行:用 streamplot 指令繪圖。 <br /> $$ \begin{bmatrix} x_0 y_0 & x_0 y_1 & x_0 y_2 & \dots & x_0 y_N\\ x_1 y_0 & x_1 y_1 & x_1 y_2 & \dots & x_1 y_N\\ \vdots & \vdots & \vdots & & \vdots \\ x_N y_0 & x_N y_1 & x_N y_2 & \dots & x_N y_N\\ \end{bmatrix} $$ <div style="text-align:center">資料轉置前</div> <br /> $$ \begin{bmatrix} x_0 y_0 & x_1 y_0 & x_2 y_0 & \dots & x_N y_0\\ x_0 y_1 & x_1 y_1 & x_2 y_1 & \dots & x_N y_1\\ \vdots & \vdots & \vdots & & \vdots \\ x_0 y_N & x_1 y_N & x_2 y_N & \dots & x_N y_N\\ \end{bmatrix} $$ <div style="text-align:center">資料轉置後</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/jSzAcxO.png"> <div style="text-align:center">xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R,沒有限制資料範圍</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/xsCjBqb.png"> <div style="text-align:center">xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R,有限制資料範圍</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/8IPgKtV.png"> <div style="text-align:center">xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 4.1R,沒有限制資料範圍</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/JL3OrNl.png"> <div style="text-align:center">xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 4.1R,有限制資料範圍</div> <br /> ## 用plot繪製x軸上各點的電場 ```python= import numpy as np import matplotlib.pyplot as plt x, Ex = np.loadtxt("ElectricFieldCircleData.csv", delimiter=',', usecols=(0, 3), unpack=True, encoding="UTF-8", skiprows=1) # Ex - x 關係圖 plt.figure(figsize=(6, 4.5), dpi=100) plt.title('Electric Field Around a Charged Circle', fontsize=16) plt.xlabel(r'$x ~\mathrm{(m)}$', fontsize=14) plt.ylabel(r'$E_x ~\mathrm{(N/C)}$', fontsize=14) plt.xticks(fontsize=12) plt.yticks(fontsize=12) plt.ylim(-4, 4) plt.subplots_adjust(left=0.12, bottom=0.15) plt.grid(color='grey', linestyle='--', linewidth=1) plt.plot(x, Ex, color='blue', marker='o', markersize=5, markeredgecolor='black', linestyle='') plt.savefig("ElectricFieldCircle2R1D.png") plt.show() ``` <br /> 1. 第4、5行:假設資料存在ElectricFieldCircleData.csv,我先用 **numpy.loadtxt** 將第0欄及第3欄的資料讀出來並儲存到x、Ex這兩個1維陣列。 2. 第8 ~ 19行:用 plot 指令繪圖。 3. 第14行:因為很靠近圓環處的電場量值會特別大,為了看出其它位置的電場強度差異,需要限制y軸的繪圖範圍。 <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/LuwKTvh.png"> <div style="text-align:center">x軸上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R</div> <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/yZH0LbA.png"> <div style="text-align:center">x軸上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 4.1R</div> <br /> ## 結語 由於VPython裡內建向量運算功能,對於計算電場相當方便,但是執行時效率較差,如果取的點較多可能需要等幾分鐘。理論上應該可以用numpy ndarray直接計算各點的電場,這樣執行速度會快很多,但是目前做出來的東西有點問題,還需要再嘗試看看。 <br /> ## 參考資料 1. **numpy.loadtxt**:https://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html 2. **matplotlib.streamplot**:https://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html 3. StackOverflow **plot streamlines with matplotlib from file**:https://stackoverflow.com/questions/55207810/plot-streamlines-with-matplotlib-from-file --- ###### tags:`Physics`、`Python`、`VPython`