コード例 #1
0
    np.where
    int_ntdc = np.cumsum(ntdc)*df
    int_ndco = np.cumsum(_ndco)*df
    int_ncomb = np.cumsum(_ncomb)*df
    f_ber = FREQS[np.where(1+2*int_ncomb > (1-2*BER)*(1+2*int_ncomb[-1]))[-1][0]]
    print("*** ", f_ber)
    tdc_steps.append(1.0/(16e6*_max_tdel))
    f_bers.append(f_ber)

plt.subplot(2,1,1)
plt.semilogx(FNS, f_bers, color="k")
plt.title("Offset from carrier containing 99% of power\n vs Closed loop PLL bandwidth")
plt.xlabel("Loop bandwidth [Hz]")
plt.ylabel("99% Power Offset [Hz]")
#plt.grid()
razavify()

plt.subplot(2,1,2)
plt.semilogx(FNS, tdc_steps, color="k")
plt.title("Minimum number of TDC steps required\n vs PLL closed loopbandwidth")
plt.xlabel("Loop bandwidth [Hz]")
plt.ylabel("Minimum TDC steps")
#plt.grid()
razavify()
adjust_subplot_space(2,1)
plt.show()
# plt.subplot(1,3,1)
# plt.semilogx(FREQS, 20*np.log10(np.abs(g)), label="TDC noise")
# plt.semilogx(FREQS, 20*np.log10(np.abs(1-g)**2), label="DCO noise")
# plt.xlabel("Frequency [Hz]")
# plt.ylabel("Magnitude response [dB]")
コード例 #2
0
ファイル: rand_walk_pn_plot.py プロジェクト: nielscol/pllsim
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")
コード例 #3
0
main_pn_data = sim_data["sim_data"]

if False:
    plt.legend()
    # plt.axhline(9990, color="r")
    # plt.axhline(10010, color="r")
    plot_td(main_pn_data["lf"], title="Loop Filter Output", tmax=50e-6)
    plt.title("PLL loop filter transient response")
    plt.ylabel("Loop filter output")
    plt.xlabel("Time [$\mu$s]")
    plt.ylim((9000, 10500))
    # plt.ylim((8800, 10300))
    # plt.plot((23e-6,23e-6),(8800, 9990), color="b", linestyle="--")
    # plt.text(25e-6, 10030, "Lock tolerance band", color="r", fontsize=12)
    # plt.text(23.5e-6, 9500, "Lock time", color="b", fontsize=12, rotation=90)
    razavify(loc="lower left", bbox_to_anchor=[0, 0])
    plt.xticks([0, 0.5e-5, 1e-5, 1.5e-5, 2e-5], ["0", "5", "10", "15", "20"])
    plt.yticks(
        [9000, 9200, 9400, 9600, 9800, 10000, 10200, 10400],
        ["9000", "9200", "9400", "9600", "9800", "10000", "12000", "14000"])
    plt.xlim((0, 2e-5))
    plt.tight_layout()
    plt.savefig("trans_loop_filter_fast.pdf")
    plt.show()
    # foo()
    foo()
#
#
# plt.clf()
# plt.cla()
if False:
コード例 #4
0
ファイル: test_bbpd_loop.py プロジェクト: nielscol/pllsim
                 tmin=GEAR_SW_T * PN_CALC_SAFETY_FACTOR,
                 label="$\\phi_n$")
# rpm = noise_power_ar_model(pn_sig, fmax=FCLK/2, p=200, tmin=GEAR_SW_T)
# print("int rpm = ", np.sqrt(rpm))

plot_pn_ar_model(em_pn,
                 p=200,
                 fmin=FBIN,
                 tmin=GEAR_SW_T * PN_CALC_SAFETY_FACTOR,
                 label="$\\phi_{em}$")
plot_pi_pll_bbpd_pn(fmin=FBIN, **lfs["bbpd"])
plot_pi_pll_osc_pn(DCO_PN, DCO_PN_DF, fmin=FBIN, **lfs["bbpd"])
# plot_osc_pn_ideal(DCO_PN, DCO_PN_DF)
plt.legend()
# ticks = plt.xticks()[0]
razavify(loc="lower center", bbox_to_anchor=[0.5, 0], legend_cols=1)
ticks = np.geomspace(1e3, 1e6, 4)
_ticks = ["$10^{%d}$" % np.log10(x) for x in ticks]
plt.xticks(ticks, _ticks)
ticks = np.linspace(-140, -80, 7)
_ticks = ["%.0f" % x for x in ticks]
plt.yticks(ticks, _ticks)
plt.xlim((FBIN, FS / 2))

