Process PI Data Using Common MATLAB Operations
This example shows you how to process PI data using common MATLAB® timetable operations.
The PI Data Archive is capable of storing decades of real-time data from hundreds of assets. Running this example assumes a PI Data Archive available for connection. The demo tags used in this example were provided by AVEVA and can be downloaded from AVEVA sharefile.
Create Client/Server Connection and Retrieve Required Tags
Connect to the PI Data Archive using the piclient
function. In this example the Windows computer name is used as the PI Data Archive name. Your situation might vary depending on the PI System configuration.
host = getenv("COMPUTERNAME");
client = piclient(host);
Request a list of tags
related to the asset of interest. For more detailed information see Get Started Accessing a PI Data Archive.
tagsGenerator = tags(client, Name = "OSIDemo_GU1 Generator*")
tagsGenerator=28×1 table
Tags
_____________________________________________________________________________________________
"OSIDemo_GU1 Generator.Active Power.4db83f0a-ff87-5c67-385a-83cfe3ac560d"
"OSIDemo_GU1 Generator.Axial Vibration.373a6144-442d-5e69-1079-5986bf866fa1"
"OSIDemo_GU1 Generator.Bearing Temperature.3cfb845c-000c-5cf2-2ca0-b47dfdcfb4d7"
"OSIDemo_GU1 Generator.Bearing Vibration.ac4f121c-0633-5a0d-3e26-e8d6a6249515"
"OSIDemo_GU1 Generator.Cooling Water Intake Temperature.2b0243be-4a97-5a48-1337-0e0b242c4795"
"OSIDemo_GU1 Generator.Cooling Water Output Temperature.7d1a79de-1957-5efc-1d55-aa5fcfccf36a"
"OSIDemo_GU1 Generator.Cooling Water Pressure.0c723cab-80c6-5630-13bf-38fdd7092768"
"OSIDemo_GU1 Generator.Core Temperature.79a1a7b5-5425-51ba-0bd6-ea1d6fbc4b86"
"OSIDemo_GU1 Generator.Current Phase A.07815f38-c5b4-5abc-3d7c-2b0d4cd303ac"
"OSIDemo_GU1 Generator.Current Phase B.7e11e986-d6e3-5f51-241a-23cc597bde31"
"OSIDemo_GU1 Generator.Current Phase C.02c2ac50-14f7-5a5a-2e97-8b7d24851468"
"OSIDemo_GU1 Generator.Frequency.8886141f-470a-514e-22d9-ef9e6aceaf95"
"OSIDemo_GU1 Generator.Hours Since Last Maintenance.cb867a54-053b-5616-1a4a-dfa68f6b454c"
"OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9"
"OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464"
"OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536"
⋮
Find All Tags from List Related to Voltage
Refine the list of tags using the contains
function. This groups together all tags related to line voltages for use later in the example.
tagsVoltage = tagsGenerator(contains(tagsGenerator.Tags,"Voltage"),:)
tagsVoltage=3×1 table
Tags
____________________________________________________________________________
"OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9"
"OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464"
"OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536"
Read Latest Value of Multiple Tags
Read the latest value multiple tags using the read
function, and specifying a range of tags.
voltageLatestTT = read(client, tagsVoltage.Tags(1:3))
voltageLatestTT=3×3 timetable
Time Tag Value Status
_________________________ ____________________________________________________________________________ _____ ______
21-December-2021 15:45:00 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" 3.31 Good
21-December-2021 15:45:00 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.32 Good
21-December-2021 15:45:00 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" 3.29 Good
Read All Recorded Values of Multiple Tags
To read all recorded values of a tag, it is useful to know when data recording began. You can use the Earliest
Name-Value pair to determine this. Notice that all three of the tags from tagsVoltage
are passed to the read
function.
voltageEarliestTT = read(client, tagsVoltage.Tags(1:3), Earliest=true)
voltageEarliestTT=3×3 timetable
Time Tag Value Status
_________________________ ____________________________________________________________________________ _____ ______
04-November-2021 20:25:12 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" NaN Bad
04-November-2021 20:25:12 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" NaN Bad
04-November-2021 20:25:12 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" NaN Bad
Notice the value of this tag at the earliest recorded time is a NaN. This is often the case for the first data point in a series as the PI Data Archive indicates a status of Bad for this data point upon creation. You can exclude this from your data set if desired.
This earliest data point identifies the time of the first recorded value. You can now use this information to establish a starting datetime
for your request.
startDate = datetime(voltageEarliestTT.Time(1)); endDate = datetime("now", TimeZone="local");
Depending on your system, this query might return a large amount of data. If you have an extensive history of data that makes this too slow or impractical, you can skip this step.
voltageAllTT = read(client, tagsVoltage.Tags(1:3), DateRange=[startDate,endDate])
voltageAllTT=29815×3 timetable
Time Tag Value Status
_________________________ ____________________________________________________________________________ _____ ______
04-November-2021 20:25:12 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" NaN Bad
04-November-2021 20:25:12 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" NaN Bad
04-November-2021 20:25:12 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" NaN Bad
04-November-2021 20:30:00 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" 3.28 Good
04-November-2021 20:30:00 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.32 Good
04-November-2021 20:30:00 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" 3.32 Good
04-November-2021 20:35:00 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.3 Good
04-November-2021 20:40:00 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" 3.31 Good
04-November-2021 20:40:00 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.3 Good
04-November-2021 20:45:00 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" 3.31 Good
04-November-2021 20:45:00 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.28 Good
04-November-2021 20:50:00 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" 3.29 Good
04-November-2021 20:50:00 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.28 Good
04-November-2021 20:50:00 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" 3.32 Good
04-November-2021 20:55:00 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.32 Good
04-November-2021 20:55:00 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" 3.3 Good
⋮
Reduce Data Set Using Linear Interpolation Provided by PI Server
Notice the large number of datapoints in the result of the previous step. You can reduce the data set by using the Interval
Name-Value pair. For example the following read requests data with an interval of 4 hours. The Interval
Name-Value pair requests the PI Server to perform linear interpolation on recorded values and provide results at the specified interval.
voltageInterpolatedTT = read(client, tagsVoltage.Tags(1:3), DateRange=[startDate,endDate], Interval=hours(4))
voltageInterpolatedTT=843×3 timetable
Time Tag Value Status
_________________________ ____________________________________________________________________________ ______ ______
04-November-2021 20:25:12 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" NaN Bad
04-November-2021 20:25:12 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" NaN Bad
04-November-2021 20:25:12 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" NaN Bad
05-November-2021 00:25:12 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" 3.2908 Good
05-November-2021 00:25:12 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.3053 Good
05-November-2021 00:25:12 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" 3.32 Good
05-November-2021 04:25:12 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" 3.2805 Good
05-November-2021 04:25:12 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.2808 Good
05-November-2021 04:25:12 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" 3.32 Good
05-November-2021 08:25:12 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" 3.3102 Good
05-November-2021 08:25:12 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.3194 Good
05-November-2021 08:25:12 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" 3.2912 Good
05-November-2021 12:25:12 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" 3.3047 Good
05-November-2021 12:25:12 "OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2a1f0096c464" 3.3092 Good
05-November-2021 12:25:12 "OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d2c1f98bf536" 3.3196 Good
05-November-2021 16:25:12 "OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a312f1aa02e9" 3.2832 Good
⋮
Unstack Values from One Timetable Variable to Multiple Variables
Unstack the timetable to distribute each line voltage as a timetable variable.
uVoltageTT = unstack(voltageInterpolatedTT,"Value","Tag",... "AggregationFunction",@(x)x(~isempty(x)),"VariableNamingRule","preserve")
uVoltageTT=281×3 timetable
Time OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2 OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d
_________________________ _______________________________________________________________ _______________________________________________________________ _______________________________________________________________
04-November-2021 20:25:12 NaN NaN NaN
05-November-2021 00:25:12 3.2908 3.3053 3.32
05-November-2021 04:25:12 3.2805 3.2808 3.32
05-November-2021 08:25:12 3.3102 3.3194 3.2912
05-November-2021 12:25:12 3.3047 3.3092 3.3196
05-November-2021 16:25:12 3.2832 3.3094 3.2992
05-November-2021 20:25:12 3.2806 3.3188 3.3096
06-November-2021 00:25:12 3.3188 3.32 3.3184
06-November-2021 04:25:12 3.2808 3.2812 3.3088
06-November-2021 08:25:12 3.2896 3.2906 3.3198
06-November-2021 12:25:12 3.3088 3.3192 3.32
06-November-2021 16:25:12 3.3184 3.2806 3.3184
06-November-2021 20:25:12 3.3 3.3188 3.3004
07-November-2021 00:25:12 3.3008 3.2992 3.3097
07-November-2021 04:25:12 3.3188 3.2908 3.2816
07-November-2021 08:25:12 3.3104 3.3196 3.2992
⋮
Fill Missing Values
Notice the timetable in the previous step contains some NaN values. This happens when datapoints of a timetable are not all sampled at the same interval. Use the fillmissing
function to correct this by linear interpolation.
[cVoltageTT,~] = fillmissing(uVoltageTT,"linear")
cVoltageTT=281×3 timetable
Time OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2 OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d
_________________________ _______________________________________________________________ _______________________________________________________________ _______________________________________________________________
04-November-2021 20:25:12 3.3011 3.3298 3.32
05-November-2021 00:25:12 3.2908 3.3053 3.32
05-November-2021 04:25:12 3.2805 3.2808 3.32
05-November-2021 08:25:12 3.3102 3.3194 3.2912
05-November-2021 12:25:12 3.3047 3.3092 3.3196
05-November-2021 16:25:12 3.2832 3.3094 3.2992
05-November-2021 20:25:12 3.2806 3.3188 3.3096
06-November-2021 00:25:12 3.3188 3.32 3.3184
06-November-2021 04:25:12 3.2808 3.2812 3.3088
06-November-2021 08:25:12 3.2896 3.2906 3.3198
06-November-2021 12:25:12 3.3088 3.3192 3.32
06-November-2021 16:25:12 3.3184 3.2806 3.3184
06-November-2021 20:25:12 3.3 3.3188 3.3004
07-November-2021 00:25:12 3.3008 3.2992 3.3097
07-November-2021 04:25:12 3.3188 3.2908 3.2816
07-November-2021 08:25:12 3.3104 3.3196 3.2992
⋮
View Each Voltage in a Separate Timetable
View voltage AB in its own timetable.
lineVoltageAB = cVoltageTT.Properties.VariableNames{1}; vabTT = timetable(cVoltageTT.(lineVoltageAB)(:), 'RowTimes', cVoltageTT.Time(:), 'VariableNames', {char(lineVoltageAB)})
vabTT=281×1 timetable
Time OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a
_________________________ _______________________________________________________________
04-November-2021 20:25:12 3.3011
05-November-2021 00:25:12 3.2908
05-November-2021 04:25:12 3.2805
05-November-2021 08:25:12 3.3102
05-November-2021 12:25:12 3.3047
05-November-2021 16:25:12 3.2832
05-November-2021 20:25:12 3.2806
06-November-2021 00:25:12 3.3188
06-November-2021 04:25:12 3.2808
06-November-2021 08:25:12 3.2896
06-November-2021 12:25:12 3.3088
06-November-2021 16:25:12 3.3184
06-November-2021 20:25:12 3.3
07-November-2021 00:25:12 3.3008
07-November-2021 04:25:12 3.3188
07-November-2021 08:25:12 3.3104
⋮
View voltage AC in its own timetable.
lineVoltageAC = cVoltageTT.Properties.VariableNames{2}; vacTT = timetable(cVoltageTT.(lineVoltageAC)(:), 'RowTimes', cVoltageTT.Time(:), 'VariableNames', {char(lineVoltageAC)})
vacTT=281×1 timetable
Time OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2
_________________________ _______________________________________________________________
04-November-2021 20:25:12 3.3298
05-November-2021 00:25:12 3.3053
05-November-2021 04:25:12 3.2808
05-November-2021 08:25:12 3.3194
05-November-2021 12:25:12 3.3092
05-November-2021 16:25:12 3.3094
05-November-2021 20:25:12 3.3188
06-November-2021 00:25:12 3.32
06-November-2021 04:25:12 3.2812
06-November-2021 08:25:12 3.2906
06-November-2021 12:25:12 3.3192
06-November-2021 16:25:12 3.2806
06-November-2021 20:25:12 3.3188
07-November-2021 00:25:12 3.2992
07-November-2021 04:25:12 3.2908
07-November-2021 08:25:12 3.3196
⋮
View voltage BC in its own timetable.
lineVoltageBC = cVoltageTT.Properties.VariableNames{3}; vbcTT = timetable(cVoltageTT.(lineVoltageBC)(:), 'RowTimes', cVoltageTT.Time(:), 'VariableNames', {char(lineVoltageBC)})
vbcTT=281×1 timetable
Time OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d
_________________________ _______________________________________________________________
04-November-2021 20:25:12 3.32
05-November-2021 00:25:12 3.32
05-November-2021 04:25:12 3.32
05-November-2021 08:25:12 3.2912
05-November-2021 12:25:12 3.3196
05-November-2021 16:25:12 3.2992
05-November-2021 20:25:12 3.3096
06-November-2021 00:25:12 3.3184
06-November-2021 04:25:12 3.3088
06-November-2021 08:25:12 3.3198
06-November-2021 12:25:12 3.32
06-November-2021 16:25:12 3.3184
06-November-2021 20:25:12 3.3004
07-November-2021 00:25:12 3.3097
07-November-2021 04:25:12 3.2816
07-November-2021 08:25:12 3.2992
⋮
Visualize Tag Values of Voltages
To visualize values of interest, you can plot voltages from the timetables over time for further analysis.
subplot(3, 1, 1) plot(vabTT.Time, vabTT.("OSIDemo_GU1 Generator.Line Voltage AB.373eb947-c651-5aef-1948-a"), "r") title("{\itVoltage AB}", "FontWeight", "bold") xlabel("Timestamp") ylabel("Voltage") subplot(3, 1, 2) plot(vacTT.Time, vacTT.("OSIDemo_GU1 Generator.Line Voltage AC.a809d1f1-c08f-54f9-0915-2"), "g") title("{\itVoltage AC}", "FontWeight", "bold") xlabel("Timestamp") ylabel("Voltage") subplot(3, 1, 3) plot(vbcTT.Time, vbcTT.("OSIDemo_GU1 Generator.Line Voltage BC.90cc345e-520f-5284-187b-d"), "b") title("{\itVoltage BC}", "FontWeight", "bold") xlabel("Timestamp") ylabel("Voltage")
Cleanup
When you are finished working with the PI Data Archive, disconnect and remove the client by clearing its variable from the workspace.
clear client;