def plot_lf_ideal_pn_full(div_jit, pn_dco, pn_dco_df, kdco, fclk, _type, m, n, k, fz, fp, delay, b1, b2, steps=100, fmin=1e1, fmax=1e7, *args, **kwargs): df = fmax/steps freqs = np.geomspace(fmin, fmax, int(steps)) lf_params = dict(_type=_type, k=k, fz=fz, fp=fp, delay=delay) # a = pll_otf2(freqs, M, N, KDCO, KP, FZ, FP, DELAY) g = pll_tf(freqs, _type, k, fz, fp, delay) # g = a/(1+a) 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, pn_dco, pn_dco_df)*np.abs(1-g)**2 ntdc = tdc_pn(fclk, n, m, g) # ntdc = tdc_pn(fclk, n, g, 1/float(m*fclk)) nlf = lf_pn(freqs, fclk, lf_params, kdco, b1, b2) ndiv = div_pn(fclk, n, div_jit, g) plt.semilogx(freqs, 10*np.log10(ntdc), label="TDC") plt.semilogx(freqs, 10*np.log10(ndco), label="DCO") plt.semilogx(freqs, 10*np.log10(nlf), label="Loop filter") plt.semilogx(freqs, 10*np.log10(ndiv), label="Divider") plt.semilogx(freqs, 10*np.log10(ndco+ntdc+nlf+ndiv), label="Total") plt.legend() plt.grid() plt.title("SSB Phase noise") plt.xlabel("Frequency [Hz]") plt.ylabel("Phase noise [dBc]")
def var_ntdc_post_lf(lf_params, steps=513): fclk = lf_params["fclk"] freqs = np.linspace(0, fclk / 2, steps) g = pll_tf(freqs, **lf_params) ntf_tdc_lf = (lf_params["n"] / lf_params["m"]) * (2j * np.pi * freqs / lf_params["kdco"]) * g return 2 * scipy.integrate.romb( abs(ntf_tdc_lf)**2 * (1 / (12 * fclk)), 0.5 * fclk / steps)
def plot_pll_tf(k, fz, fp, _type, delay, steps=100, fmax=1e7, *args, **kwargs): freqs = np.geomspace(1, fmax, int(steps)) g = pll_tf(freqs, _type, k, fz, fp, delay) # g = a/(1+a) plt.subplot(1,3,1) plt.semilogx(freqs, 20*np.log10(np.abs(g)), label="G(f)") plt.semilogx(freqs, 20*np.log10(np.abs(1-g)), label="1-G(f)") plt.legend() plt.grid() plt.title("Closed loop responses") plt.xlabel("Frequency [Hz]") plt.ylabel("Gain [dB]")
def plot_loop_filter(pn_dco, pn_dco_df, fclk, _type, m, n, k, ki, fz, fp, delay, bw, a0, a1, b0, b1, b2, mode="tdc", sigma_ph=0.1, steps=100, fmax=1e7, *args, **kwargs): freqs = np.geomspace(1, fmax, int(steps)) # a = pll_otf2(freqs, M, N, KDCO, KP, FZ, FP, DELAY) g = pll_tf(freqs, _type, k, fz, fp, delay) # g = a/(1+a) kpn = pn_dco*pn_dco_df**2 plt.subplot(1,3,1) # plt.semilogx(freqs, 20*np.log10(np.abs(solpf(freqs, fn, damping))), label="Ideal") plt.semilogx(freqs, 20*np.log10(np.abs(g)), label="G(f)") plt.semilogx(freqs, 20*np.log10(np.abs(1-g)), label="1-G(f)") plt.legend() plt.grid() plt.title("Closed loop responses") plt.xlabel("Frequency [Hz]") plt.ylabel("Gain [dB]") plt.subplot(1,3,2) # ndco = min_ro_pn(fclk*n, freqs, pn_dco, pn_dco_df)*np.abs(1-g)**2 ndco = np.abs(1-g)**2*kpn/freqs**2 ndco[np.where(g==1)] = 0 # ntdc = tdc_pn(fclk, n, g, 1/float(m*fclk)) if mode is "tdc": ntdc = tdc_pn(fclk, n, m, g) if mode is "bbpd": ntdc = bbpd_pn(fclk, n, sigma_ph, g) plt.semilogx(freqs, 10*np.log10(ntdc), label="TDC") plt.semilogx(freqs, 10*np.log10(ndco), label="DCO") plt.semilogx(freqs, 10*np.log10(ndco+ntdc), label="Combined") plt.legend() plt.grid() plt.title("SSB Phase noise") plt.xlabel("Frequency [Hz]") plt.ylabel("Phase noise [dBc]") plt.subplot(1,3,3) w, h = scipy.signal.freqz([a0, a1], [b0, b1, b2], fs=fclk) _h = lf(w[1:], _type, ki, fz, fp) plt.title("Ideal versus discrete loop filter") plt.xlabel("Frequency [Hz]") plt.ylabel("Gain [dB]") plt.semilogx(w[1:], 20*np.log10(np.abs(h[1:])), label="Discrete") plt.semilogx(w[1:], 20*np.log10(np.abs(_h)), label="Ideal") plt.grid() plt.legend()
def plot_tdc_pn(pn_dco, pn_dco_df, fclk, _type, m, n, k, ki, fz, fp, delay, bw, a0, a1, b0, b1, b2, steps=100, fmax=1e7, label="", *args, **kwargs): freqs = np.geomspace(1, fmax, int(steps)) # a = pll_otf2(freqs, M, N, KDCO, KP, FZ, FP, DELAY) g = pll_tf(freqs, _type, k, fz, fp, delay) # g = a/(1+a) ntdc = tdc_pn(fclk, n, m, g) # ntdc = tdc_pn(fclk, n, g, 1/float(m*fclk)) plt.semilogx(freqs, 10*np.log10(ntdc), label="TDC %s"%label) plt.legend() plt.grid() plt.title("SSB Phase noise") plt.xlabel("Frequency [Hz]") plt.ylabel("Phase noise [dBc]")
def plot_dco_pn(pn_dco, pn_dco_df, fclk, _type, m, n, k, ki, fz, fp, delay, bw, a0, a1, b0, b1, b2, steps=100, fmax=1e7, label="", *args, **kwargs): freqs = np.geomspace(1, fmax, int(steps)) # a = pll_otf2(freqs, M, N, KDCO, KP, FZ, FP, DELAY) g = pll_tf(freqs, _type, k, fz, fp, delay) # g = a/(1+a) kpn = pn_dco*pn_dco_df**2 # ndco = min_ro_pn(fclk*n, freqs, pn_dco, pn_dco_df)*np.abs(1-g)**2 ndco = np.abs(1-g)**2*kpn/freqs**2 ndco[np.where(g==1)] = 0 plt.semilogx(freqs, 10*np.log10(ndco), label="DCO %s"%label) plt.legend() plt.grid() plt.title("SSB Phase noise") plt.xlabel("Frequency [Hz]") plt.ylabel("Phase noise [dBc]")
def pow_ntdc_post_lf(freqs, lf_params, fclk, steps=513): g = pll_tf(freqs, **lf_params) ntf_tdc_lf = (lf_params["n"] / lf_params["m"]) * (2j * np.pi * freqs / lf_params["kdco"]) * g return abs(ntf_tdc_lf)**2 * (1 / (12))