def plot_gain_bw(specs, sim_params, fg_load_list, env): vname = 'outac' base_name = specs['impl_cell'] save_root = sim_params['save_root'] vload_list = sim_params['vload_list'] gain_mat = np.empty((len(fg_load_list), len(vload_list))) bw_mat = np.empty((len(fg_load_list), len(vload_list))) for fg_idx, fg_load in enumerate(fg_load_list): fname = os.path.join(save_root, '%s_fg%d.hdf5' % (base_name, fg_load)) results = load_sim_file(fname) swp_pars = results['sweep_params'][vname] corners = results['corner'] corner_idx = swp_pars.index('corner') env_idx = np.argwhere(corners == env)[0][0] data = np.take(results[vname], env_idx, axis=corner_idx) vload_idx = swp_pars.index('vload') vload_vec = results['vload'] for idx in range(vload_vec.size): outac = np.take(data, idx, axis=vload_idx) gain, f3db = compute_gain_and_w3db(results['freq'], outac) gain_mat[fg_idx, idx] = gain bw_mat[fg_idx, idx] = f3db plot_mat(1, '$A_v$ (V/V)', gain_mat, fg_load_list, vload_list) plot_mat(2, '$f_{3db}$ (Hz)', bw_mat, fg_load_list, vload_list) plt.show()
def process_output( self, state, # type: str data, # type: Dict[str, Any] tb_manager, # type: Union[MOSIdTB, MOSSPTB, MOSNoiseTB] ): # type: (...) -> Tuple[bool, str, Dict[str, Any]] ss_fname = os.path.join(self.data_dir, 'ss_params.hdf5') if state == 'ibias': done = False next_state = 'sp' vgs_range = tb_manager.get_vgs_range(data) output = dict(vgs_range=vgs_range) elif state == 'sp': testbenches = self.specs['testbenches'] if 'noise' in testbenches: done = False next_state = 'noise' else: done = True next_state = '' ss_params = tb_manager.get_ss_params(data) # save SS parameters save_sim_results(ss_params, ss_fname) output = dict(ss_file=ss_fname) elif state == 'noise': done = True next_state = '' temp = self.specs['noise_temp_kelvin'] fstart = self.specs['noise_integ_fstart'] fstop = self.specs['noise_integ_fstop'] scale = self.specs.get('noise_integ_scale', 1.0) ss_params = load_sim_file(ss_fname) ss_params = tb_manager.get_integrated_noise(data, ss_params, temp, fstart, fstop, scale=scale) save_sim_results(ss_params, ss_fname) output = dict(ss_file=ss_fname) else: raise ValueError('Unknown state: %s' % state) return done, next_state, output
def simulate(prj, specs_fname): # simulate and report result sim = DesignManager(prj, specs_fname) sim.characterize_designs(generate=True, measure=True, load_from_file=False) # sim.test_layout(gen_sch=False) dsn_name = list(sim.get_dsn_name_iter())[0] summary = sim.get_result(dsn_name) fname = summary['ac']['gain_w3db_file'] result = load_sim_file(fname) gain = result['gain_vout'] w3db = result['w3db_vout'] print('%s gain = %.4g' % (dsn_name, gain)) print('%s w3db = %.4g' % (dsn_name, w3db)) return gain, w3db
def run_main(prj): # save_fname = 'blocks_ec_tsmcN16/data/gm_char_dc/linearity_stack.hdf5' save_fname = 'blocks_ec_tsmcN16/data/gm_char_dc/linearity_stack.hdf5' sim_env = 'tt' vdd = 0.9 voutcm = 0.7 tper = 70e-12 ck_amp = 0.3 ck_bias = 0.05 rel_err = 0.05 cload = 5e-15 bias_vec = np.linspace(0, 0.15, 16, endpoint=True) dc_params = dict( num_k=7, sim_env=sim_env, method='linear', ) vstar_params = dict( tol=1e-3, num=21, method='cubic', ) sim_params = dict( dut_lib='CHAR_INTEG_AMP_STACK_TSW', impl_lib='CHAR_INTEG_AMP_STACK_TSW_TB', impl_cell='gm_char_dc', save_fname=save_fname, tb_lib='bag_serdes_testbenches_ec', tb_cell='gm_char_dc', dut_cell='INTEG_AMP', env_list=['tt', 'ff_hot', 'ss_cold'], sim_view='av_extracted', ) # simulate(prj, **sim_params) result = load_sim_file(save_fname) # plot_data_2d(result, 'ioutp', sim_env='tt') # get_transient(result, 15, tper, ck_amp, ck_bias, **kwargs) # get_dc_tf(result, tper, ck_amp, ck_bias, plot=True, **dc_params) plot_vstar(result, tper, vdd, cload, bias_vec, ck_amp, rel_err, dc_params, vstar_params)
def __init__(self, prj: BagProject, spec_list: List[str], interp_method: str = 'spline', vgs_res: float = 5e-3, width_var: str = 'w') -> None: self._width_res = prj.tech_info.tech_params['mos']['width_resolution'] self._sim_envs = None self._ss_swp_names = None self._dsn_info_list: List[MOSCharSpecs] = [] self._ss_list = [] self._ss_outputs = None self._width_list = [] self._vgs_res = vgs_res for spec in spec_list: dsn_info = MOSCharSpecs(spec) cur_width = dsn_info.specs['dut_params'][width_var] cur_width = int(round(cur_width / self._width_res)) self._width_list.append(cur_width) # error checking if 'w' in dsn_info.swp_var_list: raise ValueError( 'MOSDBDiscrete assumes transistor width is not swept.') ss_fun_table = {} for dsn_name in dsn_info.dsn_name_iter(): meas_dir = dsn_info.root_dir / dsn_info.specs[ 'meas_name'] # FIXME ss_dict = load_sim_file( os.path.join(str(meas_dir), 'ss_params.hdf5')) cur_corners = ss_dict['corner'].tolist() cur_ss_swp_names = ss_dict['sweep_params']['ibias'][1:] if self._sim_envs is None: # assign attributes for the first time self._sim_envs = cur_corners self._ss_swp_names = cur_ss_swp_names elif self._sim_envs != cur_corners: raise ValueError( 'Simulation environments mismatch between given specs.' ) elif self._ss_swp_names != cur_ss_swp_names: raise ValueError( 'signal-signal parameter sweep names mismatch.') cur_fun_dict = self._make_ss_functions(ss_dict, cur_corners, cur_ss_swp_names, interp_method) if self._ss_outputs is None: self._ss_outputs = sorted(cur_fun_dict.keys()) ss_fun_table[dsn_name] = cur_fun_dict self._dsn_info_list.append(dsn_info) self._ss_list.append(ss_fun_table) self._env_list = self._sim_envs self._cur_idx = 0 self._dsn_params = dict(w=self._width_list[0] * self._width_res)
def __init__( self, spec_list, # type: List[str] interp_method='spline', # type: str bag_config_path=None, # type: Optional[str] meas_type='mos_ss', # type: str vgs_res=5e-3, # type: float is_schematic=False, width_var='w', ): # type: (...) -> None # error checking tech_info = create_tech_info(bag_config_path=bag_config_path) self._width_res = tech_info.tech_params['mos']['width_resolution'] self._sim_envs = None self._ss_swp_names = None self._manager_list = [] # type: List[DesignManager] self._ss_list = [] self._ss_outputs = None self._width_list = [] self._vgs_res = vgs_res param_name = 'schematic_params' if is_schematic else 'layout_params' for spec in spec_list: dsn_manager = DesignManager(None, spec) cur_width = dsn_manager.specs[param_name][width_var] cur_width = int(round(cur_width / self._width_res)) self._width_list.append(cur_width) # error checking if 'w' in dsn_manager.swp_var_list: raise ValueError( 'MOSDBDiscrete assumes transistor width is not swept.') ss_fun_table = {} for dsn_name in dsn_manager.get_dsn_name_iter(): meas_dir = dsn_manager.get_measurement_directory( dsn_name, meas_type) ss_dict = load_sim_file( os.path.join(meas_dir, 'ss_params.hdf5')) cur_corners = ss_dict['corner'].tolist() cur_ss_swp_names = ss_dict['sweep_params']['ibias'][1:] if self._sim_envs is None: # assign attributes for the first time self._sim_envs = cur_corners self._ss_swp_names = cur_ss_swp_names elif self._sim_envs != cur_corners: raise ValueError( 'Simulation environments mismatch between given specs.' ) elif self._ss_swp_names != cur_ss_swp_names: raise ValueError( 'signal-signal parameter sweep names mismatch.') cur_fun_dict = self._make_ss_functions(ss_dict, cur_corners, cur_ss_swp_names, interp_method) if self._ss_outputs is None: self._ss_outputs = sorted(cur_fun_dict.keys()) ss_fun_table[dsn_name] = cur_fun_dict self._manager_list.append(dsn_manager) self._ss_list.append(ss_fun_table) self._env_list = self._sim_envs self._cur_idx = 0 self._dsn_params = dict(w=self._width_list[0] * self._width_res)
async def async_measure_performance(self, name: str, sim_dir: Path, sim_db: SimulationDB, dut: Optional[DesignInstance]) -> Dict[str, Any]: """ A coroutine that performs measurement. This will... 1. Acquire every sweep point/configuration (get_swp_list) 2. Run simulation for each sweep point (_run_sim) 3. Aggregate results and return (aggregate_results) Parameters ---------- name : str name of measurement sim_dir : Path simulation directory sim_db : SimulationDB the simulation database object dut : Optional[DesignInstance] the DUT to measure Returns ------- results dictionary """ assert len(self._sim_envs) > 0 self.tbm_dict: Dict[str, TestbenchManager] = {k: None for k in self.tbm_order} res = {} for idx, tbm_name in enumerate(self.tbm_order): if not self._run_tbm[tbm_name]: continue tbm = self.add_tbm(tbm_name) sim_results = await sim_db.async_simulate_tbm_obj(tbm_name, sim_dir / tbm_name, dut, tbm, tb_params={}) data = sim_results.data ss_fname = str(sim_dir / 'ss_params.hdf5') if tbm_name == 'ibias': tbm: MOSIdTB vgs_range = tbm.get_vgs_range(data) if self._run_tbm['sp']: self.specs['tbm_specs']['sp']['vgs_range'] = vgs_range if self._run_tbm['noise']: self.specs['tbm_specs']['noise']['vgs_range'] = vgs_range self.commit() res['vgs_range'] = vgs_range elif tbm_name == 'sp': tbm: MOSSPTB ss_params = tbm.get_ss_params(data) # save SS parameters save_sim_results(ss_params, ss_fname) res['ss_file'] = ss_fname elif tbm_name == 'noise': # TODO: needs to be verified tbm: MOSNoiseTB temp = self.specs['noise_temp_kelvin'] fstart = self.specs['noise_integ_fstart'] fstop = self.specs['noise_integ_fstop'] scale = self.specs.get('noise_integ_scale', 1.0) ss_params = load_sim_file(ss_fname) ss_params = tbm.get_integrated_noise(data, ss_params, temp, fstart, fstop, scale=scale) save_sim_results(ss_params, ss_fname) res['ss_file'] = ss_fname else: raise ValueError(f"Unknown tbm name {tbm_name}") write_yaml(sim_dir / f'{name}.yaml', res) return res