Independent sources - time-domain waveforms

ground 0 

load "resistor.osdi"

model resistor resistor
model vsource vsource
model isource isource

// Sine
i1 (0 1) isource type="sine" sinedc=0.5 ampl=2.0 freq=1k tdphase=-90 theta=100
r1 (1 0) resistor r=1

// Step
i2 (0 2) isource type="pulse" val0=1 val1=2 rise=1u delay=1m
r2 (2 0) resistor r=1

// Single pulse
i3 (0 3) isource type="pulse" val0=1 val1=2 rise=1u fall=2u width=2m delay=1.1m
r3 (3 0) resistor r=1

// Pulse train
i4 (0 4) isource type="pulse" val0=1 val1=2 rise=1u fall=2u width=2m period=4m delay=1.2m
r4 (4 0) resistor r=1

// AM
i5 (0 5) isource type="am" sinedc=0.5 ampl=2.0 freq=1000 tdphase=-90 modfreq=50 modphase=90 modindex=0.5
r5 (5 0) resistor r=1

// FM
i6 (0 6) isource type="fm" sinedc=0.5 ampl=2.0 freq=1000 tdphase=-90 modfreq=50 modphase=90 modindex=10
r6 (6 0) resistor r=1

// Exponential
i7 (0 7) isource type="exp" val0=1 val1=2 delay=5m td2=10m tau1=2m tau2=10m 
r7 (7 0) resistor r=1

control
  abort always

  options rawfile="binary" op_debug=0
  options tran_fbr=0.2501
  analysis tran1 tran step=0.1m stop=30m maxstep=0.1m

  postprocess(PYTHON, "runme.py")
endc

embed "runme.py" <<<FILE
from rawfile import rawread
from runtest import *
import numpy as np
import sys

def pulse(t, v0, v1, delay, rise, fall=None, width=None, period=None, tol=1e-9):
    baseoffs = t-delay
    if period is not None:
        baseoffs = baseoffs % period
    if width is None:
        # step
        v = np.where(t<delay, v0, v1)
        v = np.where((t>=delay)&(t<delay+rise), v0+(t-delay)*(v1-v0)/rise, v)
        breaks = [ delay, delay+rise ]
    else:
        # pulse, train
        v = np.where(t<delay, v0, v1)
        v = np.where((t>=delay)&(baseoffs<rise), v0+baseoffs*(v1-v0)/rise, v)
        v = np.where((t>=delay)&(baseoffs>rise+width)&(baseoffs<rise+width+fall), v1+(baseoffs-rise-width)*(v0-v1)/fall, v)
        v = np.where((t>=delay)&(baseoffs>rise+width+fall), v0, v)   
        breaks = [ delay ]
        if period is not None and delay<0:
            # Last base<=0
            base = delay - np.ceil(delay/period)*period
        else:
            base = delay
        while base < t[-1]:
            breaks.extend([ base, base+rise, base+rise+width, base+rise+width+fall ])
            if period is not None:
                base += period
            else:
                break
        
    # Check breaks
    breakOk = True
    for b in breaks:
        if b<=0 or b>t[-1]:
            continue
        delta = np.abs(t-b).min()
        if delta>b*tol:
            breakOk=False
            break
    return v, breakOk 

tests=[]

tran1 = rawread('tran1.raw').get()

time = tran1['time']

vsin = tran1["1"]
exact = 0.5+2.0*np.sin(2*np.pi*1e3*time-np.pi/2)*np.exp(-time*100.0)
status = (relDiff(vsin, exact, 1e-6) < 1e-3).all()
print("Sinusoidal", status)
tests.append(status)

vstep = tran1["2"]
exact, breakOk = pulse(time, 1.0, 2.0, 1e-3, 1e-6)
status = (relDiff(vstep, exact, 1e-9) < 1e-3).all()
print("Step", status, "breaks", breakOk)
tests.append(status and breakOk)

vpulse = tran1["3"]
exact, breakOk = pulse(time, 1.0, 2.0, 1.1e-3, 1e-6, 2e-6, 2e-3)
status = (relDiff(vpulse, exact, 1e-9) < 1e-3).all()
print("Pulse", status, "breaks", breakOk)
tests.append(status and breakOk)

vtrain = tran1["4"]
exact, breakOk = pulse(time, 1.0, 2.0, 1.2e-3, 1e-6, 2e-6, 2e-3, 4e-3)
status = (relDiff(vtrain, exact, 1e-9) < 1e-3).all()
print("Train", status, "breaks", breakOk)
tests.append(status and breakOk)

vam = tran1["5"]
exact = 0.5+2.0*np.sin(2*np.pi*1000.0*time-90*np.pi/180)*(1+0.5*np.sin(2*np.pi*50.0*time+90*np.pi/180))
status = (relDiff(vam, exact, 1e-9) < 1e-3).all()
print("AM", status)
tests.append(status)

vfm = tran1["6"]
exact = 0.5+2.0*np.sin(2*np.pi*1000.0*time-90*np.pi/180+10*np.sin(2*np.pi*50.0*time+90*np.pi/180))
status = (relDiff(vfm, exact, 1e-9) < 1e-3).all()
print("FM", status)
tests.append(status)

vexp = tran1["7"]
exact = 1.0 + (
      (2.0-1.0)*(1-np.exp(-(time-5e-3)/2e-3))*(time>5e-3)
    + (1.0-2.0)*(1-np.exp(-(time-15e-3)/10e-3))*(time>15e-3)
)
status = (relDiff(vexp, exact, 1e-9) < 1e-3).all()
print("Exponential", status)
tests.append(status)


if isTest():
    sys.exit(not all(tests))
else:
    import matplotlib.pyplot as plt 

    fig1, ax1 = plt.subplots(7, 1, figsize=(6,9), dpi=100, constrained_layout=True)
    fig1.suptitle("Transient excitations")

    fig1.axes[0].set_title('Sine')
    fig1.axes[0].set_ylabel('V [V]')
    fig1.axes[0].plot(time*1000, vsin, marker=".")

    fig1.axes[1].set_title('Step')
    fig1.axes[1].set_ylabel('V [V]')
    fig1.axes[1].plot(time*1000, vstep, marker=".")

    fig1.axes[2].set_title('Pulse')
    fig1.axes[2].set_ylabel('V [V]')
    fig1.axes[2].plot(time*1000, vpulse, marker=".")
    
    fig1.axes[3].set_title('Pulse train')
    fig1.axes[3].set_ylabel('V [V]')
    fig1.axes[3].plot(time*1000, vtrain, marker=".")

    fig1.axes[4].set_title('AM')
    fig1.axes[4].set_ylabel('V [V]')
    fig1.axes[4].plot(time*1000, vam, marker=".")

    fig1.axes[5].set_title('FM')
    fig1.axes[5].set_ylabel('V [V]')
    fig1.axes[5].plot(time*1000, vfm, marker=".")

    fig1.axes[6].set_title('Exponential')
    fig1.axes[6].set_ylabel('V [V]')
    fig1.axes[6].set_xlabel('time [ms]')
    fig1.axes[6].plot(time*1000, vexp, marker=".")

    plt.show()
>>>FILE


