Exemple #1
0
def pll_tf_step(pll_tf, tmax):
    """ Generate signal of step response of PLL tranfer function.
    """
    sys = pll_tf_to_sys(pll_tf)
    t = np.arange(0, tmax, 1 / pll_tf["fclk"])
    t, x = scipy.signal.step(sys, T=t, N=len(t))
    return make_signal(td=x, fs=pll_tf["fclk"])
Exemple #2
0
def sim_bbpd_pipll(fclk, fs, sim_steps, div_n, use_bbpd, bbpd_rms_jit,
                 kdco1, kdco2, fine_bits, med_bits, fl_dco, krw_dco,
                 lf_i_bits, lf_f_bits, lf_params_sc, lf_params_bbpd,
                 tsettle_est, init_params, verbose=True, ignore_clk=False,
                 *args, **kwargs):
    # init pll component objects
    if verbose and args: print("Unused args = %r"%args)
    if verbose and kwargs: print("Unused kwargs = %r"%kwargs)
    clk = ClockPhase(f=fclk, dt=1/float(fs), init_phase=init_params["clk"])
    scpd = SCPDPhase(modulus=div_n, init_clk=init_params["clk"], init_out=init_params["scpd"],
                    ignore_clk=ignore_clk)
    bbpd = BBPD(rms_jit=bbpd_rms_jit, fclk=fclk, init_clk=init_params["clk"],
                init_out=init_params["bbpd"], ignore_clk=ignore_clk)
    dco = DCOPhase(kdco1=kdco1, kdco2=kdco2, f0=fl_dco, dt=1/float(fs), krw=krw_dco,
                   init_phase=init_params["osc"], quantize=True)
    lf = LoopFilterPIPhase(init_out=init_params["lf"], init_clk=init_params["clk"],
                            int_bits=lf_i_bits, frac_bits=lf_f_bits, ignore_clk=ignore_clk,
                            verbose=verbose, out_bits=fine_bits+med_bits, **lf_params_sc)

    bbpd_lf_switch = int(np.round(fclk*tsettle_est))
    if bbpd_lf_switch ==0:
        bbpd_lf_switch = 1
    print("LF gearswitch at %d samples"%bbpd_lf_switch)
    def eval_step(n, step):
        if n == bbpd_lf_switch and use_bbpd:
            if verbose: print("\n* Simulation step = %d, switching to BBPD optimized loop filter"%n)
            lf.change_filter(x1init=1, **lf_params_bbpd)
            # dco.clk_align()
        step["osc"]   = dco.update(step["fine"], step["med"])
        step["clk"]   = clk.update()
        step["scpd"]  = scpd.update(clk=step["clk"], xin=step["osc"])
        step["bbpd"]  = bbpd.update(clk=step["clk"], xin=step["osc"])
        if n < bbpd_lf_switch: step["error"] = step["scpd"]
        else: step["error"] = step["bbpd"]
        step["lf"]    = lf.update(xin=step["error"], clk=step["clk"])
        fine, med = fine_med(step["lf"], fine_bits, med_bits)
        step["fine"] = fine
        step["med"] = med
        return step

    data = run_sim(eval_step, sim_steps, init_params)

    for k,v in data.items():
        data[k] = make_signal(td=v, fs=fs)
    params = dict(fclk=fclk, fs=fs, sim_steps=sim_steps, div_n=div_n, use_bbpd=use_bbpd,
                  bbpd_rms_jit=bbpd_rms_jit, kdco1=kdco1, kdco2=kdco2, fl_dco=fl_dco,
                  krw_dco=krw_dco, lf_i_bits=lf_i_bits, lf_f_bits=lf_f_bits,
                  lf_params_sc=lf_params_sc, lf_params_bbpd=lf_params_bbpd,
                  fine_bits=fine_bits, med_bits=med_bits,
                  tsettle_est=tsettle_est, init_params=init_params, verbose=verbose)
    for k,v in kwargs.items():
        params[k] = v
    data["params"] = params
    return data
