Load Measurement Data (Time Series)#
In this example Notebook, we show you how to load time series (channel) data from your Peak ODS Server.
The first sections are on initializing and connecting. The fun starts with “Load Measurement”.
Dependencies for this notebook#
The ASAM ODSBox contain some functionality that wraps the ODS HTTP API making using Python easier ;-)
It contains:
http wrapper implemented using protobuf and requests
utility that converts ODS DataMatrices into pandas.DataFrame
try:
import odsbox
except:
!pip install odsbox
from odsbox.con_i import ConI
from odsbox.submatrix_to_pandas import submatrix_to_pandas
Connect to ASAM ODS server#
The ODS HTTP API is a session based API. The session ID is called conI in the ODS documentation. The ASAM ODSBox uses con_i as API object representing the session. Close this session to release the connection license. Otherwise the session will be auto closed after 30 minutes of inactivity.
con_i = ConI(url='http://79.140.180.128:10032/api', auth=('Demo','mdm'))
Load Measurement#
Query for available measurement data#
Measurement (or time series) data is contained in a structure called ‘Submatrix’ containing the individual channels (columns) of the measurement. In the example below the first 10 submatrices of some MDF4 files (see query pattern) are requested from the server. Let’s pick the first submatrix of that list for further data exploration.
sms = con_i.query_data({
# "SubMatrix": {"measurement.test.Name": {"$like": "Profile*.mf4"}},
"SubMatrix": {"measurement.Name": {"$like": "Profile*"}},
"$attributes": {
"Name": 1,
"Id": 1
},
"$options": {"$rowlimit": 10}
})
print(sms)
# just pick the first one
submatrix_id = sms["SubMatrix.Id"].iloc[0]
print("Submatrix id: " + str(submatrix_id))
SubMatrix.Name SubMatrix.Id
0 Profile_56 297
1 Profile_76 298
2 Profile_61 299
3 Profile_69 300
4 Profile_45 301
5 Profile_55 302
6 Profile_51 303
7 Profile_70 304
8 Profile_54 306
9 Profile_59 307
Submatrix id: 297
Load measurement data and convert to DataFrame#
From our imported library we use ‘submatrix_to_dataframe’ to get a pandas.DataFrame from that submatrix we’ve selected above…
df = submatrix_to_pandas(con_i, submatrix_id)
if "Time" in df.columns:
df.set_index("Time", inplace=True)
elif "time" in df.columns:
df.set_index("time", inplace=True)
df.head()
U_q | Coolant | Stator_winding | U_d | Stator_tooth | Motor_speed | I_d | I_q | Pm | Stator_yoke | Ambient | Torque | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Time | ||||||||||||
0.0 | 0.952783 | 90.727609 | 87.146673 | -0.204597 | 85.926141 | 0.456684 | -2.001956 | 1.096882 | 74.009240 | 86.390770 | 25.305479 | 8.405353e-40 |
0.5 | 2.475837 | 90.706851 | 87.127266 | -0.020058 | 85.938663 | 45.193413 | -2.352413 | -2.355965 | 74.011489 | 86.343487 | 25.287223 | -2.465794e+00 |
1.0 | 6.688818 | 90.700972 | 87.152911 | 0.375610 | 85.942543 | 148.292486 | -2.620045 | -4.937004 | 74.010871 | 86.290301 | 25.306941 | -4.309906e+00 |
1.5 | 12.895296 | 90.694511 | 87.160676 | 0.949208 | 85.943236 | 293.049078 | -2.840353 | -6.937861 | 74.006943 | 86.292164 | 25.315282 | -5.741626e+00 |
2.0 | 20.546038 | 90.703373 | 87.168169 | 1.763395 | 85.946817 | 467.625270 | -3.030668 | -8.667006 | 74.006793 | 86.308939 | 25.313541 | -6.976574e+00 |
Working with the DataFrame#
Now that the data is in a DataFrame, you can use all operations supported on DataFrames. So let’s dump the content of the DataFrame:
df.describe()
U_q | Coolant | Stator_winding | U_d | Stator_tooth | Motor_speed | I_d | I_q | Pm | Stator_yoke | Ambient | Torque | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 33123.000000 | 33123.000000 | 33123.000000 | 33123.000000 | 33123.000000 | 33123.000000 | 33123.000000 | 33123.000000 | 33123.000000 | 33123.000000 | 33123.000000 | 33123.000000 |
mean | 67.712335 | 58.899453 | 92.553726 | -20.714359 | 81.703319 | 2360.830408 | -74.106438 | 2.514944 | 77.534026 | 72.057477 | 26.882020 | 4.920972 |
std | 37.097723 | 20.461698 | 22.161028 | 72.732526 | 17.472679 | 1291.338157 | 52.504769 | 128.504393 | 10.991158 | 16.506447 | 0.619549 | 105.270414 |
min | -9.305150 | 17.354847 | 45.986175 | -131.234010 | 45.733880 | 0.456684 | -269.072268 | -293.426793 | 53.955221 | 39.307843 | 19.849699 | -246.466663 |
25% | 37.464195 | 39.633733 | 77.436864 | -93.881841 | 67.214455 | 1397.810081 | -99.579849 | -110.108606 | 69.458324 | 57.440199 | 26.384514 | -83.100255 |
50% | 65.954024 | 59.938400 | 95.969894 | -14.983064 | 87.076511 | 2237.634633 | -67.957561 | 10.460382 | 79.641092 | 75.338748 | 26.560787 | 7.240760 |
75% | 98.125913 | 75.553992 | 110.731653 | 40.943274 | 95.070421 | 3170.851708 | -32.165739 | 102.446312 | 85.588273 | 85.839370 | 27.402148 | 87.906554 |
max | 133.009676 | 91.180365 | 131.675086 | 123.049144 | 110.074551 | 5981.344042 | -2.001956 | 294.683193 | 97.552674 | 97.601695 | 28.126869 | 244.555683 |
… and we can plot some curves (remember we set ‘time’ to be the index at the beginning) …
_ = df.plot(kind="line", subplots=True, layout=(6,3), sharex=True)
… or only one curve …
_ = df[df.columns[0]].plot(kind="line")
… or get some information of the index channel - time axis should be monotonic ;-)
df.index.is_monotonic_increasing
True
Close Session#
Don’t forget to close the session to release the connection license. Otherwise the session will be auto closed after 30 minutes of inactivity.
con_i.logout()
License#
Copyright © 2024 Peak Solution GmbH
The training material in this repository is licensed under a Creative Commons BY-NC-SA 4.0 license. See LICENSE file for more information.