.. |mementos| raw:: html Mementos .. |hibernus| raw:: html Hibernus .. |d2vfs| raw:: html D2VFS .. |fbtc| raw:: html FBTC .. |wisp| raw:: html WISP .. |sceptic-energy-sources| raw:: html dedicated repo .. |bonito| raw:: html Bonito .. |bonito-paper| raw:: html Bonito .. _system-model-label: System Model Configuration ========================== ScEpTIC analysis can emulate the energy consumption and timing of a given system. ScEpTIC allows you to specify and configure the various components of your system through the various classes available in ``ScEpTIC/emulator/energy``. These classes allows you to specify the following elements of your system: - Energy Source - Energy Harvester - Voltage Regulator - Energy Buffer - MCU - Peripherals - State Retention Mechanism - Custom Circuitry and Devices - Timekeeper The various analysis available in ScEpTIC takes a ``SystemEnergyModel`` object as one of the inputs, which represents a container that includes the system components and provides the logic to emulate system energy consumption and timing. This is a base example to initialize the ``SystemEnergyModel``:: import ScEpTIC from ScEpTIC.config import ScEpTICConfig from ScEpTIC.emulator.energy.system_energy_model import SystemEnergyModel from ScEpTIC.emulator.energy.options import PowerOffCondition from ScEpTIC.emulator.energy.power_state_event import PowerStateEvent system_model = SystemEnergyModel() system_model.set_power_off_condition(PowerOffCondition.POWER_STATE_EVENT) system_model.add_power_off_event(PowerStateEvent.MCU_OFF) # Attach here all system model components # ... # ... config = ScEpTICConfig() config.analysis.add_config("enabled_analysis", "energy") config.analysis.energy.set_config("system_model", system_model) We discuss below the various classes you can use to model your system and how you can attach them to the ``SystemEnergyModel``. The methods available to attach components to your system are: - ``attach_energy_buffer(energy_buffer)``: attaches an energy buffer to the system model - ``attach_energy_harvester(energy_harvester)``: attaches an energy harvester to the system model - ``attach_energy_source_model(energy_source)``: attaches an energy source model to the system model - ``attach_mcu(mcu)``: attaches a MCU energy model to the system model - ``attach_timekeeper(timekeeper)``: attaches a time keeper to the system model - ``attach_voltage_regulator(voltage_regulator)``: attaches a voltage regulator to the system model. Note that this is the regulator used by the MCU. Custom components can be connected directly to the energy buffer or to this regulator - ``attach_component(name, component, power_target)``: attaches attaches a custom component to the system model - ``attach_custom_device(custom_device)``: attaches a custom device to the system model - ``attach_state_retention_model(state_retention)``: attaches a system retention model to the system model Note that you should attach components to the ``SystemEnergyModel`` before attaching it to the ``ScEpTICConfig``. Units ----- To simplify the readability of configuration parameters, ScEpTIC allows you to specify numbers in a text form with the following multipliers: .. list-table:: Supported Multipliers :header-rows: 1 * - Name - Value * - ``T`` - ``1000000000000.0`` * - ``G`` - ``1000000000.0`` * - ``M`` - ``1000000.0`` * - ``K`` - ``1000.0`` * - ``m`` - ``0.001`` * - ``u`` - ``0.000001`` * - ``n`` - ``0.000000001`` * - ``p`` - ``0.000000000001`` For example, if you want to specify a :math:`100{\mu}F` capacitor, you can simply specify its value as ``100u`` ScEpTIC parses this units using functions available in ``ScEpTIC/emulator/energy/energy_utils.py``. Energy Source ------------- Energy sources models extends the base ``EnergySourceModel`` available in ``ScEpTIC/emulator/energy/energy_source``. ScEpTIC offers three types of energy sources: ``FixedVoltageSource``, ``SyntheticEnergySource``, and ``TimeSeriesEnergySource``. Further, you can create your own energy source model by extending ``EnergySourceModel``. ScEpTIC accounts for harvested energy power limitations by reproducing the energy source voltage and maximum current. For doing so, you may need to specify the resistance of the load used to measure the energy source output voltage using the ``set_load_resistance(resistance)`` method. ScEpTIC uses the value of ``resistance`` to calculate the maximum current and limits the energy buffer recharge accordingly. You can use the ``resistance`` parameter to model different energy dynamics than the one when the energy source was recorded. FixedVoltageSource ****************** The ``FixedVoltageSource`` class models an ambient energy source that supply a constant amount of voltage. You can create a ``FixedVoltageSource`` as follows:: from ScEpTIC.emulator.energy.energy_source.fixed_voltage_source import FixedVoltageSource energy_source = FixedVoltageSource(v) energy_source.set_load_resistance('30K') # attach the energy source to the system model system_model.attach_energy_source_model(energy_source) where ``v`` is the output voltage of the energy source. Further, ``FixedVoltageSource`` provides the ``set_voltage()`` method to change the output voltage:: energy_source.set_voltage(v) where ``v`` is the new output voltage of the energy source. SyntheticEnergySource ********************* The ``SyntheticEnergySource`` class models a synthetic ambient energy source that supplies energy only when the device is powered off. You can create a ``SyntheticEnergySource`` as follows:: from ScEpTIC.emulator.energy.energy_source.synthetic_energy_source import SyntheticEnergySource energy_source = SyntheticEnergySource(v) energy_source.set_load_resistance('30K') # attach the energy source to the system model system_model.attach_energy_source_model(energy_source) where ``v`` is the output voltage of the energy source when the device is powered off. Similarly to ``FixedVoltageSource``, ``SyntheticEnergySource`` provides the ``set_voltage()`` method to change the output voltage:: energy_source.set_voltage(v) where ``v`` is the new output voltage of the energy source when the device is powered off. TimeSeriesEnergySource ********************** The ``TimeSeriesEnergySource`` reproduces a voltage or power trace collected from a real energy source. You can create a ``TimeSeriesEnergySource`` as follows:: from ScEpTIC.emulator.energy.energy_source.time_series_energy_source import TimeSeriesEnergySource energy_source = TimeSeriesEnergySource(name) energy_source.set_load_resistance('30K') # attach the energy source to the system model system_model.attach_energy_source_model(energy_source) where ``name`` is the name of the energy source. ScEpTIC provides voltage or power traces of real energy sources in a |sceptic-energy-sources| and automatically downloads them into the ``ScEpTIC/emulator/energy/energy_source/time_series/`` directory the first time they are used. ScEpTIC provides the traces of the following sources: .. list-table:: Energy Source Traces :header-rows: 1 * - Name - Description - Reference * - ``rf_mementos`` - Voltage trace of the RF energy source - Used in |Mementos| experiments * - ``solar_indoor_rest`` - Voltage trace of a mono-crystalline solar panel attached to a wrist of a person sitting in a desk in the lab - Used in |d2vfs| experiments * - ``solar_indoor_moving`` - Voltage trace of a mono-crystalline solar panel attached to a wrist of a person moving in the lab - Used in |d2vfs| experiments * - ``solar_outdoor_rest`` - Voltage trace of a mono-crystalline solar panel attached to a wrist of a person sitting in the university campus - Used in |d2vfs| experiments * - ``solar_outdoor_moving`` - Voltage trace of a mono-crystalline solar panel attached to a wrist of a person moving in the university campus - Used in |d2vfs| experiments * - ``bonito_cars_node0`` - Power trace of |bonito| cars dataset (node 0) - Used in |bonito-paper| * - ``bonito_cars_node1`` - Power trace of |bonito| cars dataset (node 1) - Used in |bonito-paper| * - ``bonito_cars_node2`` - Power trace of |bonito| cars dataset (node 2) - Used in |bonito-paper| * - ``bonito_cars_node3`` - Power trace of |bonito| cars dataset (node 3) - Used in |bonito-paper| * - ``bonito_cars_node4`` - Power trace of |bonito| cars dataset (node 4) - Used in |bonito-paper| * - ``bonito_cars_node5`` - Power trace of |bonito| cars dataset (node 5) - Used in |bonito-paper| * - ``bonito_jogging_node0`` - Power trace of |bonito| jogging dataset (node 0) - Used in |bonito-paper| * - ``bonito_jogging_node1`` - Power trace of |bonito| jogging dataset (node 1) - Used in |bonito-paper| * - ``bonito_jogging_node2`` - Power trace of |bonito| jogging dataset (node 2) - Used in |bonito-paper| * - ``bonito_jogging_node3`` - Power trace of |bonito| jogging dataset (node 3) - Used in |bonito-paper| * - ``bonito_jogging_node4`` - Power trace of |bonito| jogging dataset (node 4) - Used in |bonito-paper| * - ``bonito_office_node0`` - Power trace of |bonito| office dataset (node 0) - Used in |bonito-paper| * - ``bonito_office_node1`` - Power trace of |bonito| office dataset (node 1) - Used in |bonito-paper| * - ``bonito_office_node2`` - Power trace of |bonito| office dataset (node 2) - Used in |bonito-paper| * - ``bonito_office_node3`` - Power trace of |bonito| office dataset (node 3) - Used in |bonito-paper| * - ``bonito_office_node4`` - Power trace of |bonito| office dataset (node 4) - Used in |bonito-paper| * - ``bonito_stairs_node0`` - Power trace of |bonito| stairs dataset (node 0) - Used in |bonito-paper| * - ``bonito_stairs_node1`` - Power trace of |bonito| stairs dataset (node 1) - Used in |bonito-paper| * - ``bonito_stairs_node2`` - Power trace of |bonito| stairs dataset (node 2) - Used in |bonito-paper| * - ``bonito_stairs_node3`` - Power trace of |bonito| stairs dataset (node 3) - Used in |bonito-paper| * - ``bonito_stairs_node4`` - Power trace of |bonito| stairs dataset (node 4) - Used in |bonito-paper| * - ``bonito_stairs_node5`` - Power trace of |bonito| stairs dataset (node 5) - Used in |bonito-paper| * - ``bonito_washer_node0`` - Power trace of |bonito| washer dataset (node 0) - Used in |bonito-paper| * - ``bonito_washer_node1`` - Power trace of |bonito| washer dataset (node 1) - Used in |bonito-paper| * - ``bonito_washer_node2`` - Power trace of |bonito| washer dataset (node 2) - Used in |bonito-paper| * - ``bonito_washer_node3`` - Power trace of |bonito| washer dataset (node 3) - Used in |bonito-paper| * - ``bonito_washer_node4`` - Power trace of |bonito| washer dataset (node 4) - Used in |bonito-paper| For example, you can use the ``rf_mementos`` energy source as follows:: from ScEpTIC.emulator.energy.energy_source.time_series_energy_source import TimeSeriesEnergySource energy_source = TimeSeriesEnergySource('rf_mementos') energy_source.set_load_resistance('30K') # attach the energy source to the system model system_model.attach_energy_source_model(energy_source) Energy traces have a fixed recording length. When the trace end is reached, ScEpTIC reproduces the ``TimeSeriesEnergySource`` from its trace start. This behaviour can be disabled by setting the attribute ``restart_on_trace_end`` to ``False``:: energy_source.restart_on_trace_end = False **Bring Your Own Voltage Source** You can use your own voltage source by creating a new json file in ``ScEpTIC/emulator/energy/energy_source/time_series/``. The json file must contan a dictionary with the following elements:: { # Sampling time "sampling_time": "1m", # Equivalent resistance of the load used to collect the traces # In that case, ScEpTIC uses the energy harvester resistance as circuit load "load_resistance": 30000, # Multiplier for the measues (e.g. in this case, the measures are in uW) "measures_multiplier": '1u', # Value type of the trace (power or voltage) "measures_type": "power", # If the measures are compressed using zlib to reduce space "measures_compressed": false, # Measures "measures": [...] } For example, if you want to create a ``piezo`` energy source, you need to create the file ``ScEpTIC/emulator/energy_source/time_series/piezo.json`` with the following content:: { "sampling_time": "1m", "load_resistance": 30000, "measures_multiplier": none, "measures_type": "voltage", "measures_compressed": false, "measures": [0.5, 0.3, 1.2, 3.1, ...] } Next, you can use the new ``piezo`` voltage trace as follows:: from ScEpTIC.emulator.energy.energy_source.time_series_energy_source import TimeSeriesEnergySource energy_source = TimeSeriesEnergySource('piezo') For further details, you can find examples in ScEpTIC energy sources |sceptic-energy-sources| or check ``ScEpTIC/emulator/energy_source/time_series/gen_json.py``. .. _harvester-label: Voltage Regulator ----------------- Real systems often use voltage regulators to regulate the operating voltage of system components. Therefore, ScEpTIC implements voltage regulator logic and energy models through the ``VoltageRegulatorModel`` base class, located in ``ScEpTIC/emulator/energy/voltage_regulators``. In the same file, ScEpTIC implements the logic of step up voltage regulators and step down voltage regulators, through the classes ``StepUpVoltageRegulatorModel`` and ``StepDownVoltageRegulatorModel``, respectively. You can model a voltage regulator by extending ``StepUpVoltageRegulatorModel`` or ``StepDownVoltageRegulatorModel`` as follows:: from ScEpTIC.emulator.energy.voltage_regulator import StepUpVoltageRegulatorModel class MyVoltageRegulator(StepUpVoltageRegulatorModel): def __init__(self): super().__init__() self.efficiency = 0.90 self.i_quiescent = energy_utils.str_to_float('6.5u') self.v_min = 0.9 where the attribute ``efficiency`` is the average efficiency of the voltage regulator, ``i_quiescent`` is its quiescent current, and ``v_min`` is the minimum operating voltage for the regulator to work. These parameters can be obtained from components' datasheet information. ScEpTIC already implements the model of three commonly used voltage regulators, using their datasheet information: the ``MAX20361`` voltage charge boost regulator, the ``TPS61322`` step up voltage regulator, and the ``TPS62740`` step down voltage regulator. They can be used as follows:: from ScEpTIC.emulator.energy.voltage_regulator.MAX20361 import MAX20361 regulator = MAX20361() from ScEpTIC.emulator.energy.voltage_regulator.TPS61322 import TPS61322 regulator = TPS61322() from ScEpTIC.emulator.energy.voltage_regulator.TPS62740x import TPS62740x regulator = TPS62740x() Voltage regulators can be attached to any component using the ``attach_voltage_regulator(regulator)`` method. Further, you can model your own voltage regulator by extending the ``VoltageRegulatorModel`` class. Finally, you can set the output voltage of any class extending the ``VoltageRegulatorModel`` using the ``set_output_voltage()`` method, as follows:: regulator.set_output_voltage(3.6) Energy Harvester ---------------- ScEpTIC models energy dynamics using an energy harvester attached to the system model. Therefore, ScEpTIC requires you to attach the energy source to an energy harvester. Once you defined your energy source model, you need to specify an energy harvester. ScEpTIC allows you to model energy harvesters circuitry by extending the ``EnergyHarvesterModel`` base class located in ``ScEpTIC/emulator/energy/energy_harvester``. You can set the energy harvester equivalent resistance using the ``set_equivalent_resistance()`` method. Further, you can attach an energy source model to an energy harvester using the method ``attach_energy_source(energy_source)``. ScEpTIC already implements three types of energy harvesters: ``ChargeBoosterEnergyHarvester``, ``VoltageDoublerEnergyHarvester``, and ``GenericEnergyHarvster``. Charge Booster ************** This type of energy harvester include a charge booster to boost the energy source voltage. To use this energy harvester, you need first to instantiate a voltage regulator or voltage charge booster. Then, you can create a new instance of the ``ChargeBoosterEnergyHarvester`` by passing the charge booster and the harvester resistance as parameters. Here is an example:: from ScEpTIC.emulator.energy.voltage_regulator.MAX20361 import MAX20361 from ScEpTIC.emulator.energy.energy_harvester.charge_booster import ChargeBoosterEnergyHarvester harvester_resistance = '1' # create the voltage booster charge_booster = MAX20361() charge_booster.set_output_voltage(v_on * 1.015) # create the energy harvester energy_harvester = ChargeBoosterEnergyHarvester(charge_booster, harvester_resistance) # attach energy source to energy harvester energy_harvester.attach_energy_source(energy_source) # attach energy harvester to the system model system_model.attach_energy_harvester(energy_harvester) Voltage Doubler *************** This type of energy harvester models a capacitor array that the |wisp| platform uses to multiply the voltage of low-voltage energy sources. You can create a new instance of the ``VoltageDoublerEnergyHarvester`` by passing the number of voltage doublers and the harvester resistance as parameters. Here is an example:: from ScEpTIC.emulator.energy.energy_harvester.voltage_doubler import VoltageDoublerEnergyHarvester harvester_resistance = '1' n_voltage_doublers = 1 # doubles the voltage once # create the voltage doubler energy_harvester = VoltageDoublerEnergyHarvester(n_voltage_doublers, harvester_resistance) # attach energy source to energy harvester energy_harvester.attach_energy_source(energy_source) # attach energy harvester to the system model system_model.attach_energy_harvester(energy_harvester) Generic Harvester ***************** This is the most simple type of energy harvester, which does not include any circuitry that alter the energy source voltage. You can create a new instance of the ``GenericEnergyHarvester`` by passing the the harvester resistance as a parameter. Here is an example:: from ScEpTIC.emulator.energy.energy_harvester.generic import GenericEnergyHarvester harvester_resistance = '1' # create the generic harvester energy_harvester = GenericEnergyHarvester(harvester_resistance) # attach energy source to energy harvester energy_harvester.attach_energy_source(energy_source) # attach energy harvester to the system model system_model.attach_energy_harvester(energy_harvester) Energy Buffer ------------- ScEpTIC implements the model of a capacitor ``CapacitorModel`` that you can use as follows:: from ScEpTIC.emulator.energy.buffer.capacitor import CapacitorModel energy_buffer = CapacitorModel(capacitance, voltage_upper_bound, energy_upper_bound) # attach the energy buffer to the system model system_model.attach_energy_buffer(energy_buffer) where ``capacitance`` is the capacitor's capacitance, ``voltage_upper_bound`` is the maximum capacitor's voltage, and ``energy_upper_bound`` is the maximum energy the capacitor can store. Note that you need to specify the value only for ``voltage_upper_bound`` or ``energy_upper_bound``, as ScEpTIC will automatically calcualte the other parameter. For example, to model a :math:`50{\mu}F` capacitor that reaches maximum 6V:: from ScEpTIC.emulator.energy.buffer.capacitor import CapacitorModel energy_buffer = CapacitorModel('50u', 6.0, None) The ``CapacitorModel`` extends the ``EnergySourceModel`` base class that models energy buffers. The ``EnergySourceModel`` offers a method to set the energy buffer voltage:: energy_buffer.set_voltage(v) where ``v`` is the new voltage of the energy buffer. Further, you can implement your own energy buffer by extending the ``EnergyBufferModel`` base class, located in ``ScEpTIC/emulator/energy/buffer``, and by overriding its methods. MCU --- In principle, ScEpTIC allows you to model the energy consumption of any MCU and its operating modes through the ``MCUEnergyModel`` class, located in ``ScEpTIC/emulator/energy/mcu``. ScEpTIC currently implement only MCUs from the MSP430-FR and MSP430-G families of MCUs, through the ``MSP430FREnergyModel`` and ``MSP430GEnergyModel`` classes. When initializing an MCUEnergyModel, you must provide the MCU model name, if a lookup table for its energy measurement is available, and the instruction cache hit ratio. For example:: from ScEpTIC.emulator.energy.mcu.msp430fr import MSP430FREnergyModel mcu = MSP430FREnergyModel('msp430fr5969', load_lookup_table=False, instruction_cache_hit_ratio=0.9) # attach MCU to the system model system_model.attach_mcu(mcu) from ScEpTIC.emulator.energy.mcu.msp430g import MSP430GEnergyModel mcu = MSP430GEnergyModel('msp430g2553', load_lookup_table=False, instruction_cache_hit_ratio=0.9) # attach MCU to the system model system_model.attach_mcu(mcu) ScEpTIC already models and provides the energy consumption of the following MCUs: * msp430fr2355 * msp430fr5043 * msp430fr5739 * msp430fr5969 * msp430g2553 The ``MCUEnergyModel`` provides three methods that you can use to setup the MCU: * ``set_frequency(frequency)`` sets the MCU operating frequency * ``set_target_lpm(lpm_mode)`` sets the low-power mode used in the simulations * ``set_v_on(v_on)`` sets the voltage at which the MCU powers on after energy failures * ``set_mcu_state(state)`` sets the MCU power state (``MCUPowerState.ON`` for on or ``MCUPowerState.OFF`` for off) * ``set_adc_state(state)`` sets the MCU internal ADC state (``ADCPowerState.ON`` for on or ``ADCPowerState.OFF`` for off) For example, you can set the MCU at 16MHz, LPM4 as target low-power mode, 3.6V as power-on voltage, the MCU on, and the ADC off as follows:: from ScEpTIC.emulator.energy.mcu.options import MCUPowerState, ADCPowerState mcu.set_frequency('16MHz') mcu.set_target_lpm('LPM4') mcu.set_v_on(3.6) mcu.set_mcu_state(MCUPowerState.ON) mcu.set_adc_state(ADCPowerState.OFF) Peripherals ----------- ScEpTIC allows you to model various peripheral devices by extending the ``MCUPeripheral`` base class, located in ``ScEpTIC/emulator/energ/mcu_peripheral``. ScEpTIC already implement various peripheral devices: * 0V7620 camera/image sensor * CC1101 radio * SGP40 VOC sensor * SHT85 Digital temperature and humidity sensor * Generic ADC sensors They can be found in ``ScEpTIC/emulator/energ/mcu_peripheral``. Peripherals must be attached to the system model as custom components, speficying if they are powered using the voltage regulator or the energy buffer directly:: from ScEpTIC.emulator.energy.options import ComponentVoltageSource from ScEpTIC.emulator.energy.mcu_peripheral.cc1101 import CC1101Model from ScEpTIC.emulator.energy.mcu_peripheral.SHT85 import SHT85 from ScEpTIC.emulator.energy.mcu_peripheral.generic_sensor import GenericADCSensorModel from ScEpTIC.emulator.energy.mcu_peripheral.camera_0V7620 import Camera0V7620Model # Crate peripherals radio = CC1101Model() generic_sensor = GenericADCSensorModel() camera = Camera0V7620Model() temperature = SHT85() # attach peripherals to the system model, using the voltage regulator to power them system_model.attach_component('cc1101', radio, ComponentVoltageSource.VOLTAGE_REGULATOR) system_model.attach_component('0V7620', camera, ComponentVoltageSource.VOLTAGE_REGULATOR) system_model.attach_component('SHT85', temperature, ComponentVoltageSource.VOLTAGE_REGULATOR) # attach a peripheral to the system model, using the energy buffer to power it system_model.attach_component('generic_sensor', generic_sensor, ComponentVoltageSource.ENERGY_BUFFER) External NVM ------------ ScEpTIC allows to model external NVM to cover situations where MCUs lack a directly-addressable and internal NVM. ScEpTIC models external NVMs using the ``ExternalNVM`` class, located in ``ScEpTIC/emulator/energy/mcu_peripheral/external_nvm.py``. ``ExternalNVM`` initialization requires to supply the memory model as a parameter. ScEpTIC already implement the following NVMs: * MB85RC64V (I2C FRAM, 8kBytes) * MB85RC256V (I2C FRAM, 32kBytes) * MB85RS64V (SPI FRAM, 8kBytes) Note that ScEpTIC models the overhead of the I2C and SPI communication protocols. External NVM must be attached as custom component. For example, to initialize a MB85RC64V:: from ScEpTIC.emulator.energy.options import ComponentVoltageSource from ScEpTIC.emulator.energy.mcu_peripheral.options import MCUPeripheralPowerStateBehaviour from ScEpTIC.emulator.energy.mcu_peripheral.external_nvm import ExternalNVM external_fram = ExternalNVM('MB85RC64V') # Set power state behavior to follow the one of the MCU (on MCU power off, the NVM powers off) external_fram.set_power_state_behaviour(MCUPeripheralPowerStateBehaviour.FOLLOW_MCU) # OR set power state behavior to be always on (depeding on NVM minimum operating voltage) #external_fram.set_power_state_behaviour(MCUPeripheralPowerStateBehaviour.ALWAYS_ON) # attach NVM to the system model, powering it using the energy buffer system_model.attach_component('I2C_FRAM', external_fram, ComponentVoltageSource.ENERGY_BUFFER) State Retention --------------- ScEpTIC models the energy consumption of state-retention approaches, without requiring to implement them in the code. ScEpTIC supports two types of state retentions: ``InternalNVMCHeckpointEnergyModel`` for state retention techniques using NVM locations internal/directly addressable from the MCU, and ``ExternalCheckpointEnergyModel`` for state retention techniques using NVM locations external to the MCU. You can instantiate them as follows:: from ScEpTIC.emulator.energy.state_retention.external_checkpoint import ExternalNVMCheckpointEnergyModel state_retention = ExternalNVMCheckpointEnergyModel() # attach state retention model to the system model system_model.attach_state_retention(state_retention) from ScEpTIC.emulator.energy.state_retention.internal_checkpoint import InternalNVMCheckpointEnergyModel state_retention = InternalNVMCheckpointEnergyModel() # attach state retention model to the system model system_model.attach_state_retention(state_retention) Note that ``ExternalNVMCHeckpointEnergyModel`` requires that the system configuration contains an external NVM. Custom Devices -------------- ScEpTIC allows you to model the energy consumption and logic of custom external devices through the ``CustomDevice`` class, located at ``ScEpTIC/emulator/custom_devices``. Each custom device must extend the ``CustomDevice`` base class and override the following methods: * ``def setup(self, system_model)`` used to setup the circuitry components of the custom device * ``def init()`` used to initialize the component * ``def run_logic()`` used to simulate the device logic ScEpTIC already implement three custom devies: ``D2VFS``, ``FBTC``, and ``HibernusVoltageMonitor``. They are located in a corresponding directory inside ``ScEpTIC/emulator/custom_devices``. You can follow their implementation to understand how to implement your own custom device. D2VFS ***** This custom device implements the logic and energy consumption of |d2vfs| dynamic voltage and frequency scaling circuitry. You can instantiate D2VFS as follows:: from ScEpTIC.emulator.custom_devices.D2VFS import D2VFSSystemModel d2vfs = D2VFSSystemModel() # attach custom device to the system model system_model.attach_custom_device(d2vfs) FBTC **** This custom device implements the logic and energy consumption of |fbtc| dynamic voltage and frequency scaling circuitry. You can instantiate FBTC as follows:: from ScEpTIC.emulator.custom_devices.FBTC import FBTCSystemModel fbtc = FBTCSystemModel() # attach custom device to the system model system_model.attach_custom_device(fbtc) Hibernus ******** This custom device implements the energy consumption of |hibernus|. It automatically attaches Hibernus voltage monitor to the system energy model configuration. You can instantiate this component as follows:: from ScEpTIC.emulator.custom_devices.HibernusVoltageMonitor import HibernusVoltageMonitor hibernus = HibernusVoltageMonitor() # attach custom device to the system model system_model.attach_custom_device(hibernus) Note that Hibernus behavior is already available in ScEpTIC state-retention mechanisms. Time Keeper ----------- ScEpTIC supports basic offline timekeeper functionalities, which are implemented in the ``TimekeeperModel`` class, located in ``ScEpTIC/emulator/timekeeper``. You can instantiate a timekeeper as follows:: from ScEpTIC.emulator.energy.timekeeper import TimekeeperModel timekeeper = TimekeeperModel() # attach time keeper to the system model system_model.attach_time_keeper(time_keeper) To access timekeeper data, you can call ``sceptic_timekeeper_get_time()`` or ``sceptic_timekeeper_get_time_us()`` in your source code. The former gives you the elapsed seconds while the MCU was powered off, whereas the latter gives you the microseconds. Example of System Model ----------------------- Here is an example of a system model:: from ScEpTIC.emulator.energy.buffer.capacitor import CapacitorModel from ScEpTIC.emulator.energy.energy_harvester.charge_booster import ChargeBoosterEnergyHarvester from ScEpTIC.emulator.energy.energy_source.time_series_energy_source import TimeSeriesEnergySource from ScEpTIC.emulator.energy.mcu.msp430fr import MSP430FREnergyModel from ScEpTIC.emulator.energy.mcu.options import MCUPowerState, ADCPowerState from ScEpTIC.emulator.energy.mcu_peripheral.camera_0V7620 import Camera0V7620Model from ScEpTIC.emulator.energy.mcu_peripheral.cc1101 import CC1101Model from ScEpTIC.emulator.energy.options import ComponentVoltageSource from ScEpTIC.emulator.energy.options import PowerOffCondition from ScEpTIC.emulator.energy.power_state_event import PowerStateEvent from ScEpTIC.emulator.energy.state_retention.internal_checkpoint import InternalNVMCheckpointEnergyModel from ScEpTIC.emulator.energy.system_energy_model import SystemEnergyModel from ScEpTIC.emulator.energy.timekeeper import TimekeeperModel from ScEpTIC.emulator.energy.voltage_regulator.MAX20361 import MAX20361 # Configuration params config = { 'capacitance': '100u', 'cap_v_max': 5.0, 'mcu_v_on': 3.6, 'mcu_model': 'msp430fr5969', 'mcu_cache_hit': 0.85, 'mcu_lpm': 'LPM4', 'mcu_clock_frequency': '16MHz', 'energy_source': 'rf_mementos', 'load_resistance': '30K', 'harvester_resistance': '1', } # RF Energy Source energy_source = TimeSeriesEnergySource(config['energy_source']) energy_source.set_load_resistance(config['load_resistance']) energy_source.restart_on_trace_end = True # Charge Booster Energy Harvester charge_booster = MAX20361() # Voltage 1.5% higher than MCU Von to ensure power on charge_booster.set_output_voltage(config['mcu_v_on'] * 1.015) energy_harvester = ChargeBoosterEnergyHarvester(charge_booster, config['harvester_resistance']) energy_harvester.attach_energy_source(energy_source) # Energy buffer energy_buffer = CapacitorModel(config['capacitance'], config['cap_v_max'], None) # Start with full energy buffer energy_buffer.set_voltage(config['mcu_v_on']) # MCU mcu = MSP430FREnergyModel(config['mcu_model'], instruction_cache_hit_ratio=config['mcu_cache_hit']) mcu.set_frequency(config['mcu_clock_frequency']) mcu.set_target_lpm(config['mcu_lpm']) mcu.set_v_on(config['mcu_v_on']) mcu.set_mcu_state(MCUPowerState.ON) mcu.set_adc_state(ADCPowerState.OFF) # Timekeeper timekeeper = TimekeeperModel() # Peripherals radio = CC1101Model() camera = Camera0V7620Model() # System model system_model = SystemEnergyModel() system_model.attach_energy_buffer(energy_buffer) system_model.set_power_off_condition(PowerOffCondition.POWER_STATE_EVENT) system_model.add_power_off_event(PowerStateEvent.MCU_OFF) system_model.attach_energy_source_model(energy_source) system_model.attach_energy_harvester(energy_harvester) system_model.attach_mcu(mcu) # Do not use a voltage regulator for the system system_model.attach_voltage_regulator(None) system_model.attach_timekeeper(timekeeper) system_model.attach_component('cc1101', radio, ComponentVoltageSource.ENERGY_BUFFER) system_model.attach_component('0V7620', camera, ComponentVoltageSource.ENERGY_BUFFER) # State retention model state_retention = InternalNVMCheckpointEnergyModel() system_model.attach_state_retention_model(state_retention)