Try   HackMD

均勻帶電圓環的電場

作者:王一哲
日期:2019/12/1


前言

這是一個選修物理上第6章靜電學的題目,但是題目只會問圓心處或是圓心上一段距離處的電場,因為這些位置才能利用對稱性計算電場量值,如果想計算其它位置的電場該怎麼辦?由於我們在 VPython 教學〈靜電力及簡諧〉程式 19-3 已經寫過類似的東西,應該可以從這支程式開始修改。

用 VPython 計算空間中各處的電場

GlowScript 版本

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)

在這支程式中,我試著用箭頭畫出各處的電場量值及方向,可以產生3種資料:

  1. 1維:沿著x軸方向各點的電場,使用第40、41行程式碼,並將第44 ~ 53行改為註解。
  2. 2維:xy平面各點的電場,使用第44 ~ 46行程式碼,並將第40、41行及第50 ~ 53行改為註解。
  3. 3維:空間中各點的電場,使用第50 ~ 53行程式碼,並將第40 ~ 46行改為註解。

當箭頭數量較少時,會缺少某些位置的電場;但是當箭頭數量較多時,畫面會太雜亂,幾乎看不出任何東西。因此,我決定只用這支程式產生資料,將資料存成文字檔案,再用另一支程式繪圖。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
空間中各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
x軸上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R,但箭頭數量太多

用streamplot繪製xy平面上各點的電場

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()

  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 指令繪圖。

[x0y0x0y1x0y2x0yNx1y0x1y1x1y2x1yNxNy0xNy1xNy2xNyN]

資料轉置前

[x0y0x1y0x2y0xNy0x0y1x1y1x2y1xNy1x0yNx1yNx2yNxNyN]

資料轉置後

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R,沒有限制資料範圍

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R,有限制資料範圍

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 4.1R,沒有限制資料範圍

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
xy平面上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 4.1R,有限制資料範圍

用plot繪製x軸上各點的電場

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()

  1. 第4、5行:假設資料存在ElectricFieldCircleData.csv,我先用 numpy.loadtxt 將第0欄及第3欄的資料讀出來並儲存到x、Ex這兩個1維陣列。
  2. 第8 ~ 19行:用 plot 指令繪圖。
  3. 第14行:因為很靠近圓環處的電場量值會特別大,為了看出其它位置的電場強度差異,需要限制y軸的繪圖範圍。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
x軸上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 2.1R

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
x軸上各點電場示意圖,圓環半徑 R = 1,畫面寬度 L = 4.1R

結語

由於VPython裡內建向量運算功能,對於計算電場相當方便,但是執行時效率較差,如果取的點較多可能需要等幾分鐘。理論上應該可以用numpy ndarray直接計算各點的電場,這樣執行速度會快很多,但是目前做出來的東西有點問題,還需要再嘗試看看。

參考資料

  1. numpy.loadtxthttps://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html
  2. matplotlib.streamplothttps://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html
  3. StackOverflow plot streamlines with matplotlib from filehttps://stackoverflow.com/questions/55207810/plot-streamlines-with-matplotlib-from-file

tags:PhysicsPythonVPython