def make_thd_plot(thdplot, sinplot, voltages): thdplot.set_ylabel("thd (dB)") thdplot.set_xlabel("control current (mA)") thdplot.set_title("total harmonic distortion") sinplot.set_xticks([], []) #sinplot.set_yticks([],[]) #sinplot.set_title("sine shape at cc = 1mA") #for voltage in np.arange(3,18, 1): for voltage in voltages: printall(ns.cmd("alter v1 %f" % voltage)) printall(ns.cmd("alter v2 %f" % voltage)) y = [] x = my_logspace(0.01, 1, 8) for current in x: printall(ns.cmd("alter i1 %fm" % current)) y.append(calc_thd(300)) printall(ns.cmd("alter i1 40u")) _, signal, time = simulate_waveform(300, n_periods=1, steps_per_period=64) thdplot.plot(x / 1000, np.log10(y) * 10, label="+/- %fV" % voltage) sinplot.plot(time, signal) thdplot.set_xscale('log') fmt_mA = ticker.EngFormatter(unit='A') fmt_dB = ticker.FormatStrFormatter('%.0f dB') thdplot.xaxis.set_major_formatter(fmt_mA) thdplot.yaxis.set_major_formatter(fmt_dB)
def test_cmd(self): self.assertEqual(ns.cmd('print planck'), ['planck = 6.626200e-34']) self.assertEqual(ns.cmd('print' + ' ' * 200 + 'kelvin'), ['kelvin = -2.73150e+02']) # Command too long self.assertRaises(ValueError, ns.cmd, 'print' + ' ' * 2000 + 'kelvin')
def test_cmd(self): self.assertEqual(ns.cmd('print planck'), ['planck = 6.626200e-34']) self.assertEqual(ns.cmd('print' + ' ' * 200 + 'kelvin'), ['kelvin = -2.73150e+02']) # Command too long self.assertRaises(ValueError, ns.cmd, 'print' + ' ' * 2000 + 'kelvin')
def sim(): tb = testbench(common_emitter_amplifer()) circuit = Builder(tb).compile() circuit.to_spice('common_emitter_amplifier.sp') ng.source('common_emitter_amplifier.sp') ng.cmd('tran 50us 10ms') print('\n'.join(ng.vector_names())) time, tp1 = map(ng.vector, ['time', 'V(VOUT)']) plt.plot(time, tp1, label='VOUT') plt.legend() plt.show()
def test_default_codemodels(self): """Test presence of one model from each default .cm library""" required_models = {'spice2poly', 'sine', 'd_nor', 'aswitch', 'd_to_real'} existing_models = {line.partition(' ')[0] for line in ns.cmd('devhelp')[1:]} self.assertEqual(required_models, required_models & existing_models)
def plot_bode(outfile): plt.clf() printall(ns.cmd("alter c6 100u")) #printall(ns.cmd("alter v1 3")) #printall(ns.cmd("alter v2 3")) gains = [500**(1 / n) for n in range(3, 0, -1)] impedances = [1000, 10 * 1000, 100 * 1000, 1000 * 1000, 10 * 1000 * 1000] currents_mA = [0] + list(my_logspace(0.0001, 10, 5 if DRAFT_MODE else 16)) _, plots = plt.subplots( len(gains), len(impedances) + 1, gridspec_kw={'width_ratios': [3] * len(impedances) + [1]}) fmt_Hz = ticker.EngFormatter(unit='Hz') fmt_dB = ticker.EngFormatter(unit='dB') ohmfmt = ticker.EngFormatter(unit="Ω") for y, gain in enumerate(gains): for x, impedance_ohms in enumerate(impedances): update_amplifier(impedance_ohms, gain) plot_single_bode_family(plots[y][x], currents_mA) plots[y][x].set_ylim(10 * math.log10(gain / 500) - 55, 10 * math.log10(gain / 500) + 5) plots[y][x].xaxis.set_major_formatter(fmt_Hz) plots[y][x].yaxis.set_major_formatter(fmt_dB) if x == 0: plots[y][x].text(0, 0.5, 'gain = %.1f×\n\n\n\n' % gain, fontsize=10, horizontalalignment='right', verticalalignment='center', transform=plots[y][x].transAxes, rotation='vertical') if y == 0: plots[y][x].text(0.5, 1.0, 'impedance = %s\n' % ohmfmt.format_data(impedance_ohms), fontsize=10, horizontalalignment='center', verticalalignment='baseline', transform=plots[y][x].transAxes) if y == len(gains) - 1: plots[y][x].set_xlabel("Frequency") for p in plots: p[-1].axis(False) fmt = ticker.EngFormatter(unit="A") make_legend([fmt.format_data(c / 1000) for c in currents_mA], plots[0][-1]) plt.gcf().set_size_inches(20, 11) if outfile is not None: plt.savefig(outfile)
def update_amplifier(impedance_ohms, factor): factor /= PREGAIN if not TWO_STAGE_AMP: r78 = impedance_ohms r910 = r78 * factor printall(ns.cmd("alter r7 %f" % r78)) printall(ns.cmd("alter r8 %f" % r78)) printall(ns.cmd("alter r9 %f" % r910)) printall(ns.cmd("alter r10 %f" % r910)) else: factor_sqrt = math.sqrt(factor) r78 = impedance_ohms r910 = r78 * factor_sqrt printall(ns.cmd("alter r7 %f" % r78)) printall(ns.cmd("alter r8 %f" % r78)) printall(ns.cmd("alter r9 %f" % r910)) printall(ns.cmd("alter r10 %f" % r910)) printall(ns.cmd("alter r101 %f" % r78)) printall(ns.cmd("alter r102 %f" % r910))
def simulate_waveform(freq, n_periods=2, t_skip_ms=25, steps_per_period=200): period = 1 / freq timestep = period / steps_per_period # set the input frequency printall(ns.cmd("let tmp = @v4[sin]")) printall(ns.cmd("let tmp[2] = %f" % freq)) printall(ns.cmd("alter @v4[sin] = tmp")) skip_periods = math.ceil(t_skip_ms / 1000 * freq) actual_t_skip_ms = skip_periods / freq * 1000 t_run_ms = actual_t_skip_ms + n_periods / freq * 1000 ns.destroy() print("tran %fu %fm %fm" % (timestep * 1000000, t_run_ms, actual_t_skip_ms)) ns.cmd("tran %fu %fm %fm" % (timestep * 1000000, t_run_ms, actual_t_skip_ms)) return ns.vector('signal_in'), ns.vector('signal_out'), ( ns.vector('time') - actual_t_skip_ms / 1000)
def plot_bode2(outfile): plt.clf() printall(ns.cmd("alter c6 100u")) currents_mA = [0] + list(my_logspace(0.0001, 0.1, 5 if DRAFT_MODE else 16)) headroom = 1 # set to 2.5 possibly update_amplifier(10000, 500 / headroom) if DRAFT_MODE: xlen, ylen = 3, 2 else: xlen, ylen = 7, 5 max_resonance_gain = 1 / 25 * headroom resonance_gains = list( np.arange(0, max_resonance_gain, max_resonance_gain / (xlen * ylen))) _, plots = plt.subplots(xlen, ylen) fmt_Hz = ticker.EngFormatter(unit='Hz') fmt_dB = ticker.EngFormatter(unit='dB') ohmfmt = ticker.EngFormatter(unit="Ω") for i, resonance_gain in enumerate(resonance_gains): x = i % ylen y = int(i / ylen) print("\n######\n####### %s\n######\n" % resonance_gain) printall(ns.cmd("alter r122 %f" % (100000 * resonance_gain))) plot_single_bode_family(plots[y][x], currents_mA) plots[y][x].set_ylim(-55, 15) plots[y][x].xaxis.set_major_formatter(fmt_Hz) plots[y][x].yaxis.set_major_formatter(fmt_dB) plots[y][x].set_title("gain = %7.5f" % resonance_gain, y=1.0, pad=-14) plt.gcf().set_size_inches(20, 11) if outfile is not None: plt.savefig(outfile)
def calc_attenuation_and_phase(freq, control_current_mA, n_periods=2, t_skip_ms=25, steps_per_period=200, debug=False): # set the control current printall(ns.cmd("alter i1 %fm" % control_current_mA)) signal_in, signal_out, time = simulate_waveform(freq, n_periods, t_skip_ms, steps_per_period) amplitude_in = np.max(signal_in) - np.min(signal_in) amplitude_out = np.max(signal_out) - np.min(signal_out) zeros = zero_crossings(signal_out) if len(zeros) >= 3: pmax = int((zeros[0] + zeros[1]) / 2) pmin = int((zeros[1] + zeros[2]) / 2) print(pmax, pmin) if signal_out[pmax] < signal_out[pmin]: pmin, pmax = pmax, pmin period = ((time[pmax] * freq - 1 / 4) % 1.0) * math.pi * 2 if period > math.pi: period -= 2 * math.pi else: period = np.nan attenuation_db = math.log10(amplitude_out / amplitude_in) * 10 print(attenuation_db, period) if debug: plt.plot(time, signal_in) plt.plot(time, signal_out) plt.pause(3) return attenuation_db, period
def run_sim(varactor_voltage): ngspyce.cmd(f'alterparam varactor_bias_voltage = {varactor_voltage}') ngspyce.cmd('reset') # ngspyce.cmd('stop after 10000') step_ps = 1 #not always obeyed - ngspice sets its own timestep. sim_duration = 100000 n_steps = sim_duration / step_ps # ngspyce.cmd(" ") ngspyce.cmd(f'tran {step_ps}p {sim_duration}ps uic') timesteps = ngspyce.vector('time') v_collector = ngspyce.vector('v(E1)') v_base = ngspyce.vector('v(Base)') varactor_bias = ngspyce.vector('v(Vvaractor)') output = ngspyce.vector('v(output)') stable_running_point = -1 * len(v_collector) // 3 v_collector_trimmed = v_collector[ stable_running_point:] # lots of noise on startup. we want to trim that out of the FFT. spectrum = np.fft.fft(v_collector_trimmed) spectrum_freqs = np.fft.fftfreq( len(v_collector_trimmed), d=(timesteps[-1] - timesteps[stable_running_point]) / len(v_collector_trimmed)) spectrum_begin_indice = np.abs(spectrum_freqs - 100e6).argmin() spectrum_end_indice = np.abs(spectrum_freqs - 25e9).argmin() #normalize spectrum_norm = np.linalg.norm( spectrum[spectrum_begin_indice:spectrum_end_indice].clip(min=0)) if (spectrum_norm): fft_cleaned = spectrum[spectrum_begin_indice:spectrum_end_indice].clip( min=0) / spectrum_norm else: fft_cleaned = np.zeros_like( spectrum[spectrum_begin_indice:spectrum_end_indice]) spectrum_freqs = spectrum_freqs[spectrum_begin_indice:spectrum_end_indice] fft_cleaned = fft_cleaned[:int( 600)] # trim all spectra to the same length 2ps,800, 5ps, 600 spectrum_freqs = spectrum_freqs[:int(600)] return [ np.array(np.abs(fft_cleaned)), np.array(spectrum_freqs), timesteps, v_collector, v_base, varactor_bias, output ]
import ngspyce import numpy as np from matplotlib import pyplot as plt ngspyce.source('quad.net') #trrandom(2 2m 0 10m 0) ngspyce.cmd('tran 1m 20m') print('\n'.join(ngspyce.vector_names())) time, vsin, vcos = map(ngspyce.vector, ['time', 'Vsin', 'Vcos']) #np.savetxt('vcos.txt', vcos) #np.savetxt('vsin.txt', vsin) #np.savetxt('time.txt', time) #exit() plt.plot(time, vcos, label='Vcos') plt.plot(time, vsin, label='Vsin') plt.legend() plt.show()
# Plot the frequency response of an RC low-pass filter import ngspyce from matplotlib import pyplot as plt import numpy as np # Reat netlist ngspyce.cmd('source lowpass.net') # Calculate small-signal transfer function between 10kHz and 100MHz, with 5 # points per decade ngspyce.cmd('ac dec 5 10k 100meg') # Read results freq = np.abs(ngspyce.vector('frequency')) vout = ngspyce.vector('vout') # And plot them fig = plt.figure() fig.suptitle('Frequency response of an RC low-pass filter') ax = fig.add_subplot(1,2,1) ax.semilogx(freq, 20*np.log10(np.abs(vout))) ax.set_xlabel('Frequency [Hz]') ax.set_ylabel('Magnitude [dB]') ax = fig.add_subplot(1,2,2) ax.semilogx(freq, np.angle(vout,True)) ax.set_xlabel('Frequency [Hz]') ax.set_ylabel('Phase [degrees]')
# Plot output voltages of an operational amplifier quadrature oscillator import ngspyce import numpy as np from matplotlib import pyplot as plt # Load netlist ngspyce.cmd(b'source quad.net') # Simulate 10 ms ngspyce.cmd(b'tran 12n 10m 1n') # Read results time, vsin, vcos = map(ngspyce.vector, ['time','Vsin','Vcos']) # And plot them plt.plot(time*1e3, vcos, label='Vcos') plt.plot(time*1e3, vsin, label='Vsin') plt.title('Quadrature op-amp oscillator output voltage') plt.xlabel('Time [ms]') plt.ylabel('Voltage [V]') plt.savefig('quad.png') plt.show()
""" Plot output voltages of an operational amplifier quadrature oscillator """ import ngspyce import numpy as np from matplotlib import pyplot as plt # Load netlist ngspyce.source('quad.net') # Simulate 10 ms ngspyce.cmd('tran 12n 10m 1n') # Read results time, vsin, vcos = map(ngspyce.vector, ['time', 'Vsin', 'Vcos']) # And plot them plt.plot(time * 1e3, vcos, label='Vcos') plt.plot(time * 1e3, vsin, label='Vsin') plt.title('Quadrature op-amp oscillator output voltage') plt.xlabel('Time [ms]') plt.ylabel('Voltage [V]') plt.savefig('quad.png') plt.show()
def test_vector(self): ns.cmd('let myvector = unitvec(4)') self.assertEqual(list(ns.vector('myvector')), [1, 1, 1, 1])
def test_vector_names(self): ns.cmd('set curplot = new') names = list('abdf') for name in names: ns.cmd('let {} = 0'.format(name)) self.assertEqual(sorted(ns.vector_names()), names)
def set_input_amplitude(amplitude): printall(ns.cmd("let tmp = @v4[sin]")) printall(ns.cmd("let tmp[1] = %f" % amplitude)) printall(ns.cmd("alter @v4[sin] = tmp"))
""" Plot output voltages of an operational amplifier quadrature oscillator """ import ngspyce import numpy as np from matplotlib import pyplot as plt # Load netlist ngspyce.source('quad.net') # Simulate 10 ms ngspyce.cmd('tran 12n 10m 1n') # Read results time, vsin, vcos = map(ngspyce.vector, ['time', 'Vsin', 'Vcos']) # And plot them plt.plot(time*1e3, vcos, label='Vcos') plt.plot(time*1e3, vsin, label='Vsin') plt.title('Quadrature op-amp oscillator output voltage') plt.xlabel('Time [ms]') plt.ylabel('Voltage [V]') plt.savefig('quad.png') plt.show()
""" Plot the output characteristics for the BC337 NPN transistor """ import ngspyce import numpy as np from matplotlib import pyplot as plt # Load netlist ngspyce.source('npn.net') # Sweep both base and collector current ngspyce.cmd('dc vcc 0 2 .05 vbb .7 1.2 .1') # Load simulation results into numpy arrays vb, vc, Ivcc = map(ngspyce.vector, ['Vb', 'Vc', 'I(Vcc)']) # Correct the sign for collector current ic = -Ivcc plt.figure() # Plot one line per base voltage series = np.unique(vb) for _vb in series: plt.plot(vc[vb == _vb], ic[vb == _vb], '-', label='Vb = {:.1f}'.format(_vb)) plt.legend() plt.title('Output characteristics for BC337')
import ngspyce import numpy as np from matplotlib import pyplot as plt ngspyce.cmd(b'source quad.net') #trrandom(2 2m 0 10m 0) ngspyce.cmd(b'tran 1m 20m') print('\n'.join(ngspyce.vectorNames())) vcos, vsin, time = ngspyce.vectors(['Vcos','Vsin','time']).values() #np.savetxt('vcos.txt', vcos) #np.savetxt('vsin.txt', vsin) #np.savetxt('time.txt', time) #exit() plt.plot(time,vcos, label='Vcos') plt.plot(time,vsin, label='Vsin') plt.legend() plt.show()
# Plot the output characteristics for the BC337 NPN transistor import ngspyce import numpy as np from matplotlib import pyplot as plt # Load netlist ngspyce.cmd(b'source npn.net') # Sweep both base and collector current ngspyce.cmd(b'dc vcc 0 2 .05 vbb .7 1.2 .1') # Load simulation results into numpy arrays vb, vc, Ivcc = map(ngspyce.vector, ['Vb', 'Vc', 'I(Vcc)']) # Correct the sign for collector current ic = -Ivcc plt.figure() # Plot one line per base voltage series = np.unique(vb) for _vb in series: plt.plot(vc[vb==_vb], ic[vb==_vb], '-', label='Vb = {}'.format(_vb)) plt.legend() plt.title('Output characteristics for BC337') plt.xlabel('Collector-emitter voltage [V]') plt.ylabel('Collector current [A]') plt.savefig('bc337.png') plt.show()
""" Plot the output characteristics for the BC337 NPN transistor """ import ngspyce import numpy as np from matplotlib import pyplot as plt # Load netlist ngspyce.source('npn.net') # Sweep both base and collector current ngspyce.cmd('dc vcc 0 2 .02 vbb .7 1.2 .1') # Load simulation results into numpy arrays vb, vc, Ivcc = map(ngspyce.vector, ['Vb', 'Vc', 'I(Vcc)']) # Correct the sign for collector current ic = -Ivcc plt.figure() # Plot one line per base voltage series = np.unique(vb) for _vb in series: plt.plot(vc[vb == _vb], ic[vb == _vb], '-', label='Vb = {:.1f}'.format(_vb)) plt.legend(loc='center right') plt.title('Output characteristics for BC337') plt.xlabel('Collector-emitter voltage [V]') plt.ylabel('Collector current [A]')