def _make_circuit(cls,
                      env_idx,
                      gm_db,
                      load_db,
                      vtail,
                      vg,
                      vmid,
                      vout,
                      vbias,
                      vb_gm,
                      vb_load,
                      cload,
                      cpar1,
                      w_dict,
                      th_dict,
                      stack_dict,
                      seg_dict,
                      gz,
                      neg_cap=False,
                      no_fb=False):

        cur_env = gm_db.env_list[env_idx]
        gm_db.set_dsn_params(w=w_dict['tail'],
                             intent=th_dict['tail'],
                             stack=stack_dict['tail'])
        tail1_params = gm_db.query(env=cur_env,
                                   vbs=0,
                                   vds=vtail - vb_gm,
                                   vgs=vbias - vb_gm)
        tail2_params = gm_db.query(env=cur_env,
                                   vbs=0,
                                   vds=vout - vb_gm,
                                   vgs=vbias - vb_gm)
        gm_db.set_dsn_params(w=w_dict['in'],
                             intent=th_dict['in'],
                             stack=stack_dict['in'])
        gm1_params = gm_db.query(env=cur_env,
                                 vbs=vb_gm - vtail,
                                 vds=vmid - vtail,
                                 vgs=vg - vtail)
        load_db.set_dsn_params(w=w_dict['load'],
                               intent=th_dict['load'],
                               stack=stack_dict['diode'])
        diode1_params = load_db.query(env=cur_env,
                                      vbs=0,
                                      vds=vmid - vb_load,
                                      vgs=vmid - vb_load)
        diode2_params = load_db.query(env=cur_env,
                                      vbs=0,
                                      vds=vout - vb_load,
                                      vgs=vmid - vb_load)
        load_db.set_dsn_params(stack=stack_dict['ngm'])
        ngm1_params = load_db.query(env=cur_env,
                                    vbs=0,
                                    vds=vmid - vb_load,
                                    vgs=vmid - vb_load)
        ngm2_params = load_db.query(env=cur_env,
                                    vbs=0,
                                    vds=vout - vb_load,
                                    vgs=vmid - vb_load)

        cir = LTICircuit()
        # stage 1
        cir.add_transistor(tail1_params,
                           'tail',
                           'gnd',
                           'gnd',
                           'gnd',
                           fg=seg_dict['tail1'],
                           neg_cap=neg_cap)
        cir.add_transistor(gm1_params,
                           'midp',
                           'inn',
                           'tail',
                           'gnd',
                           fg=seg_dict['in'],
                           neg_cap=neg_cap)
        cir.add_transistor(gm1_params,
                           'midn',
                           'inp',
                           'tail',
                           'gnd',
                           fg=seg_dict['in'],
                           neg_cap=neg_cap)
        cir.add_transistor(diode1_params,
                           'midp',
                           'midp',
                           'gnd',
                           'gnd',
                           fg=seg_dict['diode1'],
                           neg_cap=neg_cap)
        cir.add_transistor(diode1_params,
                           'midn',
                           'midn',
                           'gnd',
                           'gnd',
                           fg=seg_dict['diode1'],
                           neg_cap=neg_cap)
        cir.add_transistor(ngm1_params,
                           'midn',
                           'midp',
                           'gnd',
                           'gnd',
                           fg=seg_dict['ngm1'],
                           neg_cap=neg_cap)
        cir.add_transistor(ngm1_params,
                           'midp',
                           'midn',
                           'gnd',
                           'gnd',
                           fg=seg_dict['ngm1'],
                           neg_cap=neg_cap)

        # stage 2
        cir.add_transistor(tail2_params,
                           'outp',
                           'gnd',
                           'gnd',
                           'gnd',
                           fg=seg_dict['tail2'],
                           neg_cap=neg_cap)
        cir.add_transistor(tail2_params,
                           'outn',
                           'gnd',
                           'gnd',
                           'gnd',
                           fg=seg_dict['tail2'],
                           neg_cap=neg_cap)
        cir.add_transistor(diode2_params,
                           'outp',
                           'midn',
                           'gnd',
                           'gnd',
                           fg=seg_dict['diode2'],
                           neg_cap=neg_cap)
        cir.add_transistor(diode2_params,
                           'outn',
                           'midp',
                           'gnd',
                           'gnd',
                           fg=seg_dict['diode2'],
                           neg_cap=neg_cap)
        cir.add_transistor(ngm2_params,
                           'outp',
                           'midn',
                           'gnd',
                           'gnd',
                           fg=seg_dict['ngm2'],
                           neg_cap=neg_cap)
        cir.add_transistor(ngm2_params,
                           'outn',
                           'midp',
                           'gnd',
                           'gnd',
                           fg=seg_dict['ngm2'],
                           neg_cap=neg_cap)

        # parasitic cap
        cir.add_cap(cpar1, 'midp', 'gnd')
        cir.add_cap(cpar1, 'midn', 'gnd')
        # load cap
        cir.add_cap(cload, 'outp', 'gnd')
        cir.add_cap(cload, 'outn', 'gnd')
        # feedback resistors
        if not no_fb:
            cir.add_conductance(gz, 'xp', 'midn')
            cir.add_conductance(gz, 'xn', 'midp')
        # diff-to-single conversion
        cir.add_vcvs(0.5, 'inp', 'gnd', 'in', 'gnd')
        cir.add_vcvs(-0.5, 'inn', 'gnd', 'in', 'gnd')
        cir.add_vcvs(1, 'out', 'gnd', 'outp', 'outn')

        return cir
