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)
../_images/576cda6e333139b21bca14da936c0861aee8398215a51f70d7ba09c513942e65.png

… or only one curve …

_ = df[df.columns[0]].plot(kind="line")
../_images/c16ad719a77565e0294a15ffffb0f36453c420f56b9a5a5bec0282bb29679a8b.png

… 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.