2026-07-10 10:38:57 +02:00

116 lines
3.7 KiB
Python

import math
from ScEpTIC.emulator.energy import energy_utils
from ScEpTIC.emulator.energy.mcu.options import MCUClockCycleAction, ADCPowerState
from ScEpTIC.emulator.energy.options import OpModeName
from ScEpTIC.emulator.energy.voltage_drawner import VoltageDrawner
class SHT85(VoltageDrawner):
"""
Energy model of a SHT85 digital temperature humidity sensor
https://sensirion.com/media/documents/4B40CEF3/640B2346/Sensirion_Humidity_Sensors_SHT85_Datasheet.pdf
"""
STATES = ['on', 'off']
CC_READ_COMMAND = 1
CC_READ_DATA = 2
datasheet = {
'V': 3.3,
'I_min': '600u',
'I_max': '1500u',
}
t_wakeup = '1.5m'
t_read = '15.5m'
def __init__(self):
self.state = 'off'
avg_i = (energy_utils.str_to_float(self.datasheet['I_min']) + energy_utils.str_to_float(self.datasheet['I_max'])) / 2.0
self.resistance = self.datasheet['V'] / avg_i
self.system_model = None
def attach_system_model(self, system_model):
self.system_model = system_model
def set_state(self, state):
"""
Set state (off, on)
"""
if state not in self.STATES:
raise Exception('SHT85 - Invalid state')
self.state = state
def simulate_set_state(self, state):
ticks = 0
# activate sensor
ticks += self.system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, OpModeName.SIMULATE_SENSOR)
# enter LPM and wait for sensor to be on
if state == 'on' and self.state == 'off':
ticks += self.system_model.run_step(MCUClockCycleAction.LPM_ENTER, OpModeName.LPM_ENTER)
lpm_start_time = self.system_model.get_simulation_time()
wait_time = energy_utils.str_to_float(self.t_wakeup)
lpm_end_time = lpm_start_time + wait_time
while self.system_model.get_simulation_time() < lpm_end_time:
ticks += self.system_model.run_step(MCUClockCycleAction.LPM_NOP, OpModeName.SIMULATE_SENSOR)
ticks += self.system_model.run_step(MCUClockCycleAction.LPM_EXIT, OpModeName.LPM_EXIT)
self.set_state(state)
return ticks
def simulate_read(self):
# Activate the sensor
ticks = self.simulate_set_state('on')
self.system_model.enable_lpm_precise_ticks()
# send read command
for _ in range(self.CC_READ_COMMAND):
ticks += self.system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, OpModeName.SIMULATE_SENSOR)
# enter LPM
ticks += self.system_model.run_step(MCUClockCycleAction.LPM_ENTER, OpModeName.LPM_ENTER)
lpm_start_time = self.system_model.get_simulation_time()
wait_time = energy_utils.str_to_float(self.t_read)
lpm_end_time = lpm_start_time + wait_time
while self.system_model.get_simulation_time() < lpm_end_time:
ticks += self.system_model.run_step(MCUClockCycleAction.LPM_NOP, OpModeName.SIMULATE_SENSOR)
ticks += self.system_model.run_step(MCUClockCycleAction.LPM_EXIT, OpModeName.LPM_EXIT)
# read data
for _ in range(self.CC_READ_DATA):
ticks += self.system_model.run_step(MCUClockCycleAction.NO_MEMORY_ACCESS, OpModeName.SIMULATE_SENSOR)
# Deactivate the sensor
ticks += self.simulate_set_state('off')
self.system_model.disable_lpm_precise_ticks()
return ticks
def get_drained_energy(self, t):
"""
Calculates the energy consumed by the component.
:param t: elapsed time
:return: the consumed energy
"""
voltage = self.voltage_source.get_voltage()
if self.state == 'off':
return 0.0
energy_from_R = energy_utils.energy_from_R_t(voltage, self.resistance, t)
return energy_from_R