mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-21 14:08:13 +00:00
258 lines
6.8 KiB
Python
258 lines
6.8 KiB
Python
import sys
|
|
from pathlib import Path
|
|
|
|
import matplotlib.pyplot as plt
|
|
from InquirerPy import inquirer
|
|
from InquirerPy.base import Choice
|
|
from utils import load_measured_data
|
|
|
|
default_dataset_dir = Path("../single_capture_test_results")
|
|
|
|
battery_thermal_limit = 45.0 # Celsius
|
|
case_thermal_limit = 41.0 # Celsius
|
|
|
|
|
|
def select_waveforms(dataset_directory=default_dataset_dir):
|
|
"""
|
|
Select waveforms from a given dataset directory.
|
|
|
|
Args:
|
|
dataset_directory (Path): The directory containing the dataset.
|
|
|
|
Returns:
|
|
list: A list of selected waveforms.
|
|
"""
|
|
|
|
if not dataset_directory.exists():
|
|
print(f"Dataset directory {dataset_directory} does not exist.")
|
|
return []
|
|
|
|
# glob all .csv files in the directory
|
|
all_csv_files = list(dataset_directory.glob("*.csv"))
|
|
if not all_csv_files:
|
|
print(f"No CSV files found in {dataset_directory}.")
|
|
return []
|
|
|
|
external_temp_files = list(dataset_directory.glob("external_temp.*.csv"))
|
|
|
|
# Filter out external temperature files
|
|
waveform_files = [f for f in all_csv_files if f not in external_temp_files]
|
|
|
|
choices = []
|
|
for waveform_file in waveform_files:
|
|
time_id = waveform_file.stem.split(".")[1]
|
|
|
|
ch = Choice(
|
|
name=f"{waveform_file.name}",
|
|
value={"waveform": waveform_file, "external_temp": None},
|
|
)
|
|
|
|
for temp_file in external_temp_files:
|
|
if time_id in temp_file.stem:
|
|
ch.name += " (ext. temp available)"
|
|
ch.value["external_temp"] = temp_file
|
|
break
|
|
|
|
choices.append(ch)
|
|
|
|
try:
|
|
selected = inquirer.fuzzy(
|
|
message="Select one or more waveforms:",
|
|
choices=choices,
|
|
multiselect=True,
|
|
instruction="(Use <tab> to select, <enter> to confirm)",
|
|
).execute()
|
|
|
|
except KeyboardInterrupt:
|
|
print("Selection cancelled by user.")
|
|
sys.exit(0)
|
|
|
|
except Exception as e:
|
|
print(f"An error occurred during selection: {e}")
|
|
sys.exit(1)
|
|
|
|
return selected
|
|
|
|
|
|
def colored_region_plot(axis, time_vector, data_vector, mask, color="red", alpha=0.5):
|
|
|
|
start = None
|
|
in_region = False
|
|
for i, val in enumerate(mask):
|
|
if val and not in_region:
|
|
start = i
|
|
in_region = True
|
|
elif not val and in_region:
|
|
axis.plot(
|
|
time_vector[start : i - 1],
|
|
data_vector[start : i - 1],
|
|
color=color,
|
|
alpha=alpha,
|
|
)
|
|
in_region = False
|
|
|
|
if in_region:
|
|
axis.plot(
|
|
time_vector[start : (i - 1)],
|
|
data_vector[start : i - 1],
|
|
color=color,
|
|
alpha=alpha,
|
|
)
|
|
|
|
|
|
def colored_region_box(axis, time_vector, mask, color="orange", alpha=0.5):
|
|
|
|
start = None
|
|
in_region = False
|
|
for i, val in enumerate(mask):
|
|
if val and not in_region:
|
|
start = i
|
|
in_region = True
|
|
elif not val and in_region:
|
|
axis.axvspan(
|
|
time_vector[start], time_vector[i - 1], color=color, alpha=alpha
|
|
)
|
|
in_region = False
|
|
|
|
if in_region:
|
|
axis.axvspan(time_vector[start], time_vector[-1], color=color, alpha=alpha)
|
|
|
|
|
|
def sec_to_min(time_vector):
|
|
return (time_vector - time_vector[0]) / 60.0
|
|
|
|
|
|
def plot_temperature_profile(waveform_name, profile_data):
|
|
|
|
fig, ax = plt.subplots(2)
|
|
fig.canvas.manager.set_window_title(waveform_name)
|
|
|
|
ax[0].plot(
|
|
sec_to_min(profile_data.time),
|
|
profile_data.battery_temp,
|
|
color="green",
|
|
label="battery temeperature",
|
|
)
|
|
ax[0].axhline(y=battery_thermal_limit, color="green", linestyle="--")
|
|
|
|
ax[0].plot(
|
|
sec_to_min(profile_data.time),
|
|
profile_data.pmic_die_temp,
|
|
color="orange",
|
|
label="pmic die temperature",
|
|
)
|
|
|
|
colored_region_plot(
|
|
ax[0],
|
|
sec_to_min(profile_data.time),
|
|
profile_data.battery_temp,
|
|
profile_data.battery_temp > battery_thermal_limit,
|
|
color="red",
|
|
alpha=1,
|
|
)
|
|
|
|
if profile_data.ext_temp is not None:
|
|
ax[0].plot(
|
|
sec_to_min(profile_data.ext_temp_time),
|
|
profile_data.ext_temp,
|
|
color="blue",
|
|
label="case temperature",
|
|
linestyle="--",
|
|
)
|
|
ax[0].axhline(y=case_thermal_limit, color="blue", linestyle="--")
|
|
|
|
colored_region_plot(
|
|
ax[0],
|
|
sec_to_min(profile_data.ext_temp_time),
|
|
profile_data.ext_temp,
|
|
profile_data.ext_temp > case_thermal_limit,
|
|
color="red",
|
|
alpha=1,
|
|
)
|
|
|
|
ax[0].set_xlabel("Time (min)")
|
|
ax[0].set_ylabel("Temperature (C)")
|
|
ax[0].set_title("Temperature Profile: " + waveform_name)
|
|
ax[0].set_xlim(
|
|
left=sec_to_min(profile_data.time)[0], right=sec_to_min(profile_data.time)[-1]
|
|
)
|
|
|
|
ax[0].legend()
|
|
ax[0].grid(True)
|
|
|
|
def min_to_hr(x):
|
|
return x / 60.0
|
|
|
|
def hr_to_min(x):
|
|
return x * 60.0
|
|
|
|
secax = ax[0].secondary_xaxis("top", functions=(min_to_hr, hr_to_min))
|
|
secax.set_xlabel("Time (hours)")
|
|
|
|
# Change background color according to charging state
|
|
usb_charging_mask = (profile_data.usb == "USB_connected") & (
|
|
abs(profile_data.battery_current) > 0
|
|
)
|
|
wlc_charging_mask = (
|
|
(profile_data.wlc == "WLC_connected")
|
|
& ~usb_charging_mask
|
|
& (abs(profile_data.battery_current) > 0)
|
|
)
|
|
colored_region_box(
|
|
ax[0], sec_to_min(profile_data.time), usb_charging_mask, color="blue", alpha=0.2
|
|
)
|
|
colored_region_box(
|
|
ax[0],
|
|
sec_to_min(profile_data.time),
|
|
wlc_charging_mask,
|
|
color="green",
|
|
alpha=0.2,
|
|
)
|
|
|
|
ax[1].plot(
|
|
sec_to_min(profile_data.time),
|
|
profile_data.battery_current,
|
|
color="purple",
|
|
label="battery current",
|
|
)
|
|
ax[1].set_xlabel("Time (min)")
|
|
ax[1].set_ylabel("Current (mA)")
|
|
ax[1].set_xlim(
|
|
left=sec_to_min(profile_data.time)[0], right=sec_to_min(profile_data.time)[-1]
|
|
)
|
|
ax[1].grid(True)
|
|
ax[1].legend()
|
|
|
|
colored_region_box(
|
|
ax[1], sec_to_min(profile_data.time), usb_charging_mask, color="blue", alpha=0.2
|
|
)
|
|
colored_region_box(
|
|
ax[1],
|
|
sec_to_min(profile_data.time),
|
|
wlc_charging_mask,
|
|
color="green",
|
|
alpha=0.2,
|
|
)
|
|
|
|
|
|
def main():
|
|
|
|
selected_waveforms = select_waveforms()
|
|
|
|
for waveform in selected_waveforms:
|
|
|
|
# Load data from files
|
|
profile_data = load_measured_data(
|
|
data_file_path=waveform["waveform"],
|
|
extern_temp_file_path=waveform["external_temp"],
|
|
)
|
|
|
|
plot_temperature_profile(waveform["waveform"].name, profile_data)
|
|
|
|
# Plot graphs
|
|
plt.show()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|