mirror of
https://github.com/CovidBraceletPrj/CovidBracelet.git
synced 2024-12-04 16:45:43 +01:00
WIP
This commit is contained in:
parent
d5277916d7
commit
b1173bfaff
280
scripts/eval.py
Normal file
280
scripts/eval.py
Normal file
@ -0,0 +1,280 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
import math
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from eval_utility import slugify, cached, init_cache, load_env_config
|
||||
|
||||
import matplotlib.ticker as ticker
|
||||
from matplotlib.ticker import PercentFormatter
|
||||
from matplotlib.ticker import (MultipleLocator, AutoMinorLocator)
|
||||
import matplotlib as mpl
|
||||
|
||||
VOLTS = 3.0
|
||||
|
||||
METHOD_PREFIX = 'export_'
|
||||
|
||||
CONFIDENCE_FILL_COLOR = '0.8'
|
||||
|
||||
NUM_NODES = 24
|
||||
|
||||
def load_plot_defaults():
|
||||
# Configure as needed
|
||||
plt.rc('lines', linewidth=2.0)
|
||||
plt.rc('legend', framealpha=1.0, fancybox=True)
|
||||
plt.rc('errorbar', capsize=3)
|
||||
plt.rc('pdf', fonttype=42)
|
||||
plt.rc('ps', fonttype=42)
|
||||
plt.rc('font', size=8, family="serif", serif=['Times New Roman'] + plt.rcParams['font.serif'])
|
||||
#mpl.style.use('tableau-colorblind10')
|
||||
|
||||
|
||||
IDLE_LABEL = 'idle'
|
||||
consumptions = {}
|
||||
durations = {}
|
||||
times_per_day = {}
|
||||
scaled_consumptions = {}
|
||||
raw_scaled_consumptions = {}
|
||||
|
||||
def add_consumption(label, consumption_msrmnt, duration, tpd, repetitions=1):
|
||||
consumptions[label] = consumption_msrmnt
|
||||
durations[label] = duration/repetitions
|
||||
times_per_day[label] = tpd
|
||||
|
||||
|
||||
def calculate_usage_seconds_per_day(labels, normalize_with_idle=True):
|
||||
# we first calculate the times for each label
|
||||
usage_seconds = {
|
||||
IDLE_LABEL: 0
|
||||
}
|
||||
sum = 0
|
||||
for l in labels:
|
||||
if l == IDLE_LABEL:
|
||||
continue
|
||||
usage_seconds[l] = durations[l]*times_per_day[l]
|
||||
assert 0 <= usage_seconds[l] <= 24*3600.0
|
||||
sum += usage_seconds[l]
|
||||
|
||||
if sum < 24*3600.0:
|
||||
usage_seconds[IDLE_LABEL] = 24*3600.0-sum # we spent the rest of the time idling!
|
||||
|
||||
cons_per_day = {}
|
||||
for l in labels:
|
||||
cons_per_day[l] = usage_seconds[l] # also convert to ampere hours!
|
||||
return cons_per_day
|
||||
|
||||
def calculate_consumption_per_day(labels, normalize_with_idle=True):
|
||||
# we first calculate the times for each label
|
||||
usage_seconds = {
|
||||
IDLE_LABEL: 0
|
||||
}
|
||||
sum = 0
|
||||
for l in labels:
|
||||
if l == IDLE_LABEL:
|
||||
continue
|
||||
usage_seconds[l] = durations[l]*times_per_day[l]
|
||||
assert 0 <= usage_seconds[l] <= 24*3600.0
|
||||
sum += usage_seconds[l]
|
||||
|
||||
if sum < 24*3600.0:
|
||||
usage_seconds[IDLE_LABEL] = 24*3600.0-sum # we spent the rest of the time idling!
|
||||
|
||||
cons_per_day = {}
|
||||
for l in labels:
|
||||
cons_per_day[l] = consumptions[l]*usage_seconds[l]*(1/3600.0) # also convert to ampere hours!
|
||||
return cons_per_day
|
||||
|
||||
|
||||
# calculate the remaining idle time
|
||||
|
||||
|
||||
|
||||
# THE TOTAL EXPECTED AMOUNT PER DAY in milli ampere
|
||||
expected_consumption_per_day = 0.0
|
||||
|
||||
idle_consumption = 0.500
|
||||
add_consumption(IDLE_LABEL, idle_consumption, 1.0, 1.0)
|
||||
|
||||
# ADVERTISING
|
||||
adv_interval = 0.250
|
||||
per_adv_consumption = {
|
||||
0: 2.23,
|
||||
-4: 1.49 ,
|
||||
-8: 1.43,
|
||||
-16: 1.38,
|
||||
-20: 1.3,
|
||||
-40: 1.22,
|
||||
}
|
||||
# TODO: Add error bars if possible!
|
||||
# measured_duration
|
||||
# duration
|
||||
# repetitions
|
||||
|
||||
|
||||
adv_consumption = sum(list(per_adv_consumption.values())) / len(per_adv_consumption.values())
|
||||
|
||||
add_consumption('adv', adv_consumption, 0.01, (24*3600)/0.25)
|
||||
|
||||
# SCANNING
|
||||
scan_consumption = 5.440
|
||||
add_consumption('scan', scan_consumption, 1.0, 24*60)
|
||||
|
||||
|
||||
crypt_duration = 0.01
|
||||
generate_tek_consumption = 2
|
||||
derive_tek_consumption = 2
|
||||
derive_rpi_consumption = 2
|
||||
encrypt_aem_consumption = 2
|
||||
|
||||
add_consumption('generate_tek', generate_tek_consumption, crypt_duration, 1)
|
||||
add_consumption('derive_tek', derive_tek_consumption, crypt_duration, 1)
|
||||
add_consumption('derive_rpi', derive_rpi_consumption, crypt_duration, 144)
|
||||
add_consumption('encrypt_aem', encrypt_aem_consumption, crypt_duration, 144*len(per_adv_consumption.values()))
|
||||
|
||||
# A table for the timings of the cryptographic fundamentals
|
||||
# One detailed graph as a comparison of the advertisements
|
||||
# One bar graph for each of the factors involved in the daily energy usage
|
||||
|
||||
tek_check_duration = 0.020
|
||||
tek_check_amount = 32
|
||||
tek_check_consumption = 4
|
||||
|
||||
# generate graph with keys to check
|
||||
# Worst case scenario: Flash is fully used!
|
||||
# we generate a bloom filter of all records!
|
||||
|
||||
|
||||
# How long does it take to create the bloom filter for the whole dataset?
|
||||
#64kByte
|
||||
|
||||
|
||||
|
||||
# then check keys (i.e., maybe 32 teks at once?)
|
||||
# measure time
|
||||
# measure consumption
|
||||
# extrapolate numbers for more keys!
|
||||
|
||||
# We then get keys to check
|
||||
# 1000, 10000, 100000
|
||||
|
||||
|
||||
def export_adv_consumption():
|
||||
|
||||
xs = [per_adv_consumption[0], per_adv_consumption[-4], per_adv_consumption[-8], per_adv_consumption[-16], per_adv_consumption[-20], per_adv_consumption[-40]]
|
||||
ys = ['0', '-4', '-8', '-16', '-20', '-40']
|
||||
|
||||
width = 0.6 # the width of the bars: can also be len(x) sequence
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
ax.set_ylabel('Avg. Advertising Current [µA]')
|
||||
ax.set_xlabel('TX Power [dBm]')
|
||||
|
||||
bars = ax.bar(ys,xs)
|
||||
ax.bar_label(bars, padding=5, fmt='%.2f')
|
||||
|
||||
#ax.set_title('')
|
||||
#ax.legend() # (loc='upper center', bbox_to_anchor=(0.5, -0.5), ncol=2)
|
||||
|
||||
# Adapt the figure size as needed
|
||||
fig.set_size_inches(3.5, 3.2)
|
||||
plt.tight_layout()
|
||||
plt.savefig("../out/adv_consumption.pdf", format="pdf", bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
|
||||
def export_consumption_per_day():
|
||||
cpd = calculate_consumption_per_day([
|
||||
IDLE_LABEL, 'adv', 'scan', 'generate_tek', 'derive_tek', 'derive_rpi', 'encrypt_aem'
|
||||
])
|
||||
print(sum(cpd.values()))
|
||||
ys = ['Idle', 'Adv.', 'Scan', 'Crypto\n(Daily)']
|
||||
xs = [cpd[IDLE_LABEL], cpd['adv'], cpd['scan'], cpd['generate_tek']+cpd['derive_tek']+cpd['derive_rpi']+ cpd['encrypt_aem']]
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
ax.set_ylabel('Avg. Consumption per Day [mA h]')
|
||||
ax.set_xlabel('Functionality')
|
||||
|
||||
bars = ax.bar(ys,xs)
|
||||
ax.bar_label(bars, padding=5, fmt='%.2f')
|
||||
|
||||
# Adapt the figure size as needed
|
||||
fig.set_size_inches(3.5, 3.2)
|
||||
plt.tight_layout()
|
||||
plt.savefig("../out/weighted_consumption.pdf", format="pdf", bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
|
||||
def export_usage_seconds_per_day():
|
||||
cpd = calculate_usage_seconds_per_day([
|
||||
IDLE_LABEL, 'adv', 'scan', 'generate_tek', 'derive_tek', 'derive_rpi', 'encrypt_aem'
|
||||
])
|
||||
print(sum(cpd.values()))
|
||||
ys = ['Idle', 'Adv.', 'Scan', 'Crypto\n(Daily)']
|
||||
xs = [cpd[IDLE_LABEL], cpd['adv'], cpd['scan'], cpd['generate_tek']+cpd['derive_tek']+cpd['derive_rpi']+ cpd['encrypt_aem']]
|
||||
xs = [x/(24*3600) for x in xs]
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
ax.set_ylabel('Estimated Duration per Day [%]')
|
||||
ax.set_xlabel('Functionality')
|
||||
|
||||
bars = ax.bar(ys,xs)
|
||||
ax.bar_label(bars, padding=5, fmt='%.2f')
|
||||
|
||||
# Adapt the figure size as needed
|
||||
fig.set_size_inches(3.5, 3.2)
|
||||
plt.tight_layout()
|
||||
plt.savefig("../out/export_usage_seconds_per_day.pdf", format="pdf", bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
def export_current_per_functionality():
|
||||
|
||||
ys = ['Idle', 'Adv.', 'Scan', 'Daily\nSecret', 'TEK', 'RPI', 'AEM']
|
||||
xs = [consumptions[IDLE_LABEL], consumptions['adv'], consumptions['scan'], consumptions['generate_tek'], consumptions['derive_tek'], consumptions['derive_rpi'], consumptions['encrypt_aem']]
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
ax.set_ylabel('Avg. Consumption [mA]')
|
||||
ax.set_xlabel('Functionality')
|
||||
|
||||
bars = ax.bar(ys,xs)
|
||||
ax.bar_label(bars, padding=5, fmt='%.2f')
|
||||
|
||||
# Adapt the figure size as needed
|
||||
fig.set_size_inches(4.5, 3.2)
|
||||
plt.tight_layout()
|
||||
plt.savefig("../out/current_per_functionality.pdf", format="pdf", bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
def export_tek_check():
|
||||
tek_check_duration = 0.020
|
||||
|
||||
xs = [1000, 10000, 1000000]
|
||||
ys = [x*tek_check_duration for x in xs]
|
||||
|
||||
xs = [str(x) for x in xs]
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
ax.set_ylabel('Extrapolated Time [s]')
|
||||
ax.set_xlabel('Number of TEKs')
|
||||
|
||||
bars = ax.bar(xs,ys)
|
||||
ax.bar_label(bars, padding=5, fmt='%d')
|
||||
|
||||
# Adapt the figure size as needed
|
||||
fig.set_size_inches(4.5, 3.2)
|
||||
plt.tight_layout()
|
||||
plt.savefig("../out/tek_check.pdf", format="pdf", bbox_inches='tight')
|
||||
plt.close()
|
||||
|
||||
|
||||
export_adv_consumption()
|
||||
export_usage_seconds_per_day()
|
||||
export_consumption_per_day()
|
||||
export_current_per_functionality()
|
||||
export_tek_check()
|
55
scripts/eval_utility.py
Normal file
55
scripts/eval_utility.py
Normal file
@ -0,0 +1,55 @@
|
||||
import re
|
||||
import gzip
|
||||
import json
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
# https://stackoverflow.com/a/46801075/6669161
|
||||
def slugify(s):
|
||||
if not isinstance(s, str):
|
||||
s = " ".join(str(x) for x in s)
|
||||
s = str(s).strip().replace(' ', '_')
|
||||
return re.sub(r'(?u)[^-\w.]', '', s)
|
||||
|
||||
def load_env_config():
|
||||
import dotenv
|
||||
return {
|
||||
**dotenv.dotenv_values(".env"), # load shared development variables
|
||||
**dotenv.dotenv_values(".env.local"), # load sensitive variables
|
||||
**os.environ, # override loaded values with environment variables
|
||||
}
|
||||
|
||||
# Source: https://github.com/mpld3/mpld3/issues/434#issuecomment-340255689
|
||||
class NumpyEncoder(json.JSONEncoder):
|
||||
""" Special json encoder for numpy types """
|
||||
def default(self, obj):
|
||||
if isinstance(obj, (np.int_, np.intc, np.intp, np.int8,
|
||||
np.int16, np.int32, np.int64, np.uint8,
|
||||
np.uint16, np.uint32, np.uint64)):
|
||||
return int(obj)
|
||||
elif isinstance(obj, (np.float_, np.float16, np.float32,
|
||||
np.float64)):
|
||||
return float(obj)
|
||||
elif isinstance(obj,(np.ndarray,)):
|
||||
return obj.tolist()
|
||||
return json.JSONEncoder.default(self, obj)
|
||||
|
||||
|
||||
export_cache_dir = None
|
||||
|
||||
def cached(id, proc_cb=None):
|
||||
if export_cache_dir:
|
||||
cache_file = os.path.join(export_cache_dir, slugify(id) + '.json.gz')
|
||||
if not os.path.isfile(cache_file):
|
||||
data = proc_cb()
|
||||
with gzip.open(cache_file, 'wt', encoding='UTF-8') as zipfile:
|
||||
json.dump(data, zipfile, cls=NumpyEncoder)
|
||||
with gzip.open(cache_file, 'rt', encoding='UTF-8') as json_file:
|
||||
return json.load(json_file)
|
||||
else:
|
||||
return proc_cb()
|
||||
|
||||
def init_cache(path):
|
||||
global export_cache_dir
|
||||
export_cache_dir = path
|
||||
os.makedirs(export_cache_dir, exist_ok=True)
|
0
scripts/gateway.py
Normal file
0
scripts/gateway.py
Normal file
@ -25,9 +25,10 @@
|
||||
|
||||
typedef ENIntervalIdentifier ENIntervalIdentifier;
|
||||
|
||||
#define RPI_ROTATION_MS (11*60*1000)
|
||||
#define SCAN_INTERVAL_MS (4*1000)
|
||||
#define SCAN_DURATION_MS 1000
|
||||
#define RPI_ROTATION_MS_MIN (500*1000)
|
||||
#define RPI_ROTATION_MS_MAX (1250*1000)
|
||||
#define SCAN_INTERVAL_MS (5*60*1000)
|
||||
#define SCAN_DURATION_MS 2000
|
||||
#define ADV_INTERVAL_MS 250
|
||||
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
|
||||
# Bluetooth Settings
|
||||
CONFIG_BT=y
|
||||
CONFIG_BT_BROADCASTER=y
|
||||
CONFIG_BT_OBSERVER=y
|
||||
@ -7,6 +9,7 @@ CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_DEVICE_NAME="CWB"
|
||||
CONFIG_ENTROPY_GENERATOR=y
|
||||
|
||||
# Crypto Settings
|
||||
CONFIG_MBEDTLS=y
|
||||
CONFIG_MBEDTLS_USER_CONFIG_ENABLE=y
|
||||
CONFIG_MBEDTLS_USER_CONFIG_FILE="user-tls.conf"
|
||||
@ -28,9 +31,7 @@ CONFIG_MPU_ALLOW_FLASH_WRITE=y
|
||||
# CONFIG_DISK_ACCESS=y
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
|
||||
# Let __ASSERT do its job
|
||||
CONFIG_DEBUG=y
|
||||
CONFIG_LOG=y
|
||||
|
||||
|
||||
CONFIG_NEWLIB_LIBC=y
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=131072
|
||||
@ -39,17 +40,21 @@ CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
|
||||
|
||||
# max contacts, that can be stored
|
||||
CONFIG_ENS_MAX_CONTACTS=65536
|
||||
|
||||
CONFIG_TIMING_FUNCTIONS=y
|
||||
|
||||
CONFIG_LOG=y
|
||||
#CONFIG_TIMING_FUNCTIONS=y
|
||||
|
||||
CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y
|
||||
|
||||
CONFIG_SERIAL=n
|
||||
|
||||
|
||||
# DEBUG!
|
||||
# Let __ASSERT do its job
|
||||
CONFIG_DEBUG=y
|
||||
CONFIG_LOG=y
|
||||
|
||||
# # Run protobuf unpack tests at startup
|
||||
# CONFIG_TEST_UNPACK_KEYS_N=12
|
||||
# CONFIG_TEST_UNPACK_KEYS=y
|
||||
|
||||
# # Run bloom filter tests at startup
|
||||
# CONFIG_CONTACTS_PERFORM_RISC_CHECK_TEST=y
|
||||
# CONFIG_CONTACTS_BLOOM_REVERSE=y
|
||||
|
Loading…
Reference in New Issue
Block a user