Source code for bspysmg.utils.iv.multiple

"""
File containing a class for measuring IV curves on a single device (or surrogate model).
"""
import numpy as np
from brainspy.utils.pytorch import TorchUtils
from brainspy.utils.manager import get_driver
from brainspy.utils.transforms import linear_transform
from bspysmg.utils.inputs import generate_sawtooth_simple, generate_sinewave


[docs]class MultiIVMeasurement(): def __init__(self, configs: dict, save_plot=None, show_plot=True) -> None: """ Initializes the drivers for which IV curve is to be plotted. It uses a config dict to initialize the driver. The drivers can be the DNPU device itself (on chip training) or a surrogate model (off chip training). This class allows for the measurement of IV curves for several devices in a single PCB. Parameters ---------- configs : dict Dictionary containing the configurations for IV measurements with following keys: - input_signal: dict The configuration of signal with following keys: - input_signal_type: str The type of signal to generate - sawtooth or sine. - time_in_seconds: int The length of the signal to generate in seconds. - devices: list List of devices for which IV response is to be computed. This list contains the names of all the devices (A,B,C,D etc) involved in the experiment. """ self.configs = configs self.input_signal = self.configs['input_signal'] self.driver = get_driver(self.configs['driver'])
[docs] def run_test( self, experiments=["IV1", "IV2", "IV3", "IV4", "IV5", "IV6", "IV7"], close_driver: bool =True) -> None: """ Generates the IV response of devices to a sawtooth or sine wave and shows it on the screen. It uses configs dictionary with the following keys: - devices: list List of devices for which IV response is to be computed. This list contains the names of all the devices (A,B,C,D etc) involved in the experiment. - driver: dict It contains the configurations for each device in the experiment which are defined in the devices list. - close_driver: boolean Whether to close the driver or not after running the IV curve. """ # save(mode='configs', path=self.configs['results_base_dir'], filename='test_configs.json', overwrite=self.configs['overwrite_results'], data=self.configs) self.devices_in_experiments = {} output = {} inputs = {} output_array = [] input_arrays = [] self.index_prog = {} self.index_prog["all"] = 0 for dev in self.configs['devices']: self.index_prog[dev] = 0 for i, exp in enumerate(experiments): output[exp] = {} inputs[exp] = {} self.devices_in_experiments[exp] = self.configs['devices'].copy() output_array = self.driver.forward_numpy( self.create_input_arrays(inputs[exp])) for j, dev in enumerate(self.configs['devices']): output[exp][dev] = output_array[:, j] self.index_prog["all"] = 0 if close_driver: self.driver.close_tasks() return self.configs, inputs, output
[docs] def create_input_arrays(self, inputs_dict: dict) -> np.array: """ Generates input signal arrays for each device in inputs_dict dictionary that will be used to measure the IV response of those devices. The devices can be the DNPU device or a surrogate model. It uses configs dictionary with the following keys: - devices: list List of devices for which IV response is to be computed. This list contains the names of all the devices (A,B,C,D etc) involved in the experiment. - shape: int The length of the generated signal. - driver: dict It contains the configurations for each device in the experiment which are defined in the devices list. Parameters ---------- inputs_dict : dict Dictionary containing the devices for which IV curve is to be measured as keys. Returns ---------- inputs_array : np.array Generated signal arrays for each device. """ #inputs_dict = {} inputs_array = [] for dev in self.configs['devices']: inputs_dict[dev] = np.zeros( (self.configs["driver"]['instruments_setup'][dev] ['activation_channel_mask'].count(1), self.configs['shape'] )) # creates a zeros array for each '1' in the mask entry if self.configs["driver"]['instruments_setup'][dev][ 'activation_channel_mask'][self.index_prog["all"]] == 1: inputs_dict[dev][ self.index_prog[dev], :] = self.gen_input_wfrm( self.configs["driver"]['instruments_setup'][dev] ['activation_voltage_ranges'][self.index_prog["all"]]) self.index_prog[dev] += 1 else: self.devices_in_experiments["IV" + str(self.index_prog["all"] + 1)].remove(dev) inputs_array.extend(inputs_dict[dev]) inputs_array = np.array(inputs_array) self.index_prog["all"] += 1 return inputs_array.T
[docs] def gen_input_wfrm(self, input_range: float) -> np.array: """ Generates input signal to compute the IV response of DNPU device or a surrogate model. It uses configs dictionary with the following keys: - input_signal_type: str The type of signal to generate - sawtooth or sine. - shape: int The length of the generated signal. - direction: str ['up'/'down'] The Direction of the sawtooth. If true, the sawtooth will go first up and then down. If False, the sawtooth will go first down and then up. By default up. - frequency: int The frequency of the sine wave signal. Parameters ---------- input_range : float Maximum voltage that the signal will achieve. Minimum voltage is 0. Returns ---------- result : np.array Generated sawtooth or sine signal. """ if self.input_signal['input_signal_type'] == 'sawtooth': input_data = generate_sawtooth_simple( input_range[0], input_range[1], self.configs['shape'], self.input_signal['direction']) else: input_data = generate_sinewave( self.configs['shape'], self.configs['driver']['instruments_setup']['activation_sampling_frequency'], amplitude=1) # Max from the input range input_data = linear_transform(input_range[0], input_range[1], -1, 1, input_data ) input_data[-1] = 0 input_data[0] = 0 return input_data