Penn Electric Racing Data Analyzer: PERDA#
PERDA is PER’s in-house data analysis library designed to streamline the process of analyzing vehicle data logs.
Load Data (local csv)#
[ ]:
from perda.analyzer import Analyzer
from perda.utils import patch_ned_velocity
csvPath = "csv_files/16thApr10-52-00.csv"
aly = Analyzer(csvPath, preprocessing=[patch_ned_velocity])
# Print summary of the loaded data
print(aly)
Load Data (via server)#
[ ]:
from perda.analyzer import Analyzer
from perda.server import ServerClient
# Fill in our server address and password
client = ServerClient("http://198.74.62.28:5000/")
# Optional cache_dir to download and load logs
# client = ServerClient("http://198.74.62.28:5000/", cache_dir="~/.perda/cache/")
# Please fill in password, you should know what it is... :)
client.login("FILL")
[ ]:
# Find your log by changing the path
client.print_logs("REV 11/")
[ ]:
# Get/download analyzer via log path on server
aly = client.load("REV 11/2026-04-01/test.csv")
# Print summary of the loaded data
print(aly)
Search Data#
[ ]:
search_results = aly.search("vectornav")
Inspect Data#
[ ]:
from perda.utils import data_instance_summary
# Print individual variable's info
data_instance_summary(
aly.data["bms.pack.current"], source_time_unit="ms"
) # change source_time_unit to us if using car logs
# Print the same variable, but accessing the data structure using variable ID instead
data_instance_summary(aly.data[422], source_time_unit="ms")
Graph GPS#
[ ]:
from perda.utils import create_representative_gps_image
lat = aly.data["pcm.vnav.posLla.latitude"] # Put latitude data here, if any
lon = aly.data["pcm.vnav.posLla.longitude"] # Put longitude data here, if any
vel = aly.data[
"pcm.wheelSpeeds.frontLeft"
] # Put velocity data here, optional but recommended
create_representative_gps_image(lat, lon, vel)
Graph Variables (Single Y-Axis)#
[ ]:
# Variables to graph
variables = [
"pcm.moc.motor.requestedTorque",
"pcm.moc.motor.wheelSpeed",
"bms.pack.power",
"bms.pack.voltage",
]
aly.plot(variables)
Graph Variables (Dual Y-Axis)#
[ ]:
# Variables to graph
variables_left = [
"pcm.wheelSpeeds.frontLeft",
"pcm.wheelSpeeds.frontRight",
"pcm.wheelSpeeds.backLeft",
"pcm.wheelSpeeds.backRight",
]
variables_right = [
"bms.stack.mma.temp.avg",
"bms.stack.mma.dieTemp.avg",
422, # We can also specify variables by variable ID
]
aly.plot(
var_1=variables_left,
var_2=variables_right,
title="Dual Y-Axis Example",
y_label_1="Wheel Speeds (MPH)",
y_label_2="Minion Temperature Data",
)
Data Manipulation#
The core of PERDA is the DataInstance class. Each variable is stored as a DataInstance object.
[ ]:
from perda.utils import data_instance_summary
# Retrieve DataInstances
current = aly.data["bms.pack.current"]
voltage = aly.data["bms.pack.voltage"]
# Print info for current
data_instance_summary(current)
# Basic arithmetic operators are overloaded for DataInstances
current_plus = current + 10 # Creates a new DataInstance that is
# 10 higher than current at every timestamp
current_plus.label = "current + 10" # Assign our new DataInstance a label
data_instance_summary(current_plus)
# One example of a practical use case is calculating power from current and voltage
power_cal = (current * voltage) / 1000
power_cal.label = "power calculated"
[ ]:
# Let's compare calculated power with ams.pack.power
variables = [
"bms.pack.power",
power_cal,
]
aly.plot(var_1=variables)
Custom Variables#
[ ]:
from perda.analyzer import DataInstance
from perda.utils import data_instance_summary
import numpy as np
# We can also create our own DataInstances
my_ts = np.arange(2000000)
my_val = my_ts / 1e3 - 1000
my_di = DataInstance(timestamp_np=my_ts, value_np=my_val, label="Line_Data", var_id=1)
data_instance_summary(my_di)
[ ]:
aly.plot(var_1=my_di)