plt.figure(3)
xticks = np.linspace(0, 20e-6, 5)
plt.subplot(3, 1, 1)
plot_td(sim_data["lf"], tmax=PLOT_SPAN, title="", dots=False)
plt.ylabel("LF Out")
plt.title("Loop Filter Output and Fine/Med DCO Codes")
razavify(legend=False)
コード例 #5
0
ファイル: opt_lf_bits.py プロジェクト: nielscol/pllsim
def opt_lf_num_bits(lf_params,
                    min_bits,
                    max_bits,
                    rms_filt_error=0.1,
                    noise_figure=1,
                    sim_steps=1000,
                    sim_runs=10,
                    fpoints=512,
                    mode="tdc",
                    sigma_ph=0.1,
                    tdc_in_stdev=1,
                    plot=False):
    """ optimize number of bits for a digital direct form-I implementation using two's complement
        representation fixed point words with all parts of the data path with same data representation
        args:
            noise_figure: the maximum dB increase in noise due to loop filter quantization
            rms_filt_error : RMS value in dB for allowable filter error
    """
    print("\n********************************************************")
    print("Optimizing loop filter digital direct form-I implementation for")
    print("number of bits in fixed point data words utilized")
    sign_bits = 1
    # fint number of integer bits needed
    int_bits = n_int_bits(lf_params)
    print("\n* Integer bits = %d" % int_bits)
    """ Optimization for quantization noise
    """
    print("\n* Optimizing for quantization noise:")
    # find optimal number of bits for quantization noise
    # generate white noise signal w simulating "regular" activity
    if lf_params["mode"] == "tdc":
        # w = np.floor(np.random.normal(0, 0.1*lf_params["m"], sim_steps))
        w = np.floor(np.random.normal(0, tdc_in_stdev, sim_steps))
    else:  # BBPD mode, test sequence is random +/- 1
        # w = np.random.normal(0, np.sqrt((1-2/np.pi)), sim_steps)
        w = np.random.choice((-1, 1), sim_steps)  # ate

    pow_npd_post_lf = var_npd_post_lf(
        lf_params, mode=mode)  # variance of TDC noise at loop filter

    lf_ideal = LoopFilterPIPhase(ignore_clk=True, **lf_params)
    x_ideal = np.zeros(sim_steps)
    for n in range(sim_steps):
        x_ideal[n] = lf_ideal.update(w[n], 0)

    mses = []
    bit_range = range(min_bits - int_bits - 1, max_bits - int_bits)
    for frac_bits in bit_range:
        # use a large number of int bits to avoid overflow. Tuning here is with frac bits as
        runs = np.zeros(sim_runs)
        for m in range(sim_runs):
            lf_quant = LoopFilterPIPhase(ignore_clk=True,
                                         int_bits=32,
                                         frac_bits=frac_bits,
                                         quant_filt=False,
                                         **lf_params)
            x_quant = np.zeros(sim_steps)
            for n in range(sim_steps):
                x_quant[n] = lf_quant.update(w[n], 0)
            runs[m] = np.var(x_ideal - x_quant)
            mse = np.average(runs)
        print(
            "\tBits = %d,\t #(sign,int,frac) = (%d,%d,%d), \tQuant noise power = %E LSB^2"
            % ((sign_bits + int_bits + frac_bits), sign_bits, int_bits,
               frac_bits, mse))
        mses.append(mse)
    threshold = (10**(noise_figure / 10.0) - 1) * pow_npd_post_lf
    print("Threshold=%E, PD noise post-LF=%E" % (threshold, pow_npd_post_lf))
    for n, v in enumerate(mses):
        if v < threshold:
            break
    opt_frac_bits_qn = bit_range[n]
    print(
        "* Optimum int bits = %d, frac bits = %d, sign bits = 1, quant noise = %.3f LSB^2"
        % (int_bits, opt_frac_bits_qn, mses[n]))
    if plot:
        plt.figure(1)
        plt.clf()
        plt.semilogy(np.arange(min_bits, max_bits + 1), mses)
        plt.title("RMS Quantization Noise versus Filter Coefficient Bits")
        plt.xlabel("Total bits")
        plt.grid()
        plt.ylabel("DAC LSB$^2$")
        razavify()
        ticks = plt.yticks()[0]
        plt.yticks(ticks,
                   ["10$^{%d}$" % int(round(np.log10(x))) for x in ticks])
        plt.xlim(min_bits, max_bits)
        ticks = plt.xticks()[0]
        plt.xticks(ticks, ["%d" % x for x in ticks])

    #////////////////////////////////////////////////////////////////////////////////////
    """ Optimization for filter accuracy
    """
    print("\n* Optimizing for filter design accuracy:")
    fmin = 1e2
    fref = lf_params["fref"]

    b = [lf_params["b0"], lf_params["b1"]]
    a = [
        1,
        -1,
    ]
    f, h_ideal = scipy.signal.freqz(b,
                                    a,
                                    np.geomspace(fmin, fref / 2, fpoints),
                                    fs=fref)
    s = 2j * np.pi * f
    l = 2 * np.pi * lf_params["kpd"] * lf_params["kdco"] * h_ideal / s
    g = l / (1 + l)
    bit_range = range(min_bits - int_bits - 1, max_bits - int_bits)
    mses = []
    # print(lf_params["b0"], lf_params["b1"])
    for frac_bits in bit_range:
        _lf_params = quant_lf_params(lf_params, int_bits, frac_bits)
        b = [_lf_params["b0"], _lf_params["b1"]]
        # print(_lf_params["b0"], _lf_params["b1"])
        f, h = scipy.signal.freqz(b,
                                  a,
                                  np.geomspace(fmin, fref / 2, fpoints),
                                  fs=fref)
        s = 2j * np.pi * f
        l = 2 * np.pi * lf_params["kpd"] * lf_params["kdco"] * h / s
        _g = l / (1 + l)
        # mses.append(np.var(20*np.log10(np.abs(h[1:]))-20*np.log10(np.abs(h_ideal[1:]))))
        mses.append(
            np.var(20 * np.log10(np.abs(g[1:])) -
                   20 * np.log10(np.abs(_g[1:]))))
        # print("\tN bits = %d\tMSE = %E dB^2"%(frac_bits+int_bits+sign_bits, mses[-1]))
        print(
            "\tBits = %d,\t #(sign,int,frac) = (%d,%d,%d), \tMSE = %E LSB^2" %
            ((sign_bits + int_bits + frac_bits), sign_bits, int_bits,
             frac_bits, mses[-1]))
    n = len(mses) - 1
    for n, v in enumerate(mses):
        if v < rms_filt_error**2:
            break
    opt_frac_bits_filt_acc = bit_range[n]
    print(
        "* Optimum int bits = %d, frac bits = %d, sign_bits=1, quant noise = %E LSB^2"
        % (int_bits, opt_frac_bits_filt_acc, mses[n]))
    if plot:
        plt.figure(2)
        plt.clf()
        plt.semilogy(np.arange(min_bits, max_bits + 1), mses)
        plt.title("MSE Filter Error (dB) versus Filter Coefficient Bits")
        plt.xlabel("Total bits")
        plt.ylabel("MSE [dB$^2$]")
        plt.grid()
        razavify()
        ticks = plt.yticks()[0]
        plt.yticks(ticks,
                   ["10$^{%d}$" % int(round(np.log10(x))) for x in ticks])
        plt.xlim(min_bits, max_bits)
        ticks = plt.xticks()[0]
        plt.xticks(ticks, ["%d" % x for x in ticks])

    frac_bits = max(opt_frac_bits_qn, opt_frac_bits_filt_acc)
    print("\n* Optimization complete:")
    print("\tInt bits = %d, frac bits = %d, sign bits = 1" %
          (int_bits, frac_bits))
    print("\tTotal number bits = %d" % (int_bits + frac_bits + sign_bits))
    return int_bits, frac_bits