def write(infofile, version, serial_number, calibfile, no_calib): if infofile is not None: if serial_number is not None or version is not None: raise click.UsageError(("--infofile and --version/--serial_number" " are mutually exclusive")) cape_data = CapeData.from_yaml(infofile) with EEPROM() as eeprom: eeprom.write_cape_data(cape_data) elif serial_number is not None or version is not None: if version is None or serial_number is None: raise click.UsageError( ("--version and --serial_number are required")) cape_data = CapeData.from_values(serial_number, version) with EEPROM() as eeprom: eeprom.write_cape_data(cape_data) if calibfile is not None: if no_calib: raise click.UsageError( "--no-calib and --calibfile are mutually exclusive") calib = CalibrationData.from_yaml(calibfile) with EEPROM() as eeprom: cape_data = eeprom.write_calibration(calib) if no_calib: calib = CalibrationData.from_default() with EEPROM() as eeprom: eeprom.write_calibration(calib)
def data_h5(tmp_path): store_path = tmp_path / "record_example.h5" with LogWriter(store_path, CalibrationData.from_default()) as store: for i in range(100): len_ = 10_000 fake_data = DataBuffer(random_data(len_), random_data(len_), i) store.write_buffer(fake_data) return store_path
def log_writer(tmp_path): calib = CalibrationData.from_default() with LogWriter( force_overwrite=True, store_path=tmp_path / "test.h5", mode="load", calibration_data=calib, ) as lw: yield lw
def log_writer(tmp_path, mode): calib = CalibrationData.from_default() with LogWriter( mode=mode, calibration_data=calib, force=True, store_path=tmp_path / "test.h5", ) as lw: yield lw
def emulator(request, shepherd_up, log_reader): emu = Emulator( calibration_recording=log_reader.get_calibration_data(), calibration_emulation=CalibrationData.from_default(), initial_buffers=log_reader.read_buffers(end=64), ) request.addfinalizer(emu.__del__) emu.__enter__() request.addfinalizer(emu.__exit__) return emu
def emulator(request, shepherd_up, log_reader, virtsource_settings_yml): vs_settings = VirtualSourceData(virtsource_settings_yml) emu = Emulator( calibration_recording=log_reader.get_calibration_data(), calibration_emulation=CalibrationData.from_default(), initial_buffers=log_reader.read_buffers(end=64), settings_virtsource=vs_settings, ) request.addfinalizer(emu.__del__) emu.__enter__() request.addfinalizer(emu.__exit__) return emu
def data_calibration(): return CalibrationData.from_default()
def test_from_default(): calib = CalibrationData.from_default()
def default_calib(): calib = CalibrationData.from_default() return calib
def calibration_data(): cd = CalibrationData.from_default() return cd
class VirtualSource(object): """ this is ported py-version of the pru-code, goals: - stay close to original code-base - offer a comparison for the tests - step 1 to a virtualization of emulation """ vsc = dict() cal = CalibrationData.from_default() def __init__(self, vs_settings): """ :param vs_settings: YAML-Path, dict, or regulator-name """ # NOTE: # - yaml is based on nA, mV, ms, uF # - c-code and py-copy is using nA, uV, ns, nF, pW vs_settings = VirtualSourceData(vs_settings) values = vs_settings.export_for_sysfs() # CONSTs, TODO: bring to commons (datalog can probably benefit as well) ADC_SAMPLES_PER_BUFFER = 10000 BUFFER_PERIOD_NS = 100000000 SAMPLE_INTERVAL_NS = (BUFFER_PERIOD_NS / ADC_SAMPLES_PER_BUFFER) LUT_SIZE = 12 self.vsc["LUT_size"] = LUT_SIZE # generate a new dict from raw_list (that is intended for PRU / sys_fs, see commons.h) self.vsc["converter_mode"] = values[0] # direct regulator self.vsc["C_output_nF"] = values[ 1] # final (always last) stage to catch current spikes of target # boost regulator self.vsc["V_inp_boost_threshold_uV"] = values[ 2] # min input-voltage for the boost converter to work self.vsc["C_storage_nF"] = values[3] self.vsc["V_storage_init_uV"] = values[ 4] # allow a proper / fast startup self.vsc["V_storage_max_uV"] = values[5] # -> boost shuts off self.vsc["V_storage_leak_nA"] = values[6] self.vsc["V_storage_enable_threshold_uV"] = values[ 7] # -> target gets connected (hysteresis-combo with next value) self.vsc["V_storage_disable_threshold_uV"] = values[ 8] # -> target gets disconnected self.vsc["interval_check_thresholds_ns"] = values[ 9] # some BQs check every 65 ms if output should be disconnected self.vsc["V_pwr_good_low_threshold_uV"] = values[ 10] # range where target is informed by output-pin self.vsc["V_pwr_good_high_threshold_uV"] = values[11] self.vsc["dV_stor_en_thrs_uV"] = values[12] # Buck Boost, ie. BQ25570) self.vsc["V_output_uV"] = values[13] self.vsc["dV_stor_low_uV"] = values[14] # LUTs LUT1_END = 15 + LUT_SIZE * LUT_SIZE LUT2_END = LUT1_END + LUT_SIZE self.vsc["LUT_inp_efficiency_n8"] = values[ 15: LUT1_END] # depending on inp_voltage, inp_current, (cap voltage), self.vsc["LUT_inv_output_efficiency_n10"] = values[ LUT1_END:LUT2_END] # depending on output_current # boost internal state self.vsc["P_inp_pW"] = 0.0 self.vsc["P_out_pW"] = 0.0 self.vsc["dt_us_per_C_nF"] = SAMPLE_INTERVAL_NS / ( 1000 * self.vsc["C_storage_nF"]) self.vsc["internal_check_thrs_sample"] = self.vsc[ "interval_check_thresholds_ns"] / SAMPLE_INTERVAL_NS self.vsc["V_store_uV"] = self.vsc["V_storage_init_uV"] # buck internal state self.vsc["V_out_uV"] = self.vsc["V_output_uV"] self.vsc["V_out_dac_raw"] = 1023 # TODO: unimplemented def calc_inp_power(self, input_current_nA: int, input_voltage_uV) -> NoReturn: V_inp_uV = 0 if input_voltage_uV > self.vsc["V_inp_boost_threshold_uV"]: V_inp_uV = input_voltage_uV if V_inp_uV > self.vsc["V_store_uV"]: V_inp_uV = self.vsc["V_store_uV"] eta_inp = self.get_input_efficieny(input_voltage_uV, input_current_nA) self.vsc["P_inp_pW"] = V_inp_uV * input_current_nA * eta_inp def calc_out_power(self, current_adc_raw): I_out_nA = self.conv_adc_raw_to_nA(current_adc_raw) eta_inv_out = self.get_output_efficiency(current_adc_raw) dP_leak_pW = self.vsc["V_store_uV"] * self.vsc["I_storage_leak_nA"] self.vsc["P_out_pW"] = I_out_nA * self.vsc[ "V_out_uV"] * eta_inv_out + dP_leak_pW def update_capacitor(self): P_sum_pW = self.vsc["P_inp_pW"] - self.vsc["P_out_pW"] I_cStor_nA = P_sum_pW / self.vsc["V_store_uV"] dV_cStor_uV = I_cStor_nA * self.vsc["dt_us_per_C_nF"] self.vsc["V_store_uV"] = self.vsc["V_store_uV"] + dV_cStor_uV def update_buckboost(self) -> int: global sample_count, is_outputting if self.vsc["V_store_uV"] > self.vsc["V_storage_max_uV"]: self.vsc["V_store_uV"] = self.vsc["V_storage_max_uV"] sample_count += 1 if sample_count == self.vsc["interval_check_thrs_sample"]: sample_count = 0 if is_outputting: if (self.vsc["V_store_uV"] < self.vsc["V_out_uV"]) or \ (self.vsc["V_store_uV"] < self.vsc["V_storage_disable_threshold_uV"]): is_outputting = False else: if self.vsc["V_store_uV"] > self.vsc["V_out_uV"]: is_outputting = True self.vsc["V_store_uV"] = self.vsc["V_store_uV"] - self.vsc[ "dV_stor_low_uV"] if self.vsc["V_store_uV"] > self.vsc[ "V_storage_disable_threshold_uV"]: is_outputting = True self.vsc["V_store_uV"] = self.vsc["V_store_uV"] - self.vsc[ "dV_stor_en_thrs_uV"] return self.vsc["V_out_dac_raw"] if is_outputting else 0 def conf_adc_raw_to_nA(self, current_raw: int) -> float: return self.cal.convert_raw_to_value("emulation", "adc_current", current_raw) * (10**9) def conv_uV_to_dac_raw(self, voltage_uV: int) -> int: return self.cal.convert_value_to_raw("emulation", "dac_voltage_b", float(voltage_uV) / (10**6)) def get_input_efficiency(self, voltage_uV: int, current_nA: int) -> float: pos_v = int(round(math.log2(voltage_uV))) pos_c = int(round(math.log2(current_nA))) for value in pos_v, pos_c: if value >= self.vsc["LUT_size"]: value = self.vsc["LUT_size"] - 1 return self.vsc["LUT_inp_efficiency_n8"][pos_v * self.vsc["LUT_size"] * pos_c] / (2**8) def get_output_efficiency(self, current) -> float: pos_c = int(round(math.log2(current))) if pos_c >= self.vsc["LUT_size"]: pos_c = self.vsc["LUT_size"] - 1 return self.vsc["LUT_out_inv_efficiency_n10"][pos_c] / (2**10) def set_input_power_pW(self, value): self.vsc["P_inp_pW"] = value def set_output_power_pW(self, value): self.vsc["P_out_pW"] = value def set_storage_Capacitor_uV(self, value): self.vsc["V_store_uV"] = value def get_input_power_pW(self, value): return self.vsc["P_inp_pW"] def get_output_power_pW(self, value): return self.vsc["P_out_pW"] def get_storage_Capacitor_uV(self, value): return self.vsc["V_store_uV"]