Lab 2: Electric Field

Course: PHYS 217-503

Created Date: 20 February 2022

In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

pd.options.display.float_format = '{:,.10f}'.format
pd.options.display.max_columns = 100
plt.style.use('seaborn-darkgrid')

# General Markdown Formatting Functions
from IPython.display import Markdown, display, HTML

def printmd(string: str, level: int=1):
    '''Display Markdown text with a default header value of 1.'''
    header_level = '#'*level + ' '
    display(Markdown(header_level + string))

Theory

Electric Field Vector $$ \vec{E} = \langle - \frac{\delta V_x}{\delta x} , - \frac{\delta V_y}{\delta y} \rangle $$

Magnitude of Electric Field $$ \| \vec{E} \| = \sqrt{ \left(- \frac{\delta V_x}{\delta x} \right)^2 + \left(- \frac{\delta V_y}{\delta y} \right)^2 }$$

ElectricFieldScan Class

In [2]:
from dataclasses import dataclass, field

@dataclass
class ElectricFieldScan:
    '''The ElectricFieldScan class is created to store the data and computation of each scan trial.'''
    name: str
    description: str
    step_size: float # [m]
    voltage_scan: np.ndarray # Shape -> (x, y)
    e_x: np.ndarray = field(init=False) # Shape -> (x - 1, y - 1)
    e_y: np.ndarray = field(init=False) # Shape -> (x - 1, y - 1)
    e_magnitude: np.ndarray = field(init=False) # Shape -> (x - 1, y - 1)

    def __post_init__(self):
        shape = self.voltage_scan.shape # x, y
        m, n = np.subtract(shape, (1,1)) # x - 1, y - 1

        # Electric field components are found using the following steps:
        #   1. The difference between two consecutive components is found, causing the matrix to have one less row (x.diff) or one less column (y.diff)
        #   2. As the matrices will be of different sizes, they will be sliced to size m*n aka (x - 1)*(y - 1)
        #   3. The matrices are divided by the difference between steps, which is simply the step size
        #   4. It is multiplied by -1
        #   5. The resulting vectors have the units [V/m]
        self.e_x = -1 * np.diff(self.voltage_scan, axis=0)[:m, :n] / self.step_size
        self.e_y = -1 * np.diff(self.voltage_scan, axis=1)[:m, :n] / self.step_size
        self.e_magnitude = (self.e_x**2 + self.e_y**2)**.5

        
In [3]:
# Create an instance of the `ElectricFieldScan` class for each experiment configuration.
scans = (
    ElectricFieldScan(
        name='Configuration A',
        description='Sharp Point and Bar',
        step_size=0.008,
        voltage_scan=np.loadtxt('./Data/scan_output_1.csv', delimiter=',')
    ),
    ElectricFieldScan(
        name='Configuration B',
        description='Round Edge and Bar',
        step_size=0.008,
        voltage_scan=np.loadtxt('./Data/scan_output_2.csv', delimiter=',')
    ),
    ElectricFieldScan(
        name='Configuration C',
        description='Radial Capacitor',
        step_size=0.008,
        voltage_scan=np.loadtxt('./Data/scan_output_3.csv', delimiter=',')
    ),
    ElectricFieldScan(
        name='Configuration D',
        description='Circular Conductor',
        step_size=0.008,
        voltage_scan=np.loadtxt('./Data/scan_output_4.csv', delimiter=',')
    )
)

General Vector Plotting Function

In order to observe the direction and magnitude of the electric field in each trial, the data is plotted using the matplotlib.quiver method.

In [15]:
from vector_plotter import scale_data

def plot_vector_field(scan: ElectricFieldScan, is_scaled:bool, show: bool=True):
    if is_scaled:
            electric_field_x, electric_field_y, electric_field_magnitude = scale_data(scan.e_x, scan.e_y)
    else:
        electric_field_x, electric_field_y, electric_field_magnitude = scan.e_x, scan.e_y, scan.e_magnitude

    fig, ax = plt.subplots()
    fig.set_dpi(300)
    q = ax.quiver(
        electric_field_y,
        electric_field_x,  
        electric_field_magnitude, 
        pivot='mid',
        # units='xy',
        cmap='viridis',
        edgecolor='white',
        linewidth=0.5
        )

    ax.invert_yaxis()
    ax.set_xlabel("CNC Y-axis (steps)")
    ax.set_ylabel("CNC X-axis (steps)")
    ax.set_title(f"Vector Field of {scan.description}")

    cbar = plt.colorbar(q)
    cbar.set_label('Vector magnitude', rotation=90)

    if show:
        # plt.show()
        plt.savefig('output.png', transparent=True)


for scan in scans:
    plot_vector_field(scan, True)

Final Plots

In order to more clearly visualize the electric potential and electric field in each trial, the data is plotted using the matplotlib.imshow function. With the help of guassian blurring, this leads to a very clear visualization of the behavior of these invisible fields. This is placed next to a plot with no blurring to show the actual values recorded at each point.

In [17]:
# Loop through each configuration.
for scan in scans:
    printmd(scan.name,2)
    
    # Iterate through Electric Potential and Electric Field.
    for value_field, label, unit in zip([scan.voltage_scan , scan.e_magnitude], ['Electric Potential', 'Electric Field'], ['V', 'V/m']):
        
        printmd(label, 3)

        # Find max and its index.
        max_val = np.amax(value_field)
        max_id = np.unravel_index(np.argmax(value_field), value_field.shape)

        # Create the figure and gives it a title.
        fig, axs = plt.subplots(1, 2)
        fig.suptitle(f"Max is {max_val:.0f} {unit} at {max_id}", fontsize=14, va='bottom')
        
        # Plot the exact value_field.
        hm1 = axs[0].imshow(value_field, cmap='viridis', origin='lower')
        axs[0].set_title('Exact')
        
        # Plot the blurred value_field.
        axs[1].imshow(value_field, cmap='viridis', interpolation='gaussian', origin='lower')
        axs[1].set_title('Gaussian')
        
        # Create the colorbar.
        c = plt.colorbar(hm1, ax=axs, location='bottom')
        c.set_label(f"{label} ({unit})")

        plt.show()
    
    # Run the vector_plotter.py program and display the plot it produces.
    plot_vector_field(scan, True, show=False)
    plt.show()

Configuration A

Electric Potential

Electric Field

Configuration B

Electric Potential

Electric Field

Configuration C

Electric Potential

Electric Field

Configuration D

Electric Potential

Electric Field