Exemple #3
0
def osc_td(f0, fs, samples, k, seed=None, rw=[]):
    """ Compute oscillator time domain signal with random walk phase noise
        args:
            f0 - oscillator fundamental frequency
            fs - 1/tstep of simulation
            samples - length of signal to generate
            k - random walk phase gain
            seed - provide 32b value for predictable sequence
    """
    t = np.arange(samples) / float(fs)
    if not any(rw):
        np.random.seed(seed=seed)
        rw = np.cumsum(np.random.choice([-1, 1], samples))
    td = np.sin(k * rw + 2 * np.pi * f0 * t)
    return make_signal(td=td, fs=fs, autocompute_fd=True)
Exemple #4
0
def make_pn_sig(fbin,
                fmax,
                pn_dco,
                pn_dco_df,
                fclk,
                _type,
                m,
                n,
                k,
                ki,
                fz,
                fp,
                delay,
                fn,
                bw,
                damping,
                a0,
                a1,
                b0,
                b1,
                b2,
                label="",
                *args,
                **kwargs):

    bins = int(round(2 * fmax / fbin))
    freqs = fbin * (np.arange(bins) - int(bins / 2))

    # a = pll_otf2(freqs, M, N, KDCO, KP, FZ, FP, DELAY)
    g = pll_tf(freqs, _type, k, fz, fp, delay)

    kpn = pn_dco * pn_dco_df**2
    ndco = np.abs(1 - g)**2 * kpn / freqs**2
    ndco[np.where(g == 1)] = 0

    # ndco = min_ro_pn(fclk*n, freqs, posc, temp)*np.abs(1-g)**2
    ntdc = tdc_pn(fclk, n, m, g) * np.abs(g)**2

    psd = np.fft.fftshift(ndco + ntdc) * bins**2
    if np.isnan(psd[0]): psd[0] = 0.5 * (psd[1] + psd[-1])

    return make_signal(fd=np.sqrt(psd), fs=bins * fbin)
Exemple #5
0
def pn_signal2(sim_data, div_n):
    """ Extract phase noise/error signal from pllsim data
    """
    td = sim_data["osc"].td - div_n * sim_data["clk"].td
    return make_signal(td=td, fs=sim_data["clk"].fs)
Exemple #6
0
def pn_signal(sim_data, div_n):
    """ Extract phase noise/error signal from pllsim data
    """
    td = div_n * (sim_data["div"].td - sim_data["clk"].td)
    return make_signal(td=td, fs=sim_data["clk"].fs)
plt.subplot(3, 3, 8)
pn_sig = pn_signal2(sim_data, div_n=round(FOSC / FCLK))
pn_sig = debias_pn(pn_sig, 0.5 * SIM_SPAN)
plot_td(pn_sig, tmax=PLOT_SPAN, title="Phase error", dots=True)

half = int(SIM_STEPS / 2)
rms = np.std(pn_sig.td[half:])
print("\nSimulated RMS PN:\t\t%.2E rad -> %.2f dB" % (rms, 20 * np.log10(rms)))
est_rms_pn_design = np.sqrt(lfs["bbpd"]["int_pn"])
print("Filter design RMS PN Est:\t%.2E rad -> %.2f dB" %
      (est_rms_pn_design, 20 * np.log10(est_rms_pn_design)))

x = np.zeros(SIM_STEPS + 1)
x[1:] = sim_data["lf"].td
em = -np.cumsum(2 * np.pi * KDCO1 * np.diff(x) * (1 / float(FS)))
em_pn = make_signal(em, fs=FS)
em_pn = debias_pn(em_pn, 0.5 * SIM_SPAN)
plot_td(em_pn, tmax=PLOT_SPAN, title="Emergent PN", dots=True)

plt.subplot(3, 3, 9)
pn = copy(pn_sig.td[int(np.ceil(GEAR_SW_T * FCLK)):])
em = copy(em_pn.td[int(np.ceil(GEAR_SW_T * FCLK)):])
pn[np.abs(pn) > 3 * rms] = np.nan
em[np.abs(em) > 3 * rms] = np.nan
plt.hist(pn, alpha=0.5, bins=50, density=True)
plt.hist(em, alpha=0.5, bins=50, density=True)

