def current_divider(i, r1, r2): circuit = Circuit('Current Divider') circuit.I('input', 1, circuit.gnd, u_A(float(i))) # Fixme: current value circuit.R(1, 1, circuit.gnd, u_kOhm(float(r1))) circuit.R(2, 1, circuit.gnd, u_kOhm(float(r2))) for resistance in (circuit.R1, circuit.R2): resistance.minus.add_current_probe(circuit) # to get positive value simulator = circuit.simulator(temperature=25, nominal_temperature=25) analysis = simulator.operating_point() output = {} for node in analysis.branches.values(): output[str(node)] = str(round(float(node), 2)) + "A" return circuit, analysis, output
analysis = simulator.dc(Vbase=slice(0, 3, .01)) axe1 = plt.subplot(221) axe1.plot(analysis.base, u_mA(-analysis.Vbase)) # Fixme: I_Vbase axe1.axvline(x=.65, color='red') axe1.legend(('Base-Emitter Diode curve',), loc=(.1,.8)) axe1.grid() axe1.set_xlabel('Vbe [V]') axe1.set_ylabel('Ib [mA]') #################################################################################################### #r# We will now replace the base's voltage source by a current source in the previous circuit. circuit = Circuit('Transistor') Ibase = circuit.I('base', circuit.gnd, 'base', 10@u_uA) # take care to the orientation Vcollector = circuit.V('collector', 'collector', circuit.gnd, 5) # circuit.BJT(1, 'collector', 'base', circuit.gnd, model='generic') # circuit.model('generic', 'npn') circuit.include(spice_library['2n2222a']) circuit.BJT(1, 'collector', 'base', circuit.gnd, model='2n2222a') # Fixme: ngspice doesn't support multi-sweep ??? # it works in interactive mode #?# simulator = circuit.simulator(temperature=25, nominal_temperature=25) #?# analysis = simulator.dc(Vcollector=slice(0, 5, .1), Ibase=slice(micro(10), micro(100), micro(10))) #?# 0 v(i-sweep) voltage # Vcollector in fact #?# 1 v(collector) voltage #?# 2 v(base) voltage #?# 3 i(vcollector) current
thevenin_circuit = Circuit('Thévenin Representation') thevenin_circuit.V('input', 1, thevenin_circuit.gnd, 10 @ u_V) thevenin_circuit.R('generator', 1, 'load', 10 @ u_Ω) thevenin_circuit.R('load', 'load', thevenin_circuit.gnd, 1 @ u_kΩ) simulator = thevenin_circuit.simulator(temperature=25, nominal_temperature=25) analysis = simulator.operating_point() load_node = analysis.load print('Node {}: {:5.2f} V'.format(str(load_node), float(load_node))) #o# norton_circuit = Circuit('Norton Representation') norton_circuit.I( 'input', norton_circuit.gnd, 'load', thevenin_circuit.Vinput.dc_value / thevenin_circuit.Rgenerator.resistance) norton_circuit.R('generator', 'load', norton_circuit.gnd, thevenin_circuit.Rgenerator.resistance) norton_circuit.R('load', 'load', norton_circuit.gnd, thevenin_circuit.Rload.resistance) simulator = norton_circuit.simulator(temperature=25, nominal_temperature=25) analysis = simulator.operating_point() load_node = analysis.load print('Node {}: {:5.2f} V'.format(str(load_node), float(load_node))) #o#
'REBCCD', 'T28out', circuit.gnd, model='T28', length=1, number_of_lumps=8) circuit.UniformDistributedRCLine('T29', 'T28out', 'T29out', circuit.gnd, model='T29', length=1, number_of_lumps=8) #Heat generators circuit.I(1, circuit.gnd, 'CurrentSource', par.CurrSrccurrent) circuit.I(2, circuit.gnd, 'CurrentASPIC', par.ASPICcurrent) circuit.I(3, circuit.gnd, 'CABACcurrent', par.CABACcurrent) circuit.I(4, circuit.gnd, 'ADCcurrent', par.ADCcurrent) circuit.I(5, circuit.gnd, 'DiffAmpcurrent', par.DiffAmpcurrent) circuit.I(6, circuit.gnd, 'Heatercurrent', par.Heatercurrent) circuit.I(7, circuit.gnd, 'FPGAcurrent', par.FPGAcurrent) circuit.I(8, circuit.gnd, 'L3_CCD', par.CCD_DC_current) #Temperature sources and set points circuit.V(1, 'Ambient', circuit.gnd, par.TA) circuit.V(2, 'PlateSetPoint', circuit.gnd, par.Cryo_temp) circuit.V(3, 'ColdSetPoint', circuit.gnd, par.ColdTemp) circuit.V(4, 'CCDSetPoint', circuit.gnd, par.CCD_temp) #Contact resistors
simulator = circuit.simulator(temperature=25, nominal_temperature=25) analysis = simulator.dc(Vbase=slice(0, 3, .01)) axe1 = plt.subplot(221) axe1.plot(analysis.base, -analysis.Vbase * 1000) # Fixme: I_Vbase, unit scale axe1.axvline(x=.65, color='red') axe1.legend(('Base-Emitter Diode curve', ), loc=(.1, .8)) axe1.grid() axe1.set_xlabel('Vbe [V]') axe1.set_ylabel('Ib [mA]') #################################################################################################### circuit = Circuit('Transistor') Ibase = circuit.I('base', circuit.gnd, 'base', micro(10)) # take care to the orientation Vcollector = circuit.V('collector', 'collector', circuit.gnd, 5) # circuit.BJT(1, 'collector', 'base', circuit.gnd, 'generic') # circuit.model('generic', 'npn') circuit.include(spice_library['2n2222a']) circuit.BJT(1, 'collector', 'base', circuit.gnd, '2n2222a') # Fixme: ngspice doesn't support multi-sweep ??? # it works in interactive mode # simulator = circuit.simulator(temperature=25, nominal_temperature=25) # analysis = simulator.dc(Vcollector=slice(0, 5, .1), Ibase=slice(micro(10), micro(100), micro(10))) # 0 v(i-sweep) voltage # Vcollector in fact # 1 v(collector) voltage # 2 v(base) voltage # 3 i(vcollector) current
analysis = simulator.operating_point() node_A = analysis.A print('Node {}: {:5.2f} V'.format(str(node_A), float(node_A))) #o# branch_voltages = np.arange(1, number_of_branches +1) branch_resistances = branch_voltages * float(kilo(1)) conductances = 1 / branch_resistances voltage_A = np.sum(branch_voltages * conductances) / np.sum(conductances) print('V(A) = {:5.2f} V'.format(voltage_A)) #o# # with current sources for i in range(1, number_of_branches +1): ii = number_of_branches + i circuit.I('input%u' % i, circuit.gnd, ii, 100*i@u_uA) circuit.R(ii, ii, 'A', i@u_kΩ) simulator = circuit.simulator(temperature=25, nominal_temperature=25) analysis = simulator.operating_point() node_A = analysis.A print('Node {}: {:5.2f} V'.format(str(node_A), float(node_A))) #o# branch_currents = np.arange(1, number_of_branches +1) * float(micro(100)) voltage_A += np.sum(branch_currents) / np.sum(conductances) print('V(A) = {:5.2f} V'.format(voltage_A)) #o#
def spice_circuit(self, amplitude=1, frequency=0, initial_condition=0): self.amplitude = amplitude self.frequency = frequency circuit = Circuit('Battery Equivalent model') circuit.V('OCV', 1, circuit.gnd, self.Voc @ u_V) #name,positive node,negative node,value circuit.R( 'Rs', 1, 'cap_input_voltage', self.Rs @ u_Ω) #node 2='source_input_node' and node 3='source_output_node' circuit.R('Rp', 'cap_input_voltage', 'cap_output_voltage', self.Rp @ u_Ω) circuit.C('Cp', 'cap_input_voltage', 'cap_output_voltage', self.Cp @ u_F, ic=0 @ u_V) #ic=initial condition circuit.R('Rl', 'cap_output_voltage', 'source_input_node', self.Rl @ u_Ω) #Rl=0 #print(circuit) if self.frequency == 0: circuit.I('current_source', 'source_input_node', circuit.gnd, self.amplitude @ u_A) else: circuit.SinusoidalCurrentSource( 'current_source', 'source_input_node', circuit.gnd, 0 @ u_A, offset=0 @ u_A, amplitude=self.amplitude @ u_A, frequency=self.frequency @ u_Hz) #freq=0.4 #ac_line = circuit.AcLine('current_source', 'source_input_node','source_output_node' , frequenc=0.4u_Hz) #print(circuit) print(initial_condition) simulator = circuit.simulator(temperature=25, nominal_temperature=25) simulator.initial_condition(cap_input_voltage=initial_condition @ u_V) analysis = simulator.transient( step_time=0.01 @ u_s, end_time=1 @ u_s) #@u_s is sec and @u_us is micro sec output_node = [] input_node = [] for node in (analysis['cap_output_voltage']): # #print('Node {}: {} V'.format(str(node), float(node))) output_node.append(float(node)) # print(output_node) for node in (analysis['cap_input_voltage']): # #print('Node {}: {} V'.format(str(node), float(node))) input_node.append(float(node)) # ============================================================================= # print("output_node - input_node : ",input_node[100]-output_node[100]) # print("output_node ",output_node[100]) # print("input ",input_node[100]) # print("output_node shape ",len(output_node)) # ============================================================================= # ============================================================================= # figure1, ax = plt.subplots(figsize=(20, 10)) # ax.set_title('Battery Equivalent Model') # ax.set_xlabel('Time [s]') # ax.set_ylabel('Voltage [V]') # ax.grid() # ax.plot(analysis.cap_input_voltage-analysis.cap_output_voltage) # #ax.plot(analysis.cap_input_voltage) # ============================================================================= Vb = output_node[100] Vb = np.random.normal(Vb, scale=math.sqrt(self.observation_noise)) return ( Vb, input_node[100] - output_node[100] ) #at every 1 we are returning the output value 100*step_time=1sec,in array it will be 99th value100*step_time=0.1 sec,in array it will be 99th value
# r# The relation between the input and ouput current is: # r# # r# .. math:: # r# # r# \frac{I_{out}}{I_{in}} = \frac{R_1}{R_1 + R_2} # r# # r# Note the role of R1 and R2 is exchanged. # r# #r# This equation holds for any impedances like resistance, capacitance, inductance, etc. #################################################################################################### circuit = Circuit('Current Divider') circuit.I('input', 1, circuit.gnd, 1 @ u_A) # Fixme: current value circuit.R(1, 1, circuit.gnd, 2 @ u_kΩ) circuit.R(2, 1, circuit.gnd, 1 @ u_kΩ) for resistance in (circuit.R1, circuit.R2): resistance.minus.add_current_probe(circuit) # to get positive value simulator = circuit.simulator(temperature=25, nominal_temperature=25) analysis = simulator.operating_point() # Fixme: current over resistor for node in analysis.branches.values(): print('Node {}: {:5.2f} A'.format( str(node), float(node))) # Fixme: format value + unit #o#
node_A = analysis.A print('Node {}: {:5.2f} V'.format(str(node_A), float(node_A))) #o# branch_voltages = np.arange(1, number_of_branches + 1) branch_resistances = branch_voltages * float(kilo(1)) conductances = 1 / branch_resistances voltage_A = np.sum(branch_voltages * conductances) / np.sum(conductances) print('V(A) = {:5.2f} V'.format(voltage_A)) #o# # with current sources for i in range(1, number_of_branches + 1): ii = number_of_branches + i circuit.I('input%u' % i, circuit.gnd, ii, micro(100 * i)) circuit.R(ii, ii, 'A', kilo(i)) simulator = circuit.simulator(temperature=25, nominal_temperature=25) analysis = simulator.operating_point() node_A = analysis.A print('Node {}: {:5.2f} V'.format(str(node_A), float(node_A))) #o# branch_currents = np.arange(1, number_of_branches + 1) * float(micro(100)) voltage_A += np.sum(branch_currents) / np.sum(conductances) print('V(A) = {:5.2f} V'.format(voltage_A)) #o# ####################################################################################################
# - a reduced version of ngspices IYYYYYYY only generating the arguement for <<DC> DC/TRAN VALUE > # In[21]: reset() net_1 = Net('N1') net_2 = Net('N2') skidl_I = I(ref='1', dc_value=5) skidl_I['p', 'n'] += net_1, net_2 skidl_circ = generate_netlist() print(skidl_circ) # In[22]: pyspice_circ = Circuit('') pyspice_circ.I('1', 'N1', 'N2', dc_value=5) print(pyspice_circ) # In[23]: netlist_comp_check(skidl_circ, pyspice_circ) # ## J | Junction field effect transistor (JFET) # PySpice/PySpice/Spice/BasicElement.py; class JunctionFieldEffectTransistor(JfetElement) # # skidl/skidl/libs/pyspice_sklib.py; name="J" # # ngspice 9.1 Junction Field-Effect Transistors (JFETs): # # JXXXXXXX nd ng ns mname <area > <off> <ic=vds,vgs> <temp=t> #
from PySpice.Unit import * # Parameters frequency = 1e3 period = 1 / frequency omega = 2 * np.pi * frequency I_P1 = 100 L_P1 = 1e-6 L_S1 = 10e-6 K_P1S1 = 0.1 circuit = Circuit('2CoupledInductors') #Primary Side circuit.I('I2', circuit.gnd, 'N1', 'AC ' + str(I_P1) + '') circuit.L('L_P1', circuit.gnd, 'N1', str(L_P1)) # Secondary Side circuit.L('L_S1', circuit.gnd, 'N2', str(L_S1)) circuit.K('K_P1S1', 'LL_P1', 'LL_S1', K_P1S1) # NB, it adds an L to the name of the inductor ... print(circuit) # # Do the simulation # simulator = circuit.simulator(temperature=25, nominal_temperature=25) # analysis = simulator.ac(variation='lin', number_of_points=1, start_frequency=frequency, stop_frequency=frequency) # # Print the results # print('--- Results ---')
def define_circuit(self): logger = Logging.setup_logging() circuit_lab = self.circuit circuit = Circuit(circuit_lab["name"]) # for complex circuit elements that requires SPICE library # libraries_path = find_libraries() python_file = os.path.abspath(sys.argv[0]) examples_root = parent_directory_of(python_file) libraries_path = os.path.join(examples_root, 'libraries') spice_library = SpiceLibrary(libraries_path) # return message message = "" # add all elements to the PySpice circuit for element in circuit_lab: if element == "V": for dc_voltage_source in circuit_lab["V"]: circuit.V( dc_voltage_source["id"], circuit.gnd if dc_voltage_source["node1"] == "gnd" else dc_voltage_source["node1"], circuit.gnd if dc_voltage_source["node2"] == "gnd" else dc_voltage_source["node2"], dc_voltage_source["value"] @ u_V) elif element == "VA": for ac_voltage_source in circuit_lab["VA"]: circuit.SinusoidalVoltageSource( ac_voltage_source["id"], circuit.gnd if ac_voltage_source["node1"] == "gnd" else ac_voltage_source["node1"], circuit.gnd if ac_voltage_source["node2"] == "gnd" else ac_voltage_source["node2"], amplitude=ac_voltage_source["amplitude"] @ u_V, frequency=ac_voltage_source["frequency"] @ u_Hz, offset=ac_voltage_source["offset"] @ u_V) elif element == "I": for dc_current_source in circuit_lab["I"]: circuit.I( dc_current_source["id"], circuit.gnd if dc_current_source["node1"] == "gnd" else dc_current_source["node1"], circuit.gnd if dc_current_source["node2"] == "gnd" else dc_current_source["node2"], dc_current_source["value"] @ u_A) elif element == "IA": for ac_current_source in circuit_lab["IA"]: circuit.SinusoidalCurrentSource( ac_current_source["id"], circuit.gnd if ac_current_source["node1"] == "gnd" else ac_current_source["node1"], circuit.gnd if ac_current_source["node2"] == "gnd" else ac_current_source["node2"], amplitude=ac_current_source["amplitude"] @ u_A, frequency=ac_current_source["frequency"] @ u_Hz, offset=ac_current_source["offset"] @ u_A) elif element == "R": for resistor in circuit_lab["R"]: circuit.R( resistor["id"], circuit.gnd if resistor["node1"] == "gnd" else resistor["node1"], circuit.gnd if resistor["node2"] == "gnd" else resistor["node2"], resistor["value"] @ u_Ω) elif element == "L": for inductor in circuit_lab["L"]: circuit.L( inductor["id"], circuit.gnd if inductor["node1"] == "gnd" else inductor["node1"], circuit.gnd if inductor["node2"] == "gnd" else inductor["node2"], inductor["value"] @ u_H) elif element == "C": for capacitor in circuit_lab["C"]: circuit.C( capacitor["id"], circuit.gnd if capacitor["node1"] == "gnd" else capacitor["node1"], circuit.gnd if capacitor["node2"] == "gnd" else capacitor["node2"], capacitor["value"] @ u_F) elif element == "D": for diode in circuit_lab["D"]: try: circuit.include(spice_library[diode["modelType"]]) circuit.X( diode["id"], diode["modelType"], circuit.gnd if diode["node1"] == "gnd" else diode["node1"], circuit.gnd if diode["node2"] == "gnd" else diode["node2"]) except KeyError as e: message += " " + str(e) elif element == "nBJT": for nBJT in circuit_lab["nBJT"]: try: circuit.include(spice_library[nBJT["modelType"]]) circuit.BJT(nBJT["id"], circuit.gnd if nBJT["node1"] == "gnd" else nBJT["node1"], circuit.gnd if nBJT["node2"] == "gnd" else nBJT["node2"], circuit.gnd if nBJT["node3"] == "gnd" else nBJT["node3"], model=nBJT["modelType"]) except KeyError as e: message += " " + str(e) elif element == "pBJT": for pBJT in circuit_lab["pBJT"]: try: circuit.include(spice_library[pBJT["modelType"]]) circuit.BJT(pBJT["id"], circuit.gnd if pBJT["node3"] == "gnd" else pBJT["node3"], circuit.gnd if pBJT["node2"] == "gnd" else pBJT["node2"], circuit.gnd if pBJT["node1"] == "gnd" else pBJT["node1"], model=pBJT["modelType"]) except KeyError as e: message += " " + str(e) elif element == "NMOS": for NMOS in circuit_lab["NMOS"]: try: circuit.include(spice_library[NMOS["modelType"]]) # nodes are: drain, gate, source, bulk circuit.MOSFET(NMOS["id"], circuit.gnd if NMOS["node4"] == "gnd" else NMOS["node4"], circuit.gnd if NMOS["node2"] == "gnd" else NMOS["node2"], circuit.gnd if NMOS["node3"] == "gnd" else NMOS["node3"], circuit.gnd if NMOS["node1"] == "gnd" else NMOS["node1"], model=NMOS["modelType"]) except KeyError as e: message += " " + str(e) elif element == "PMOS": for PMOS in circuit_lab["PMOS"]: try: circuit.include(spice_library[PMOS["modelType"]]) # nodes are: source, gate, drain, bulk circuit.MOSFET(PMOS["id"], circuit.gnd if PMOS["node1"] == "gnd" else PMOS["node1"], circuit.gnd if PMOS["node2"] == "gnd" else PMOS["node2"], circuit.gnd if PMOS["node3"] == "gnd" else PMOS["node3"], circuit.gnd if PMOS["node4"] == "gnd" else PMOS["node4"], model=PMOS["modelType"]) except KeyError as e: message += " " + str(e) # add ammeter as a 0 volt voltage source elif element == "AM": for ammeter in circuit_lab["AM"]: circuit.V( ammeter["id"], circuit.gnd if ammeter["node1"] == "gnd" else ammeter["node1"], circuit.gnd if ammeter["node2"] == "gnd" else ammeter["node2"], ammeter["value"] @ u_V) if not message: self.spice = circuit return message return "Undefined model type:" + message
#################################################################################################### libraries_path = find_libraries() spice_library = SpiceLibrary(libraries_path) #################################################################################################### circuit = Circuit('test') R1 = circuit.R(1, 'p1', 'p2', 4 @ u_kΩ) R2 = circuit.R(2, 'p2', 'p6', 1 @ u_kΩ) R3 = circuit.R(3, 'p1', 'p5', 1 @ u_kΩ) R4 = circuit.R(4, 'p5', 'p6', 1 @ u_kΩ) R5 = circuit.R(5, 'p6', 0, 1e-9 @ u_Ω) I1 = circuit.I(1, 0, 'p1', 1 @ u_A) V1 = circuit.V(1, 'p1', 'p4', -10 @ u_V) V2 = circuit.V(2, 'p2', 'p3', -10 @ u_V) print(str(circuit)) simulator = circuit.simulator(simulator='xyce-serial') analysis = simulator.operating_point() for node in analysis.nodes.values(): print('Node {}: {:5.2f} V'.format(str(node), float(node))) for node in analysis.branches.values(): print('Node {}: {:5.2f} A'.format(str(node), float(node)))