Beispiel #2
0
def characterize_casc_amp(env_list,
                          lch,
                          intent_list,
                          fg_list,
                          w_list,
                          db_list,
                          vbias_list,
                          vload_list,
                          vtail_list,
                          vmid_list,
                          vincm,
                          voutcm,
                          vdd,
                          vin_clip,
                          clip_ratio_min,
                          cw,
                          rw,
                          fanout,
                          ton,
                          k_settle_targ,
                          scale_min=0.25,
                          scale_max=20):
    # compute DC transfer function curve and compute linearity spec
    ndb, pdb = db_list[0], db_list[-1]
    results = solve_casc_diff_dc(env_list,
                                 ndb,
                                 pdb,
                                 lch,
                                 intent_list,
                                 w_list,
                                 fg_list,
                                 vbias_list,
                                 vload_list,
                                 vtail_list,
                                 vmid_list,
                                 vdd,
                                 vincm,
                                 voutcm,
                                 vin_clip,
                                 clip_ratio_min,
                                 num_points=20)
    vmat_list, ratio_list, gain_list = results
    # compute settling ratio
    fg_tail, fg_in, fg_casc, fg_load = fg_list
    db_tail, db_in, db_casc, db_load = db_list
    w_tail, w_in, w_casc, w_load = w_list
    fzin = 1.0 / (2 * ton)
    wzin = 2 * np.pi * fzin
    tvec = np.linspace(0, ton, 200, endpoint=True)
    scale_list = []
    cin_list = []
    for env, vbias, vload, vtail, vmid, vmat in zip(env_list, vbias_list,
                                                    vload_list, vtail_list,
                                                    vmid_list, vmat_list):
        # step 1: get half circuit parameters and compute input capacitance
        in_par = db_in.query(env=env,
                             w=w_in,
                             vbs=-vtail,
                             vds=vmid - vtail,
                             vgs=vincm - vtail)
        casc_par = db_casc.query(env=env,
                                 w=w_casc,
                                 vbs=-vmid,
                                 vds=voutcm - vmid,
                                 vgs=vdd - vmid)
        load_par = db_load.query(env=env,
                                 w=w_load,
                                 vbs=0,
                                 vds=voutcm - vdd,
                                 vgs=vload - vdd)
        cir = LTICircuit()
        cir.add_transistor(in_par, 'mid', 'in', 'gnd', fg=fg_in)
        cir.add_transistor(casc_par, 'out', 'gnd', 'mid', fg=fg_casc)
        cir.add_transistor(load_par, 'out', 'gnd', 'gnd', fg=fg_load)
        zin = cir.get_impedance('in', fzin)
        cin = (1 / zin).imag / wzin
        cin_list.append(cin)
        # step 3A: construct differential circuit with vin_clip / 2.
        vts, vmps, vmns, vops, vons = vmat[-1, :]
        vinp = vincm + vin_clip / 4
        vinn = vincm - vin_clip / 4
        tail_par = db_tail.query(env=env, w=w_tail, vbs=0, vds=vts, vgs=vbias)
        inp_par = db_in.query(env=env,
                              w=w_in,
                              vbs=-vts,
                              vds=vmns - vts,
                              vgs=vinp - vts)
        inn_par = db_in.query(env=env,
                              w=w_in,
                              vbs=-vts,
                              vds=vmps - vts,
                              vgs=vinn - vts)
        cascp_par = db_casc.query(env=env,
                                  w=w_casc,
                                  vbs=-vmns,
                                  vds=vons - vmns,
                                  vgs=vdd - vmns)
        cascn_par = db_casc.query(env=env,
                                  w=w_casc,
                                  vbs=-vmps,
                                  vds=vops - vmps,
                                  vgs=vdd - vmps)
        loadp_par = db_load.query(env=env,
                                  w=w_load,
                                  vbs=0,
                                  vds=vons - vdd,
                                  vgs=vload - vdd)
        loadn_par = db_load.query(env=env,
                                  w=w_load,
                                  vbs=0,
                                  vds=vops - vdd,
                                  vgs=vload - vdd)
        cir = LTICircuit()
        cir.add_transistor(tail_par, 'tail', 'gnd', 'gnd', fg=fg_tail)
        cir.add_transistor(inp_par, 'midn', 'inp', 'tail', fg=fg_in)
        cir.add_transistor(inn_par, 'midp', 'inn', 'tail', fg=fg_in)
        cir.add_transistor(cascp_par, 'dn', 'gnd', 'midn', fg=fg_casc)
        cir.add_transistor(cascn_par, 'dp', 'gnd', 'midp', fg=fg_casc)
        cir.add_transistor(loadp_par, 'dn', 'gnd', 'gnd', fg=fg_load)
        cir.add_transistor(loadn_par, 'dp', 'gnd', 'gnd', fg=fg_load)
        cir.add_vcvs(0.5, 'inp', 'gnd', 'inac', 'gnd')
        cir.add_vcvs(-0.5, 'inn', 'gnd', 'inac', 'gnd')
        # step 3B: compute DC gain
        cir.add_vcvs(1, 'dac', 'gnd', 'dp', 'dn')
        dc_tf = cir.get_transfer_function('inac', 'dac')
        _, gain_vec = dc_tf.freqresp(w=[0.1])
        dc_gain = gain_vec[0].real
        # step 3C add cap loading
        cload = fanout * cin
        cir.add_cap(cload, 'outp', 'gnd')
        cir.add_cap(cload, 'outn', 'gnd')
        cir.add_vcvs(1, 'outac', 'gnd', 'outp', 'outn')
        # step 4: find scale factor to achieve k_settle
        # noinspection PyUnresolvedReferences
        scale_swp = np.arange(scale_min, scale_max, 0.25).tolist()
        max_kset = 0
        opt_scale = 0
        for cur_scale in scale_swp:
            # add scaled wired parasitics
            cap_cur = cw / 2 / cur_scale
            res_cur = rw * cur_scale
            cir.add_cap(cap_cur, 'dp', 'gnd')
            cir.add_cap(cap_cur, 'dn', 'gnd')
            cir.add_cap(cap_cur, 'outp', 'gnd')
            cir.add_cap(cap_cur, 'outn', 'gnd')
            cir.add_res(res_cur, 'dp', 'outp')
            cir.add_res(res_cur, 'dn', 'outn')
            # get settling factor
            sys = cir.get_state_space('inac', 'outac')
            _, yvec = scipy.signal.step(
                sys, T=tvec)  # type: Tuple[np.ndarray, np.ndarray]
            k_settle_cur = yvec[-1] / dc_gain
            # print('scale = %.4g, k_settle = %.4g' % (cur_scale, k_settle_cur))
            # update next scale factor
            if k_settle_cur > max_kset:
                max_kset = k_settle_cur
                opt_scale = cur_scale
            else:
                # k_settle is decreasing, break
                break
            if max_kset >= k_settle_targ:
                break

            # remove wire parasitics
            cir.add_cap(-cap_cur, 'dp', 'gnd')
            cir.add_cap(-cap_cur, 'dn', 'gnd')
            cir.add_cap(-cap_cur, 'outp', 'gnd')
            cir.add_cap(-cap_cur, 'outn', 'gnd')
            cir.add_res(-res_cur, 'dp', 'outp')
            cir.add_res(-res_cur, 'dn', 'outn')

        if max_kset < k_settle_targ:
            raise ValueError('%s max kset = %.4g @ scale = %.4g, '
                             'cannot meet settling time spec.' %
                             (env, max_kset, opt_scale))
        scale_list.append(opt_scale)

    return vmat_list, ratio_list, gain_list, scale_list, cin_list