-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add extras, add note to fix lum api path
- Loading branch information
1 parent
928c01d
commit 70f7570
Showing
35 changed files
with
3,287 additions
and
1 deletion.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
from scipy.optimize import curve_fit | ||
from matplotlib import pyplot as plt | ||
import numpy as np | ||
|
||
# loads np array, not sweep results | ||
def load_results(): | ||
wavelength = np.load("sweep_data/wavelength.npy") | ||
drop_transmission = np.load("sweep_data/drop_transmission.npy") | ||
thru_transmission = np.load("sweep_data/thru_transmission.npy") | ||
|
||
return wavelength, drop_transmission, thru_transmission | ||
|
||
def plot_tranmission(wavelength, drop_transmission, thru_transmission): | ||
plt.subplot(2, 1, 1) | ||
plt.plot(wavelength, thru_transmission) | ||
plt.ylabel("thru tranmission (dBm)") | ||
|
||
plt.subplot(2, 1, 2) | ||
plt.plot(wavelength, drop_transmission) | ||
plt.xlabel("wavelength (m)") | ||
plt.ylabel("drop tranmission (dBm)") | ||
plt.show() | ||
|
||
def slice_data(x_data, y_data, start_x, end_x): | ||
start_i = None | ||
end_i = None | ||
for i, x in enumerate(x_data): | ||
if start_i is None and x >= start_x: | ||
start_i = i-1 | ||
elif end_i is None and x >= end_x: | ||
end_i = i+1 | ||
break | ||
|
||
return x_data[start_i:end_i], y_data[start_i:end_i] | ||
|
||
def guassian_fit(x_data, y_data, start_x = None, end_x = None): | ||
if start_x != None and end_x != None: | ||
x_data, y_data = slice_data(x_data, y_data, start_x, end_x) | ||
|
||
print(x_data) | ||
print("") | ||
print(y_data) | ||
print("") | ||
# fit doesnt work unless this is done | ||
# this gets reverted at the end of this function | ||
y_data+=40 | ||
|
||
x0 = np.sum(x_data*y_data)/np.sum(y_data) | ||
sigma = np.sqrt(np.abs(np.sum((x_data-x0)**2*y_data)/np.sum(y_data))) | ||
max = y_data.max() | ||
|
||
print("Estimated max: " + str(max)) | ||
print("Estimated x0: " + str(x0)) | ||
print("Estimated sigma: " + str(sigma)) | ||
|
||
def gaus(x_data,max,x0,sigma): | ||
return max*np.exp(-(x_data-x0)**2/(2*sigma**2)) | ||
|
||
popt, pcov = curve_fit(gaus,x_data,y_data,p0=[max,x0,sigma]) | ||
print("Fit max: " + str(popt[0])) | ||
print("Fit x0: " + str(popt[1])) | ||
print("Fit sigma: " + str(popt[2]) + "\n") | ||
|
||
y_data_fit = gaus(x_data,*popt) | ||
y_data_fit -= 40 | ||
y_data -= 40 | ||
return x_data, y_data_fit, popt | ||
|
||
def fit_2_peaks(wavelength, transmission): | ||
start_x_peak1 = 1517e-9 | ||
end_x_peak1 = 1524e-9 | ||
start_x_peak2 = 1525e-9 | ||
end_x_peak2 = 1535e-9 | ||
|
||
#wavelength, transmission = slice_data(wavelength, transmission, start_x_peak1, end_x_peak2) | ||
|
||
# take drop, peak 1: 1515-1525, peak2: 1525-1535 | ||
x_fit_peak1, y_fit_peak1, popt_peak1 = guassian_fit(wavelength, transmission, start_x_peak1, end_x_peak1) | ||
x_fit_peak2, y_fit_peak2, popt_peak2 = guassian_fit(wavelength, transmission, start_x_peak2, end_x_peak2) | ||
|
||
fsr = popt_peak2[1] - popt_peak1[1] | ||
print("FSR: " + str(fsr)) | ||
|
||
plt.plot(wavelength,transmission,'b+:',label='data') | ||
plt.plot(x_fit_peak1,y_fit_peak1,'r-',label='fit1') | ||
plt.plot(x_fit_peak2,y_fit_peak2,'r-',label='fit2') | ||
plt.legend() | ||
plt.xlabel("wavelength (m)") | ||
plt.ylabel("drop tranmission (dBm)") | ||
plt.show() | ||
|
||
def fit_peak(wavelength, transmission): | ||
|
||
# take drop, peak 1: 1515-1525, peak2: 1525-1535 | ||
x_fit_peak, y_fit_peak, popt_peak = guassian_fit(wavelength, transmission) | ||
|
||
plt.plot(wavelength,transmission,'b+:',label='data') | ||
plt.plot(x_fit_peak,y_fit_peak,'r-',label='fit') | ||
plt.legend() | ||
plt.xlabel("wavelength (m)") | ||
plt.ylabel("drop tranmission (dBm)") | ||
plt.show() | ||
|
||
|
||
wavelength, drop_transmission, thru_transmission = load_results() | ||
|
||
#fit_2_peaks(wavelength, drop_transmission) | ||
fit_peak(wavelength, drop_transmission) | ||
#plot_tranmission(wavelength, drop_transmission, thru_transmission) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
import imp | ||
import numpy as np | ||
from math import log | ||
import os | ||
from scipy.stats import linregress | ||
from scipy.constants import c | ||
from matplotlib import pyplot as plt | ||
from prompt_toolkit import PromptSession | ||
#from prompt_toolkit.history import InMemoryHistory | ||
#from prompt_toolkit.auto_suggest import AutoSuggestFromHistory | ||
|
||
time_window = 5.12e-09 | ||
n_samples = 15360 | ||
heater_path = "./n-doped-heater/" | ||
|
||
# TODO BEFORE ANYTHING | ||
# thermally tuned waveguide | ||
# https://support.lumerical.com/hc/en-us/articles/360042833673-Thermally-tuned-waveguide-FDE- | ||
# https://kx.lumerical.com/t/different-doping-regions-device/7682/2 | ||
# pg 13: https://open.library.ubc.ca/cIRcle/collections/ubctheses/24/items/1.0363058 | ||
laser_wavelength = 1545e-9 | ||
min_voltage = 0 | ||
max_voltage = 20 | ||
n_voltages = 100 | ||
|
||
lumapi = imp.load_source("lumapi.py", "/Applications/Lumerical 2020a.app/Contents/API/Python/lumapi.py") | ||
|
||
# TODOs: | ||
''' | ||
- setup interactive config: https://codeburst.io/building-beautiful-command-line-interfaces-with-python-26c7e1bb54df | ||
- last paragraph from alex fb control pg 3, 8, (both code and report) to improve ndoped heater description & calibration | ||
- calc params from alex fb control last par. pg 5 & pg 6, thermo-optic coefficient looks doable - see what else | ||
- run headless | ||
- pip freeze | ||
- cleanup file structure | ||
- readme | ||
''' | ||
|
||
# important notes | ||
''' | ||
https://support.lumerical.com/hc/en-us/articles/360042322794 | ||
calc passive wg: step 2, or passivebentwg | ||
''' | ||
|
||
def heat(min_v, max_v, prec_v): | ||
# TODO: if resim not required, skip | ||
# need to do heat if values out of saved range, or precision is smaller than saved | ||
device = lumapi.DEVICE(heater_path + "NdopedHeaterDesign.ldev") | ||
device.switchtolayout() | ||
device.setnamed("HEAT::temp", "filename", "wgT1_" + str(min_v) + "_" + str(max_v) + "_" + str(prec_v) + ".mat") | ||
|
||
v_bc_name = "HEAT::boundary conditions::wire1" | ||
device.setnamed(v_bc_name, "range start", min_v) | ||
device.setnamed(v_bc_name, "range stop", max_v) | ||
device.setnamed(v_bc_name, "range interval", prec_v) | ||
|
||
device.run() | ||
|
||
boundaries = device.getresult('HEAT','boundaries'); | ||
current = [x[0] for x in boundaries['I_wire1'][0][0]] | ||
voltage = [x[0] for x in boundaries['V_wire1']] | ||
|
||
reg = linregress(current, voltage) | ||
resistance = reg[0] | ||
print("Resistance = " + str(resistance) + " Ohms") | ||
plt.plot(current, voltage) | ||
plt.xlabel("current") | ||
plt.ylabel("voltage") | ||
plt.show() | ||
|
||
#plot(V,-I,'Voltage (V)','Current (A)'); | ||
|
||
# this could be useful for power or ohms/power | ||
''' | ||
P1 = pinch(boundaries.P_lead_left); | ||
P2 = pinch(boundaries.P_lead_right); | ||
P3 = pinch(boundaries.P_substrate); | ||
P4 = pinch(boundaries.P_top_surface); | ||
Ptotal = abs(P1+P2+P3+P4); | ||
R = 50; # ohm | ||
Panalytic = V^2/R; | ||
plot(V,Ptotal,Panalytic,'Voltage (V)','Power (W)'); | ||
legend('simulation','analytic'); | ||
''' | ||
|
||
device.close() | ||
|
||
# TODO: this needs to be tested | ||
# go through lums example and see how its done - then just replicate | ||
def passivebentwg(): | ||
mode = lumapi.MODE(heater_path + "rib_waveguide.lms") | ||
|
||
# import T map | ||
mode.switchtolayout() | ||
mode.select("temperature") | ||
mode.setnamed('temperature','enabled', 0); | ||
|
||
mode.run() | ||
#print(mode.getanalysis()) | ||
mode.setanalysis("number of trial modes", 2) | ||
mode.setanalysis("wavelength", laser_wavelength) | ||
mode.setanalysis("use max index", 1) | ||
|
||
mode.findmodes() | ||
print("Num nodes: " + str(mode.nummodes())) | ||
mode.selectmode(1) | ||
|
||
mode.setanalysis("track selected mode", 1); | ||
input("Run frequency sweep") | ||
mode.frequencysweep() | ||
dataname = mode.copydcard("frequencysweep"); | ||
mode.savedcard("passive_bent_wg.ldf", dataname); | ||
mode.close() | ||
|
||
def neffModeSolver(): | ||
mode = lumapi.MODE(heater_path + "rib_waveguide.lms") | ||
|
||
# import T map | ||
mode.switchtolayout() | ||
mode.select("temperature") | ||
mode.importdataset("wgT1.mat") | ||
|
||
mode.run() | ||
#print(mode.getanalysis()) | ||
mode.setanalysis("number of trial modes", 2) | ||
mode.setanalysis("wavelength", laser_wavelength) | ||
mode.setanalysis("use max index", 1) | ||
|
||
mode.findmodes() | ||
print("Num nodes: " + str(mode.nummodes())) | ||
|
||
mode.selectmode(1) | ||
mode.setanalysis("track selected mode", 1) | ||
mode.frequencysweep() | ||
dataname = mode.copydcard("frequencysweep") | ||
mode.savedcard("active_bent_wg.ldf", dataname) | ||
|
||
voltage = np.linspace(min_voltage, max_voltage, n_voltages) # volts | ||
neffT = [] | ||
|
||
# TODO: ensure i dont need to use seteigensolver instead of setanalysis | ||
# read T map | ||
result_str = "" | ||
for v in voltage: | ||
mode.switchtolayout(); | ||
mode.setnamed('temperature','enabled', 1); | ||
mode.setnamed('temperature','V_wire1', v); | ||
mode.findmodes(); | ||
|
||
data = mode.getdata('mode1','neff'); | ||
|
||
if len(data) != 1 or len(data[0]) != 1: | ||
print("Error, length of data wrong") | ||
print(data) | ||
|
||
neff = data[0][0] | ||
neffT.append(neff) | ||
|
||
result_str += str(v) + " " + str(np.real(neff)) + " " + str(np.imag(neff)) + "\n" | ||
|
||
f = open("Delta_neffTemp1.txt","w+") | ||
f.write(result_str) | ||
f.close() | ||
mode.close() | ||
|
||
def interconnect(): | ||
ic = lumapi.INTERCONNECT("./weight_bank.icp") | ||
|
||
# TODO: configure sim with files from previous sims | ||
# restore design mode in case we are in analysis mode | ||
ic.switchtodesign() | ||
|
||
# time to execute simulation | ||
ic.setnamed("::Root Element","time window", time_window) | ||
# number of samples defines the INTERCONNECT time step dt | ||
# by dt = time_window/(Nsamples+1). | ||
ic.setnamed("::Root Element","number of samples", n_samples) | ||
|
||
use_laser = False | ||
# TODO: configure by user | ||
if user_laser: | ||
ic.addelement("CW Laser") | ||
ic.setnamed("CWL_1", "frequency", c/laser_wavelength) | ||
ic.setnamed("CWL_1", "power", 0.001) | ||
ic.select("ONA_1") | ||
ic.delete() | ||
ic.connect("CWL_1", "output", "COMPOUND_1", "input") | ||
|
||
ic.run() | ||
return ic | ||
|
||
def main(): | ||
# take in values, show previous given as default | ||
# depending on which are changed, re run sims | ||
session = PromptSession() | ||
voltage = session.prompt('Enter n-doped heater voltage range (start,end,precision): ', default='4.5,4.62,0.003') | ||
min_v, *rest_v = list(map(float, voltage.split(","))) | ||
|
||
max_v = rest_v[0] if rest_v else min_v | ||
prec_v = rest_v[1] if rest_v else 1 | ||
|
||
print(min_v) | ||
print(max_v) | ||
print(prec_v) | ||
|
||
heat(min_v, max_v, prec_v) | ||
#input("Run neff mode solver?") | ||
|
||
interconnect() |
Oops, something went wrong.