HB-assisted HB

ground 0 

load "diode.osdi"
load "resistor.osdi"
load "capacitor.osdi"

model vsource vsource
model d310 diode(
    is=2.5u n=1.437 rs=0.07 m=0.314 vj=1.65 
    cjo=14pF ibv=5u bv=20 tt=130n eg=0.67 xti=3
)
model resistor resistor
model capacitor capacitor

v1 (1 0) vsource type="am" sinedc=0.0 ampl=0.8 freq=50k modfreq=1k modindex=0.5
d1 (1 2) d310
c1 (2 0) capacitor c=1n
r1 (2 0) resistor r=200k

control
  abort always
  print unknowns
  
  analysis tran1 tran stop=5m step=1u maxstep=0.1u

  // Initial HB with only 2 carrier harmonics, allow homotopy
  options homotopy_debug=1 hb_debug=1 nr_debug=0 hb_skipinitial=1 hb_homotopy=["src"] 
  analysis hb0 hb freq=[1k, 50k] truncate="box" nharm=[1, 10] store="hbstart"
  // Actual HB with only 20 carrier harmonics, initial HB only, no homotopy
  // Use solution of initial HB as starting point
  options hb_skipinitial=0 hb_homotopy=[] nr_debug=0 // hb_itl=100 // nr_force=1e10
  analysis hb1 hb freq=[1k, 50k] truncate="box" nharm=[2, 20] nodeset="hbstart"
  
  postprocess(PYTHON, "runme.py")
endc

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

tests = []

tran1 = rawread('tran1.raw').get()
time = tran1['time']
vin = tran1['1']
vout = tran1['2']

hb1 = rawread('hb1.raw').get()
f = np.real(hb1['frequency'])
S = hb1['2']
Smag = np.abs(S)

ty = np.linspace(0, 2/1e3, 1000)
y = np.zeros(ty.size)
for f1, S1 in zip(f, S):
    y += np.real(S1)*np.cos(2*np.pi*f1*ty)
    y += -np.imag(S1)*np.sin(2*np.pi*f1*ty)

ytran = np.interp(time[-1]-2/1e3+ty, time, vout)

delta = np.abs(y-ytran).max()
print("delta (HB-tran):", delta)
tests.append(delta<10e-3)

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

    fig1, ax1 = plt.subplots(4, 1, figsize=(5,8), dpi=100, constrained_layout=True)
    fig1.suptitle('HB analysis of AM demodulator')
    fig1.axes[0].set_title('Transient response')
    fig1.axes[0].set_ylabel('vin [V]')
    fig1.axes[0].set_xlabel('time [ms]')
    fig1.axes[0].plot(time*1e3, vin)

    fig1.axes[1].set_ylabel('vout [V]')
    fig1.axes[1].set_xlabel('time [ms]')
    fig1.axes[1].plot(time*1e3, vout)

    fig1.axes[2].set_title('Steady-state magnitude spectrum')
    fig1.axes[2].set_ylabel('Output magnitude [V]')
    fig1.axes[2].set_xlabel('frequency [kHz]')
    fig1.axes[2].set_yscale("log")
    fig1.axes[2].stem(f/1e3, Smag, markerfmt='.')

    fig1.axes[3].set_title('Quasi-periodic response')
    fig1.axes[3].set_ylabel('vout [V]')
    fig1.axes[3].set_xlabel('time [ms]')
    fig1.axes[3].plot(ty*1e3, y, color="blue", label="HB")
    fig1.axes[3].plot(ty*1e3, ytran, color="red", label="tran")
    fig1.axes[3].legend(loc="upper right")

    plt.show()
>>>FILE

