CovidBracelet/scripts/eval.py

297 lines
7.7 KiB
Python

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_avg = 0.00252
idle_max = 0.02325
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.00256
add_consumption(IDLE_LABEL, idle_consumption, 1.0, 1.0)
# ADVERTISING
adv_interval = 0.250
adv_consumptions = [
2.45,
2.47,
2.41,
2.35,
2.47,
2.39,
2.45,
2.47,
2.49,
2.45
]
adv_max_consumption = [
7.66,
8.31,
6.96,
7.3,
7.77,
7.6,
8.55,
6.94,
7.14,
6.85
]
# 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.004, (24*3600)/0.25)
# SCANNING
scan_consumption = 6.01
scan_consumption_max = 8.71
add_consumption('scan', scan_consumption, 2.015, 24*60)
crypt_duration = 0.01
crypt_consumption_avg = 3.2
crypt_consumption_max = 5.96
add_consumption('daily_crypto', crypt_consumption_avg, 0.22, 10)
# 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()