plt.figure(2)
plot_pn_ssb2(pn_sig,
             dfmax=PN_FMAX,
             line_fit=False,
Exemple #8
0
for n in range(SAMPLES)[1:]:
    clk_out[n] = clk.update()
    tdc_out[n] = tdc.update(clk=clk_out[n - 1], xin=div_out[n - 1])
    # _tdc = TDC_SCALE*((TDC_OFFSET+tdc_out[n-1])%TDC_STEPS)
    _tdc = ((TDC_OFFSET + tdc_out[n - 1]) % TDC_STEPS) - TDC_OFFSET
    lf_out[n] = lf.update(xin=_tdc, clk=clk_out[n - 1])
    osc_out[n] = dco.update(lf_out[n - 1])
    div_out[n] = div.update(osc_out[n - 1], DIV_N)
tdelta = time.clock() - t0
print("\nSimulation completed in %f s" % tdelta)

###############################################################################
# Plot data
###############################################################################

osc_sig_full = make_signal(td=osc_out[len(osc_out) / 2:], fs=FS)
osc_sig = make_signal(td=osc_out[PLOT_SLICE], fs=FS)
clk_sig = make_signal(td=clk_out[PLOT_SLICE], fs=FS)
lf_sig = make_signal(td=lf_out[PLOT_SLICE], fs=FS)
div_sig = make_signal(td=div_out[PLOT_SLICE], fs=FS)
tdc_sig = make_signal(td=tdc_out[PLOT_SLICE], fs=FS)

plt.subplot(2, 3, 1)
plot_td(clk_sig, title="CLK")
# razavify()
plt.subplot(2, 3, 2)
plot_td(osc_sig, title="DCO")
# razavify()
plt.subplot(2, 3, 3)
plot_td(div_sig, title="DIV")
# razavify()
Exemple #9
0
    data.append([])
    for LSB_DF in np.geomspace(1e-6, 1e-3, 7):
        TREF = 1/float(FREF)
        dith = np.zeros(SA)
        for n in range(SA):
            trel = n*TSTEP/TREF - int(n*TSTEP/TREF)
            if trel >= 0 and trel < 0.5:
                dith[n] = 1

        phase = np.zeros(SA)
        for n in range(1, SA):
            phase[n] = phase[n-1] + 2*np.pi*((F0-LSB_DF/2)+LSB_DF*dith[n])*TSTEP

        td = np.sin(phase)

        sig = make_signal(td=td, fs = F0*SA_CYC)

        # plot_pn_ssb(sig, f0=F0, fref=FREF)
        #print(20*np.log10(eval_model_pn(sig, F0, PN_DF)))
        data[-1].append(20*np.log10(meas_ref_spur(sig, F0, FREF)))
print(data)
data[-1][-1] = 0
# plt.xscale("log")
# plt.yscale("log")
plt.imshow(data, interpolation="gaussian", extent=[-6, -3, -3, -1])
plt.colorbar()
CS = plt.contour(data, levels=[-120, -100, -80, -60, -40, -20], extent=[-6,-3,-1,-3], colors="w")
plt.clabel(CS, inline=1, fontsize=8)
plt.xticks([-6, -5, -4, -3], ["1e-6", "1e-5", "1e-4", "1e-3"])
plt.yticks([-3, -2, -1], ["1e-3", "1e-2", "1e-1"])
plt.xlabel("DCO LSB Resolution f_lsb/f0")
Exemple #10
0
_D = np.abs(D)

# Use DCO class model

krwro = ro_rw_model_param(f0=F0,
                          power=50e-6,
                          temp=293,
                          n=SAMPLES,
                          tstep=1.0 / FS)
dco = DCO(kdco=1, f0=F0, dt=1.0 / FS, krwro=krwro)
e = np.zeros(SAMPLES)
for n in range(SAMPLES):
    e[n] = dco.update(fctrl=100e6)

#sig_c = make_signal(td=c, fs=FS)
sig_d = make_signal(td=d, fs=FS)
sig_e = make_signal(td=e, fs=FS)

plot_pn_ssb(sig_d, f0=F0, dfmax=10e6)
plot_pn_ssb(sig_e, f0=F0 + 100e6, dfmax=10e6)

#print(20*np.log10(eval_model_pn(sig_c, 0, PN_DF)))
meas = 20 * np.log10(eval_model_pn(sig_d, F0, PN_DF))
equ = 10 * np.log10(phase_noise_est(K, SAMPLES, PN_DF, 1.0 / FS))
print("Meas=%.2f, theory=%.2f, delta=%.2f" % (meas, equ, meas - equ))
meas_dco = 20 * np.log10(eval_model_pn(sig_e, F0 + 100e6, PN_DF))
print("Meas dco=%.2f" % meas_dco)
# plt.plot(20*np.log10(_A))
# plt.plot(20*np.log10(_B))
# plt.plot(20*np.log10(_C))
# plt.plot(20*np.log10(_D))
Exemple #11
0
fs = 16e6
dt = 1 / fs

steps = 100000

pn = 10**(-80 / 10)
df = 1e6

krw = rw_gain(pn, df, steps, dt, m=1)
print("krw=", krw)
dco = DCO(kdco, f0, dt, krw=krw)

osc_sig = np.zeros(steps)
for n in range(steps):
    osc_sig[n] = dco.update(fctrl=0)

osc_sig = make_signal(td=osc_sig, fs=fs)

plot_pn_ssb2(osc_sig, line_fit=True)
#plot_pn_ar_model(osc_sig)
plt.legend()
plt.title(
    "DCO SSB Phase Noise [dBc/Hz],\n $\mathtt{krw}$ fitted to $L(\Delta f=10^6)$ = -80 dBc/Hz"
)
razavify(loc="lower left", bbox_to_anchor=[0, 0])
plt.xticks([1e2, 1e3, 1e4, 1e5, 1e6, 1e7],
           ["$10^2$", "$10^3$", "$10^4$", "$10^5$", "$10^6$", "$10^7$"])

plt.tight_layout()
plt.savefig("dco_rw_pn.pdf")
Exemple #12
0
freqs = np.geomspace(1e3, 8e6, 1000)
ntdc = pow_ntdc_post_lf(freqs, lf_params, FCLK)
plt.semilogx(freqs, 10 * np.log10(ntdc), label="TDC noise")
mses = []
bit_range = range(MIN_BITS - OPT_INT_BITS - 1, MAX_BITS - OPT_INT_BITS)
for frac_bits in bit_range:
    lf_quant = LoopFilterIIRPhase(ignore_clk=True,
                                  int_bits=INT_BITS,
                                  frac_bits=frac_bits,
                                  quant_filt=False,
                                  **lf_params)
    filt_quant = np.zeros(SIM_STEPS)
    for n in range(SIM_STEPS):
        filt_quant[n] = lf_quant.update(x[n], 0)

    sig = make_signal(td=filt_quant, fs=FCLK)
    plot_pn_ar_model(sig, fmin=1e3)
    mse = np.var(filt_ideal - filt_quant)
    print(mse)
    mses.append(mse)
plt.show()
foo()
# plt.semilogy(np.array(bit_range)+OPT_INT_BITS+1, mses)
# plt.ylim((-1,1000))
# plt.xlim(MIN_BITS, MAX_BITS)
# plt.xlabel("Data word length [bits]")
# plt.ylabel("Quantization noise power [LSB^2]")
# plt.title("Loop filter quantization noise versus data word length,\n Two's complement fixed point representation")
# plt.grid()
# razavify()
# plt.tight_layout()
Exemple #13
0
# krw = 4*np.pi*np.sqrt(FS*s0)/np.sqrt((2*FS)**2 + (2*np.pi*PN_DF)**2)
# krw = 2*np.pi*np.sqrt(s0/FS)
krw = rw_gain_fom(fom_db=DCO_FOM, fosc=FOSC, power=DCO_POWER, fs=FS)
print("krw =", krw)
error = np.zeros(SIM_STEPS)
dco1 = DCOPhase(kdco1=0, kdco2=0, f0=FL_DCO, dt=1/float(FS), krw=krw,
               init_phase=0, quantize=False)
dco2 = DCOPhase(kdco1=0, kdco2=0, f0=FL_DCO, dt=1/float(FS), krw=0,
               init_phase=0, quantize=False)
for n in range(SIM_STEPS):
    error[n] = dco1.update(0,0)-dco2.update(0,0)
# print(error)
# plt.plot(error)


E = np.fft.fft(error)/np.sqrt(FS*SIM_STEPS)
plt.semilogx(f, 20*np.log10(np.abs(E[1:int(0.5*SIM_STEPS)])))
# plt.show()
K = np.average(np.abs(E[1:int(0.5*SIM_STEPS)])**2*f**2)
print("Fitted pn @ 1MHz = ", 10*np.log10(K/1e6**2))
print("rms_error =", np.std(error))
print("predicted rms error =", np.sqrt(2*K*(1/FBIN - 1/(0.5*FS))))
# plt.plot(K)
# plt.show()

pn_sig = make_signal(error, fs=FS)
plot_pn_ssb2(pn_sig, dfmax=PN_FMAX, line_fit=False, tmin=0)
plot_pn_ar_model(pn_sig, p=200, tmin=0)
plt.show()

Exemple #14
0
# phase_noise = osc_out-DIV_N*clk_out
# pn_sig_full = make_signal(td=phase_noise[int(len(phase_noise)/2):], fs=FS)
# pn_sig = make_signal(td=phase_noise[PLOT_SLICE], fs=FS)

# osc_sig_full = make_signal(td=osc_out[len(osc_out)/2:], fs=FS)
# osc_freq = make_signal(td=np.diff(osc_out[PLOT_SLICE])/(2*np.pi*DT), fs=FS)
# clk_sig = make_signal(td=clk_out[PLOT_SLICE], fs=FS)
# lf_sig = make_signal(td=lf_out[PLOT_SLICE], fs=FS)
# div_sig = make_signal(td=div_out[PLOT_SLICE], fs=FS)
# tdc_sig = make_signal(td=tdc_out[PLOT_SLICE], fs=FS)
# bbpd_sig = make_signal(td=bbpd_out[PLOT_SLICE], fs=FS)
# error_sig = make_signal(td=error[PLOT_SLICE], fs=FS)

phase_noise = sim_data["osc"]-DIV_N*sim_data["clk"]
pn_sig_full = make_signal(td=phase_noise[int(len(phase_noise)/2):], fs=FS)
pn_sig = make_signal(td=phase_noise[PLOT_SLICE], fs=FS)

osc_freq = make_signal(td=np.diff(sim_data["osc"][PLOT_SLICE])/(2*np.pi*DT), fs=FS)
lf_sig = make_signal(td=sim_data["lf"][PLOT_SLICE], fs=FS)
tdc_sig = make_signal(td=sim_data["tdc"][PLOT_SLICE], fs=FS)
bbpd_sig = make_signal(td=sim_data["bbpd"][PLOT_SLICE], fs=FS)
error_sig = make_signal(td=sim_data["error"][PLOT_SLICE], fs=FS)

# plt.subplot(2,3,1)
# plot_td(clk_sig, title="CLK")
# razavify()
plt.figure(3)
plt.subplot(2,3,1)
plot_td(osc_freq, title="Inst. DCO Frequency")
# razavify()
Exemple #15
0
def meas_inst_freq(signal):
    return make_signal(td=signal.fs * np.diff(signal.td) / (2 * np.pi),
                       fs=signal.fs)
Exemple #16
0
    # Simulation loop
    ###############################################################################

    t0 = time.clock()
    for n in range(SAMPLES)[1:]:
        osc_out[n] = dco.update(lf_out[n - 1])
        div_out[n] = osc_out[n] / float(DIV_N)
        clk_out[n] = clk.update()
        tdc_out[n] = tdc.update(clk=clk_out[n], xin=div_out[n])
        bbpd_out[n] = bbpd.update(clk=clk_out[n], xin=div_out[n])
        error[n] = tdc_out[n] + KBBPD * bbpd_out[n]
        lf_out[n] = lf.update(xin=error[n])
    tdelta = time.clock() - t0
    print("\nSimulation completed in %f s" % tdelta)

    lf_sig = make_signal(td=lf_out[PLOT_SLICE], fs=FS)
    osc_freq = make_signal(td=np.diff(osc_out[PLOT_SLICE]) / (2 * np.pi * DT),
                           fs=FS)
    plt.subplot(1, 2, 1)
    plot_td(osc_freq, title="Inst. DCO Frequency")
    plt.subplot(1, 2, 2)
    plot_td(lf_sig, title="Loop Filter Output")

plt.show()
foo()

# plt.subplot(2,3,1)
# plt.plot(osc_out,)
# plt.title("DCO")
# plt.subplot(2,3,2)
# plt.plot(div_out,)
Exemple #17
0
def plot_pllsim_lf_inst_freq(pllsim_data):
    inst_freq = make_signal(td=pllsim_data["lf"].td*pllsim_data["params"]["kdco"], fs = pllsim_data["lf"].fs)
    plot_td(inst_freq)
    plt.ylabel("Frequency [Hz]")