Last active
January 25, 2023 05:53
-
-
Save mitbailey/e0f2146736c09348eba29290c0b28037 to your computer and use it in GitHub Desktop.
Generates graphs showing capacitor charging curves, the effect of varied resistance, overvoltage, and subsequent charge selection precision with clock frequencies.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import matplotlib.pyplot as plt | |
import numpy as np | |
import math as m | |
def align_yaxis(ax1, v1, ax2, v2): | |
"""adjust ax2 ylimit so that v2 in ax2 is aligned to v1 in ax1""" | |
_, y1 = ax1.transData.transform((0, v1)) | |
_, y2 = ax2.transData.transform((0, v2)) | |
inv = ax2.transData.inverted() | |
_, dy = inv.transform((0, 0)) - inv.transform((0, y1-y2)) | |
miny, maxy = ax2.get_ylim() | |
ax2.set_ylim(miny+dy, maxy+dy) | |
def deflect(voltage): | |
return 0.01894072 * (voltage**2.0683391) | |
def v_from_deflect(deflection): | |
return 6.80525 * (deflection**0.4834797156810505) | |
def deflection(): | |
fig = plt.figure(figsize=(8,8)) | |
ax1 = fig.add_subplot(111) | |
x_s = [0, 25, 50, 75, 100, 125, 150, 175, 200] | |
y_s = [0, 14.37, 62.83, 145.33, 264.12, 416.40, 602.47, 819.12, 1056.06] | |
x = np.linspace(0, 200, 200) | |
y = [deflect(x_v) for x_v in x] | |
ax1.scatter(x_s, y_s, label='Measured') | |
ax1.plot(x, y, label='Best-Fit') | |
fig.suptitle('DM 25CW015-028 Volt Deflection') | |
ax1.set_title('Single Actuator Deflection at Voltage, Measured and Best-Fit') | |
ax1.axes.set_ylabel('Deflection (nm)') | |
ax1.axes.set_xlabel('Voltage (V)') | |
ax1.legend(loc='center right', bbox_to_anchor=(1,0.35)) | |
fig.savefig('deflection.png', dpi=500) | |
def c_curve(C, TARGET_V, clk, PRECISION): | |
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(16,8), sharey=True) | |
# fig = plt.figure(figsize=(8,8)) | |
# ax1 = fig.add_subplot(112) | |
ax_b = ax[0].twinx() | |
TARGET_dV = (TARGET_V) / PRECISION | |
ax_b.axhline(TARGET_dV, c='k', linestyle=(0,(1,1)), label='Target \u0394Vmax') | |
ax_b.axhline(TARGET_dV * 2, c='k', linestyle=(0,(1,2))) | |
ax_b.axhline(TARGET_dV * 4, c='k', linestyle=(0,(1,4))) | |
ax_b.axhline(TARGET_dV * 8, c='k', linestyle=(0,(1,8))) | |
V = 150 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax_b.plot(x[:-1], dy, c='tab:blue', linestyle='dashed', label='\u0394V / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax[0].plot(x, y, c='tab:blue', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
for i, v in enumerate(y): | |
if v > v_from_deflect(300): | |
dv = dy[i] | |
break | |
ax_b.axhline(dv, linestyle='dashdot', c='orange', label='1/2 Full Deflection (%.4f \u0394V / Clock Cycle)'%(dv)) | |
ax[1].plot([deflect(y_v) for y_v in y], y, c='tab:orange', label='DM 25CW015-028 Deflection (nm)') | |
ax[1].set_title('DM 25CW015-028 Deflection') | |
ax[1].axes.set_ylabel('Charge Proxy (V) [Solid]') | |
ax[1].axes.set_xlabel('Actuator Deflection (nm)') | |
ax[1].axvline(300, c='r', label='1/2 Full Deflection (300 nm)') | |
ax[1].axhline(v_from_deflect(300), c='r', label='1/2 Full Deflection (%.4f V)'%(v_from_deflect(300))) | |
ax[0].axhline(v_from_deflect(300), c='r', label='1/2 Full Deflection (%.4f V)'%(v_from_deflect(300))) | |
ax[1].legend() | |
fig.suptitle('Capacitor Charging Curves (500.1nF, %.2f kHz, Target \u0394Vmax < %.4f V)'%(clk/1000, TARGET_dV)) | |
ax[0].set_title('Standard Capacitor Charging Curve') | |
ax[0].axes.set_ylabel('Charge Proxy (V) [Solid]') | |
ax_b.axes.set_ylabel('\u0394Charge Proxy (V) [Dashed, Dotted]') | |
ax[0].axes.set_xlabel('Time (s)') | |
ax[0].axhline(TARGET_V, c='k', label='%.0f V'%(TARGET_V)) | |
ax[0].legend(loc='center right', bbox_to_anchor=(1,0.35), prop={'size': 8}) | |
ax_b.legend(loc='center right', prop={'size': 8}) | |
ax_b.set_ylim([0,TARGET_dV*16]) | |
align_yaxis(ax[0], 0, ax_b, 0) | |
fig.savefig('c_curve.png', dpi=500) | |
def c_curve_r(C, TARGET_V, clk, PRECISION): | |
fig = plt.figure(figsize=(15,11)) | |
ax1 = fig.add_subplot(111) | |
ax2 = ax1.twinx() | |
TARGET_dV = (C * TARGET_V) / PRECISION | |
ax2.axhline(TARGET_dV, c='k', linestyle='dotted', label='Target \u0394Qmax') | |
ax2.axhline(TARGET_dV * 2, c='k', linestyle='dashed', label='Target \u0394Qmax * 2') | |
V = 150 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:blue', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:blue', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
V = 150 | |
R = 23750*2 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:red', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:red', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
V = 150 | |
R = 23750*4 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:green', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:green', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
V = 150 | |
R = 23750*8 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:olive', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:olive', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
fig.suptitle('Capacitor Charging Curves (500.1nF, %.2f kHz, Target \u0394Qmax < %e Coulombs)'%(clk/1000, TARGET_dV)) | |
ax1.set_title('Effects of Increasing Resistance, All Else Equal') | |
ax1.axes.set_ylabel('Charge (Coulombs) [Solid]') | |
ax2.axes.set_ylabel('\u0394Charge (Coulombs) [Dashed]') | |
ax1.axes.set_xlabel('Time (s)') | |
ax1.axhline(C*TARGET_V, c='k', label='%.0f V'%(TARGET_V)) | |
ax1.legend(loc='center right', bbox_to_anchor=(1,0.35)) | |
ax2.legend(loc='center right') | |
ax2.set_ylim([0,TARGET_dV*16]) | |
align_yaxis(ax1, 0, ax2, 0) | |
fig.savefig('c_curve_r.png', dpi=500) | |
def c_curve_v(C, TARGET_V, clk, PRECISION): | |
fig = plt.figure(figsize=(15,11)) | |
ax1 = fig.add_subplot(111) | |
ax2 = ax1.twinx() | |
TARGET_dV = (C * TARGET_V) / PRECISION | |
ax2.axhline(TARGET_dV, c='k', linestyle='dotted', label='Target \u0394Qmax') | |
ax2.axhline(TARGET_dV * 2, c='k', linestyle='dashed', label='Target \u0394Qmax * 2') | |
V = 150 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:blue', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:blue', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
V = 200 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:red', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:red', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
V = 250 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:green', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:green', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
V = 300 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:olive', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:olive', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
fig.suptitle('Capacitor Charging Curves (500.1nF, %.2f kHz, Target \u0394Qmax < %e Coulombs)'%(clk/1000, TARGET_dV)) | |
ax1.set_title('Effects of Increasing Voltage (Overvoltage), All Else Equal') | |
ax1.axes.set_ylabel('Charge (Coulombs) [Solid]') | |
ax2.axes.set_ylabel('\u0394Charge (Coulombs) [Dashed]') | |
ax1.axes.set_xlabel('Time (s)') | |
ax1.axhline(C*TARGET_V, c='k', label='%.0f V'%(TARGET_V)) | |
ax1.legend(loc='center right', bbox_to_anchor=(1,0.35)) | |
ax2.legend(loc='center right') | |
ax2.set_ylim([0,TARGET_dV*16]) | |
align_yaxis(ax1, 0, ax2, 0) | |
fig.savefig('c_curve_v.png', dpi=500) | |
def c_curve_clk(C, TARGET_V, clk, PRECISION): | |
fig = plt.figure(figsize=(15,11)) | |
ax1 = fig.add_subplot(111) | |
ax2 = ax1.twinx() | |
TARGET_dV = (C * TARGET_V) / PRECISION | |
ax2.axhline(TARGET_dV, c='k', linestyle='dotted', label='Target \u0394Qmax') | |
ax2.axhline(TARGET_dV * 2, c='k', linestyle='dashed', label='Target \u0394Qmax * 2') | |
V = 150 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:blue', linestyle='dashed', label='\u0394Q / Clock Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='purple', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
clk *= 10 | |
V = 150 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:red', linestyle='dashed', label='\u0394Q / Clock Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='purple', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
clk *= 2 | |
V = 150 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:green', linestyle='dashed', label='\u0394Q / Clock Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='purple', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
clk *= 2 | |
V = 150 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:olive', linestyle='dashed', label='\u0394Q / Clock Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='purple', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
fig.suptitle('Capacitor Charging Curves (500.1nF, %d V, %d Ohms Target \u0394Qmax < %e Coulombs)'%(V, R, TARGET_dV)) | |
ax1.set_title('Effects of Increasing Clock Speed, All Else Equal') | |
ax1.axes.set_ylabel('Charge (Coulombs) [Solid]') | |
ax2.axes.set_ylabel('\u0394Charge (Coulombs) [Dashed]') | |
ax1.axes.set_xlabel('Time (s)') | |
ax1.axhline(C*TARGET_V, c='k', label='%.0f V'%(TARGET_V)) | |
ax1.legend(loc='center right', bbox_to_anchor=(1,0.35)) | |
ax2.legend(loc='center right') | |
ax2.set_ylim([0,TARGET_dV*16]) | |
align_yaxis(ax1, 0, ax2, 0) | |
fig.savefig('c_curve_clk.png', dpi=500) | |
def c_curve_r_v(C, TARGET_V, clk, PRECISION): | |
fig = plt.figure(figsize=(15,11)) | |
ax1 = fig.add_subplot(111) | |
ax2 = ax1.twinx() | |
TARGET_dV = (C * TARGET_V) / PRECISION | |
ax2.axhline(TARGET_dV, c='k', linestyle='dotted', label='Target \u0394Qmax') | |
ax2.axhline(TARGET_dV * 2, c='k', linestyle='dashed', label='Target \u0394Qmax * 2') | |
V = 150 | |
R = 23750 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:blue', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:blue', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
V = 200 | |
R = 36000 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:red', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:red', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
V = 250 | |
R = 55000 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:green', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:green', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
V = 300 | |
R = 71000 | |
Q = C*V | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:olive', linestyle='dashed', label='\u0394Q / Clock Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:olive', label='%.0f V, %.0f kOhm, \u0394Qmax = %e'%(V, R/1000, dy[0])) | |
fig.suptitle('Capacitor Charging Curves (500.1nF, %.2f kHz, Target \u0394Qmax < %e Coulombs)'%(clk/1000, TARGET_dV)) | |
ax1.set_title('Effects of Increasing Resistance and Voltage') | |
ax1.axes.set_ylabel('Charge (Coulombs) [Solid]') | |
ax2.axes.set_ylabel('\u0394Charge (Coulombs) [Dashed]') | |
ax1.axes.set_xlabel('Time (s)') | |
ax1.axhline(C*TARGET_V, c='k', label='%.0f V'%(TARGET_V)) | |
ax1.legend(loc='center right', bbox_to_anchor=(1,0.35)) | |
ax2.legend(loc='center right') | |
ax2.set_ylim([0,TARGET_dV*16]) | |
align_yaxis(ax1, 0, ax2, 0) | |
fig.savefig('c_curve_r_v.png', dpi=500) | |
def c_curve_v_r_applied(C, TARGET_V, clk, PRECISION): | |
fig = plt.figure(figsize=(15,11)) | |
ax1 = fig.add_subplot(111) | |
ax2 = ax1.twinx() | |
TARGET_dV = (TARGET_V) / PRECISION | |
ax2.axhline(TARGET_dV, c='k', linestyle=(0,(1,4)), label='Target \u0394Vmax') | |
ax2.axhline(TARGET_dV * 2, c='k', linestyle=(0,(1,8))) | |
ax2.axhline(TARGET_dV * 4, c='k', linestyle=(0,(1,16))) | |
ax2.axhline(TARGET_dV * 8, c='k', linestyle=(0,(1,32))) | |
# Graphed Curve | |
V = 150 | |
R = 23750 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
MAX_Y_VAL = y[-1] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:blue', linestyle='dashed', label='\u0394V / Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:blue', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f'%(V, R/1000, dy[0])) | |
# Graphed Curve | |
V = 160 | |
R = 45000 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - m.e**(-time / (R*C)))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
y = [val for val in y if val <= MAX_Y_VAL] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:red', linestyle='dashed', label='\u0394V / Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:red', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f'%(V, R/1000, dy[0])) | |
# Graphed Curve | |
V = 185 | |
R = 72000 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - m.e**(-time / (R*C)))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
y = [val for val in y if val <= MAX_Y_VAL] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:green', linestyle='dashed', label='\u0394V / Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:green', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f'%(V, R/1000, dy[0])) | |
# Graphed Curve | |
V = 400 | |
R = 257000 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - m.e**(-time / (R*C)))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
y = [val for val in y if val <= MAX_Y_VAL] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:olive', linestyle='dashed', label='\u0394V / Cycle') | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:olive', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f'%(V, R/1000, dy[0])) | |
fig.suptitle('Capacitor Charging Curves (500.1nF, Target \u0394Vmax < %.4f V)'%(TARGET_dV)) | |
ax1.set_title('Applied Use of Overvoltage and Resistance to Achieve Higher Temporal Resolution') | |
ax1.axes.set_ylabel('Charge Proxy (V) [Solid]') | |
ax2.axes.set_ylabel('\u0394Charge Proxy (V) [Dashed, Dotted]') | |
ax1.axes.set_xlabel('Time (s)') | |
ax1.axhline(TARGET_V, c='k', label='%.0f V'%(TARGET_V)) | |
ax1.legend(loc='center right', bbox_to_anchor=(1,0.35)) | |
ax2.legend(loc='center right') | |
ax2.set_ylim([0,TARGET_dV*16]) | |
align_yaxis(ax1, 0, ax2, 0) | |
fig.savefig('c_curve_v_r_applied.png', dpi=500) | |
def c_curve_v_r_clk_applied(C, TARGET_V, clk, PRECISION): | |
fig = plt.figure(figsize=(15,11)) | |
ax1 = fig.add_subplot(111) | |
ax2 = ax1.twinx() | |
TARGET_dV = (TARGET_V) / PRECISION | |
ax2.axhline(TARGET_dV, c='k', linestyle=(0,(1,4)), label='Target \u0394Vmax') | |
ax2.axhline(TARGET_dV * 2, c='k', linestyle=(0,(1,8))) | |
ax2.axhline(TARGET_dV * 4, c='k', linestyle=(0,(1,16))) | |
ax2.axhline(TARGET_dV * 8, c='k', linestyle=(0,(1,32))) | |
# Graphed Curve | |
V = 150 | |
R = 23750 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
MAX_Y_VAL = y[-1] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:blue', linestyle='dashed', label='\u0394V / Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:blue', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
# for i, v in enumerate(y): | |
# if v > v_from_deflect(300): | |
# dv = dy[i] | |
# dv_minx = x[i]/x[-1] | |
# break | |
# ax2.axhline(dv, xmin=dv_minx, linestyle=(0, (5, 10, 1, 5, 1, 5, 1, 10)), c='tab:blue', label='1/2 Full Deflection (%.4f \u0394V / Clock Cycle)'%(dv)) | |
# Graphed Curve | |
clk *= 10 | |
V = 160 | |
R = 45000 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - m.e**(-time / (R*C)))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
y = [val for val in y if val <= MAX_Y_VAL] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:red', linestyle='dashed', label='\u0394V / Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:red', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
# for i, v in enumerate(y): | |
# if v > v_from_deflect(300): | |
# dv = dy[i] | |
# dv_minx = x[i]/x[-1] | |
# break | |
# ax2.axhline(dv, xmin=dv_minx, linestyle=(0, (5, 10, 1, 5, 1, 5, 1, 10)), c='tab:red', label='1/2 Full Deflection (%.4f \u0394V / Clock Cycle)'%(dv)) | |
# Graphed Curve | |
clk *= 2 | |
V = 185 | |
R = 72000 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - m.e**(-time / (R*C)))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
y = [val for val in y if val <= MAX_Y_VAL] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:green', linestyle='dashed', label='\u0394V / Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:green', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
# for i, v in enumerate(y): | |
# if v > v_from_deflect(300): | |
# dv = dy[i] | |
# dv_minx = x[i]/x[-1] | |
# break | |
# ax2.axhline(dv, xmin=dv_minx, linestyle=(0, (5, 10, 1, 5, 1, 5, 1, 10)), c='tab:green', label='1/2 Full Deflection (%.4f \u0394V / Clock Cycle)'%(dv)) | |
# Graphed Curve | |
clk *= 2 | |
V = 400 | |
R = 257000 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - m.e**(-time / (R*C)))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
y = [val for val in y if val <= MAX_Y_VAL] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:olive', linestyle='dashed', label='\u0394V / Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:olive', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
# for i, v in enumerate(y): | |
# if v > v_from_deflect(300): | |
# dv = dy[i] | |
# dv_minx = x[i]/x[-1] | |
# break | |
# ax2.axhline(dv, xmin=dv_minx, linestyle=(0, (5, 10, 1, 5, 1, 5, 1, 10)), c='tab:olive', label='1/2 Full Deflection (%.4f \u0394V / Clock Cycle)'%(dv)) | |
fig.suptitle('Capacitor Charging Curves (500.1nF, Target \u0394Vmax < %.4f V)'%(TARGET_dV)) | |
ax1.set_title('Applied Use of Overvoltage, Resistance, and Clock Speeds to Achieve Higher Temporal Resolution') | |
ax1.axes.set_ylabel('Charge Proxy (V) [Solid]') | |
ax2.axes.set_ylabel('\u0394Charge Proxy (V) [Dashed]') | |
ax1.axes.set_xlabel('Time (s)') | |
ax1.axhline(TARGET_V, c='k', label='%.0f V'%(TARGET_V)) | |
ax1.axhline(v_from_deflect(600*0.75), c='tab:purple', label='75%% Deflection (%.4f V)'%(v_from_deflect(600*0.75))) | |
ax1.axhline(v_from_deflect(600*0.5), c='tab:pink', label='50%% Deflection (%.4f V)'%(v_from_deflect(600*0.5))) | |
ax1.axhline(v_from_deflect(600*0.25), c='thistle', label='25%% Deflection (%.4f V)'%(v_from_deflect(600*0.25))) | |
ax1.legend(loc='center right', bbox_to_anchor=(1,0.25)) | |
ax2.legend(loc='center right', bbox_to_anchor=(1,0.5)) | |
plt.xlim([0,x[-1]]) | |
ax2.set_ylim([0,TARGET_dV*16]) | |
align_yaxis(ax1, 0, ax2, 0) | |
fig.savefig('c_curve_v_r_clk_applied.png', dpi=500) | |
def c_curve_loose_rc(C, TARGET_V, clk, PRECISION, RC5): | |
fig = plt.figure(figsize=(15,11)) | |
ax1 = fig.add_subplot(111) | |
ax2 = ax1.twinx() | |
TARGET_dV = (TARGET_V) / PRECISION | |
ax2.axhline(TARGET_dV, c='k', linestyle=(0,(1,2)), label='Target \u0394Vmax') | |
ax2.axhline(TARGET_dV * 2, c='k', linestyle=(0,(1,8)), label='2x Target \u0394Vmax') | |
# Graphed Curve | |
V = 150 | |
R = 200000*2*RC5 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
MAX_X_VAL = x[-1] | |
MAX_Y_VAL = y[-1] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:blue', linestyle='dashed', label='\u0394V / Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:blue', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
# for i, v in enumerate(y): | |
# if v > v_from_deflect(300): | |
# dv = dy[i] | |
# dv_minx = x[i]/x[-1] | |
# break | |
# ax2.axhline(dv, xmin=dv_minx, linestyle=(0, (5, 10, 1, 5, 1, 5, 1, 10)), c='tab:blue', label='1/2 Full Deflection (%.4f \u0394V / Clock Cycle)'%(dv)) | |
# Graphed Curve | |
# clk *= 10 | |
V = 160 | |
R = 375000*2*RC5 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - m.e**(-time / (R*C)))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
y = [val for val in y if val <= MAX_Y_VAL] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:red', linestyle='dashed', label='\u0394V / Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:red', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
# for i, v in enumerate(y): | |
# if v > v_from_deflect(300): | |
# dv = dy[i] | |
# dv_minx = x[i]/x[-1] | |
# break | |
# ax2.axhline(dv, xmin=dv_minx, linestyle=(0, (5, 10, 1, 5, 1, 5, 1, 10)), c='tab:red', label='1/2 Full Deflection (%.4f \u0394V / Clock Cycle)'%(dv)) | |
# Graphed Curve | |
# clk *= 2 | |
V = 185 | |
R = 612000*2*RC5 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - m.e**(-time / (R*C)))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
y = [val for val in y if val <= MAX_Y_VAL] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:green', linestyle='dashed', label='\u0394V / Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:green', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
# for i, v in enumerate(y): | |
# if v > v_from_deflect(300): | |
# dv = dy[i] | |
# dv_minx = x[i]/x[-1] | |
# break | |
# ax2.axhline(dv, xmin=dv_minx, linestyle=(0, (5, 10, 1, 5, 1, 5, 1, 10)), c='tab:green', label='1/2 Full Deflection (%.4f \u0394V / Clock Cycle)'%(dv)) | |
# Graphed Curve | |
# clk *= 2 | |
V = 200 | |
R = 732500*2*RC5 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - m.e**(-time / (R*C)))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
y = [val for val in y if val <= MAX_Y_VAL] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax2.plot(x[:-1], dy, c='tab:olive', linestyle='dashed', label='\u0394V / Cycle, %.0f Hz'%(clk)) | |
np.sort(dy)[::-1] | |
ax1.plot(x, y, c='tab:olive', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
# for i, v in enumerate(y): | |
# if v > v_from_deflect(300): | |
# dv = dy[i] | |
# dv_minx = x[i]/x[-1] | |
# break | |
# ax2.axhline(dv, xmin=dv_minx, linestyle=(0, (5, 10, 1, 5, 1, 5, 1, 10)), c='tab:olive', label='1/2 Full Deflection (%.4f \u0394V / Clock Cycle)'%(dv)) | |
fig.suptitle('Capacitor Charging Curves (500.1nF, %.2f kHz, Target \u0394Vmax < %.4f V)'%(clk/1000, TARGET_dV)) | |
ax1.set_title('Applied Use of Overvoltage, Resistance, and Longer RC Time to Achieve Higher Temporal Resolution') | |
ax1.axes.set_ylabel('Charge Proxy (V) [Solid]') | |
ax2.axes.set_ylabel('\u0394Charge Proxy (V) [Dashed, Dotted]') | |
ax1.axes.set_xlabel('Time (s)') | |
ax1.axhline(TARGET_V, c='k', label='%.0f V'%(TARGET_V)) | |
ax1.axhline(v_from_deflect(600*0.75), c='tab:purple', label='75%% Deflection (%.4f V)'%(v_from_deflect(600*0.75))) | |
ax1.axhline(v_from_deflect(600*0.5), c='tab:pink', label='50%% Deflection (%.4f V)'%(v_from_deflect(600*0.5))) | |
ax1.axhline(v_from_deflect(600*0.25), c='thistle', label='25%% Deflection (%.4f V)'%(v_from_deflect(600*0.25))) | |
ax1.legend(loc='center right', bbox_to_anchor=(1,0.25)) | |
ax2.legend(loc='center right', bbox_to_anchor=(1,0.5)) | |
plt.xlim([0,MAX_X_VAL]) | |
ax2.set_ylim([0,TARGET_dV*4]) | |
align_yaxis(ax1, 0, ax2, 0) | |
fig.savefig('c_curve_loose_rc_%.2f.png'%(RC5), dpi=500) | |
def c_curve_asic(C, TARGET_V, clk, PRECISION, RC5): | |
fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(14,14)) | |
TARGET_dV = (TARGET_V) / PRECISION | |
ax[0, 1].axvline(TARGET_dV, c='k', linestyle=(0,(1,2)), label='\u0394V$_{max}$ (%.4f)'%(TARGET_dV)) | |
ax[1, 1].axhline(600/PRECISION, c='k', linestyle=(0,(1,2)), label='\u0394nm$_{max}$ (%.4f)'%(600/PRECISION)) | |
# Graphed Curve | |
V = 150 | |
R = 20000*20*RC5 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - (m.e**(-time / (R*C))))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
MAX_X_VAL = x[-1] | |
MAX_Y_VAL = y[-1] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax[0, 1].plot(dy, y[:-1], c='tab:blue', linestyle='dashed', label='\u0394V / Cycle, %.0f kHz'%(clk/1000)) | |
np.sort(dy)[::-1] | |
ax[0, 0].plot(x, y, c='tab:blue', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
ny = [] | |
for i, t in enumerate(x): | |
ny.append(deflect(y[i])) | |
ax[1, 0].plot(x, ny, c='tab:blue', label='') | |
dny = np.diff(ny) | |
ax[1, 1].plot(x[:-1], dny, c='tab:blue', linestyle='dashed', label='\u0394V / Cycle, %.0f kHz'%(clk/1000)) | |
V = 185 | |
R = 61250*20*RC5 | |
Q = C*V | |
x = [] | |
y = [] | |
x = np.linspace(0, R*C*5, int(clk*R*C*5)) | |
y = [(C * V * (1 - m.e**(-time / (R*C)))) for time in x] | |
y_tv = (C * TARGET_V * (1 - (m.e**(-R*C*5 / (R*C))))) # Charge at TARGET_V voltage, aka max charge. | |
y = [(y_v / y_tv) * TARGET_V for y_v in y] | |
y = [val for val in y if val <= MAX_Y_VAL] | |
x = x[:len(y)] | |
dy = np.diff(y) | |
ax[0, 1].plot(dy, y[:-1], c='tab:red', linestyle='dashed', label='\u0394V / Cycle, %.0f kHz'%(clk/1000)) | |
np.sort(dy)[::-1] | |
ax[0, 0].plot(x, y, c='tab:red', linestyle='solid', label='%.0f V, %.0f kOhm, \u0394Vmax = %.4f V'%(V, R/1000, dy[0])) | |
ny = [] | |
for i, t in enumerate(x): | |
ny.append(deflect(y[i])) | |
ax[1, 0].plot(x, ny, c='tab:red', label='') | |
dny = np.diff(ny) | |
ax[1, 1].plot(x[:-1], dny, c='tab:red', linestyle='dashed', label='\u0394V / Cycle, %.0f kHz'%(clk/1000)) | |
fig.suptitle('Capacitor Charging Curves (500.1nF, %.2f MHz, Target \u0394Vmax < %.4f V)'%(clk/1000000, TARGET_dV)) | |
ax[0, 0].set_title('Charge vs Time') | |
ax[0, 0].axes.set_xlabel('Time (s)') | |
ax[0, 0].axes.set_ylabel('Charge Proxy (V)') | |
ax[0, 0].legend() | |
ax[0, 1].set_title('Change in Charge per Period vs Voltage') | |
ax[0, 1].axes.set_xlabel('Voltage (V)') | |
ax[0, 1].axes.set_ylabel('Change in Charge Proxy (\u0394V)') | |
ax[0, 1].legend() | |
ax[1, 0].set_title('DM Actuator Displacement vs Time') | |
ax[1, 0].axes.set_xlabel('Time (s)') | |
ax[1, 0].axes.set_ylabel('Displacement (nm)') | |
ax[1, 0].legend() | |
ax[1, 1].set_title('Change in DM Actuator Displacement per Period vs Time') | |
ax[1, 1].axes.set_xlabel('Time (s)') | |
ax[1, 1].axes.set_ylabel('Change in Displacement (\u0394nm)') | |
ax[1, 1].legend() | |
fig.savefig('c_curve_asic.png', dpi=500) | |
if __name__ == '__main__': | |
C = 500.1 * 1e-9 | |
TARGET_V = 150 | |
clk = 50000 # Hz | |
PRECISION = 2**14 | |
# deflection() | |
# c_curve(C, TARGET_V, clk, PRECISION) | |
# c_curve_r(C, TARGET_V, clk, PRECISION) | |
# c_curve_v(C, TARGET_V, clk, PRECISION) | |
# # c_curve_r_v(C, TARGET_V, clk, PRECISION) | |
# c_curve_clk(C, TARGET_V, clk, PRECISION) | |
# c_curve_v_r_applied(C, TARGET_V, clk, PRECISION) | |
# c_curve_v_r_clk_applied(C, TARGET_V, clk, PRECISION) | |
# c_curve_loose_rc(C, TARGET_V, clk, PRECISION, 0.06) | |
# c_curve_loose_rc(C, TARGET_V, clk, PRECISION, 0.2) | |
# c_curve_loose_rc(C, TARGET_V, clk, PRECISION, 0.5) | |
# c_curve_loose_rc(C, TARGET_V, clk, PRECISION, 1) | |
# c_curve_loose_rc(C, TARGET_V, clk, PRECISION, 2) | |
c_curve_asic(C, TARGET_V, 1000 * 1000, PRECISION, 0.06) | |
plt.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment