Multitone tone HB of a resistive circuit

ground 0 

load "nl2.va"

model vsource vsource
model nl2 nl2

v1 (1 0) vsource dc=0 type="am" sinedc=0.0 ampl=4 freq=50k modfreq=5k modindex=0.5
nl1 (1 0) nl2

// Excitation 
//   x = 4*sin(2*pi*50k*t)*(1+0.5*sin(2*pi*5k*t))
// Nonlinearity
//   x^2
// Response
//       9
//      -9   cos(2*pi*100k*t)
//      -1   cos(2*pi*10k*t)
//      +0.5 cos(2*pi*90k*t)
//      +0.5 cos(2*pi*110k*t)
//      +8   sin(2*pi*5k*t)
//      +4   sin(2*pi*95k*t)
//      -4   sin(2*pi*105k*t)
// Spectrum of Response
//             s    -c   c     s    -c    -s    c
//   freq  0   5k   10k  90k   95k  100k  105k  110k
//   mag   9   8    1    0.5   4    9     4     0.5
//   phase 0   -90  180  0     -90  180   90    0

control
  abort always
  print instance("v1")
  
  alter instance("v1") type="dc"
  sweep v1 instance="v1" parameter="dc" from=-1 to=1  mode="lin" points=50
    analysis dc1 op 
  
  options hb_debug=5 nr_debug=0
  alter instance("v1") type="am"
  analysis hb1 hb freq=[5k,50k] nharm=5 immax=5
  
  postprocess(PYTHON, "runme.py")
endc

embed "nl2.va" <<<FILE
`include "constants.vams"
`include "disciplines.vams"

module nl2(A,B);
    // Terminals and internal nodes
    inout A, B;
    electrical A,B;
    
    analog begin
        I(A,B) <+ pow(V(A,B), 2);
    end
endmodule
>>>FILE

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

tests = []

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

v1 = dc1['1']
i1 = -dc1["v1:flow(br)"]

hb1 = rawread('hb1.raw').get()
f = np.real(hb1['frequency'])
i1s = -hb1['v1:flow(br)']
i1mag = np.abs(i1s)
i1ph = np.angle(i1s)*180/np.pi

exactf   = np.array([0, 5, 10, 90, 95, 100, 105, 110])*1e3
exactmag = np.array([9, 8, 1, 0.5, 4, 9, 4, 0.5])
exactph  = np.array([0, -90, 180, 0, -90, 180, 90, 0])
exactcx  = exactmag*(np.cos(exactph*np.pi/180)+1j*np.sin(exactph*np.pi/180))

exact = np.zeros(f.size, dtype=np.complex64)
for fx, cx in zip(exactf, exactcx):
    ii = np.where(np.abs(f-fx)<1e-12*fx+1e-12)[0]
    if ii.size>0:
        exact[ii[0]] = cx

maxdelta = np.abs(exact-i1s).max()
print("max delta:", maxdelta)
tests.append(maxdelta<1e-12)

delta = np.abs(i1s-exact).max()
print("spectrum max delta:", delta)
tests.append(delta<1e-12)

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

    fig1, ax1 = plt.subplots(3, 1, figsize=(5,8), dpi=100, constrained_layout=True)
    fig1.suptitle('pow(v,2) of 50kHz carrier AM 5kHz, m=0.5')
    fig1.axes[0].set_title('DC response')
    fig1.axes[0].set_ylabel('I [A]')
    fig1.axes[0].set_xlabel('V [V]')
    fig1.axes[0].plot(v1, v1**2)
    fig1.axes[0].plot(v1, i1, marker=".", color="red", linestyle="none")

    fig1.axes[1].set_title('I(v1) spectrum')
    fig1.axes[1].set_ylabel('Magnitude [A]')
    fig1.axes[1].stem(f/1e3, i1mag, markerfmt='.')
    
    fig1.axes[2].set_ylabel('Phase [deg]')
    fig1.axes[2].set_xlabel('f [kHz]')
    fig1.axes[2].stem(f/1e3, i1ph, markerfmt='.')
    
    plt.show()
>>>FILE

