Jump to content

All Activity

This stream auto-updates

  1. Yesterday
  2. Hello, I have multiple bearings within multiple assets at a power plant. Some of the temperature signals drop to 0 or -250 at random times. First step would be clean all signals and use only values greater than 1 for all bearings. Some plants have 100+ assets so I'd like to make this a quick process. Secondly, I'd like to create an average trend line of all signals. Finally, when a any bearing temperature exceeds average by 20% continuously for 10 minutes - I'd like to capture those events and create a table each week showing the assets which are running at elevated temperatures each day. How do I go about this exercise?
  3. Last week
  4. Thanks, Thorsten. I was looking for something like the below search and look at the signal trend.
  5. Hi Sivaji, actually you can search by ID using either the API/SDK or writing some code in Data Lab. In terms of API/SDK you should try the /items/{id} endpoint: In case an item exists you will get HTTP 200 as status code and details about the item in the response body. If the item does not exist you receive an HTTP 404 status code. In Data Lab you can use spy.search for this. In case of non-existing item spy.search throws an error, therefore I am iterating over the IDs: item_ids = ["FCC9F932-B328-4A7E-9300-A17331519C93", "BF769E50-B93A-4C1A-81FD-326F488CD1E1", "64832183-D97F-4E5C-81A1-C466C494DC3A", "64832183-D97F-4E5C-81A1-C466C494DC6A", "FCC9F932-B328-4A7E-9300-A17331519C91"] item_infos = [] for item_id in item_ids: try: data = spy.search({"ID": item_id}) item_infos.append("Item with ID " + item_id + " exists") except: item_infos.append("Item with ID " + item_id + " does not exist") print (item_infos) Output looks like this: ['Item with ID FCC9F932-B328-4A7E-9300-A17331519C93 exists', 'Item with ID BF769E50-B93A-4C1A-81FD-326F488CD1E1 exists', 'Item with ID 64832183-D97F-4E5C-81A1-C466C494DC3A does not exist', 'Item with ID 64832183-D97F-4E5C-81A1-C466C494DC6A exists', 'Item with ID FCC9F932-B328-4A7E-9300-A17331519C91 does not exist'] Be aware that both methods return all types of items. In case you want to search only for signals or conditions you have to make some adjustments like evaluating the returned data. Hope this helps. Regards, Thorsten
  6. I was wondering if we can do a Data search a signal (formula/condition) by its ID? Use-case: for validating IDs used in the DataLab project created by others.
  7. The SPy library supports the creation of asset trees through the spy.assets models. These asset trees can include various types of items such as signals and conditions, calculations like scorecard metrics, and can be used to create numerous Workbench Analysis Worksheets and Organizer Topic Documents. One question that commonly comes up when making these trees is how to reference attributes that are located in other parts of the tree. Roll-Ups The first example of referencing other items in the tree is through roll-ups. These type of calculations "roll-up" attributes from levels below where the roll-up calculation is being performed, whether the level is directly beneath or multiple levels below. These attributes are then combined using logic you provide. For signals and scalars, the options are Average, Maximum, Minimum, Range, Sum and Multiply. For conditions, the options are Union, Intersect, Counts, Count Overlaps, and Combine With. Below are examples where .Cities() are a component beneath the current class. All attributes and assets beneath the Cities component will be searched through and included in the roll-up based on the criteria given in the pick function. Here, we're filtering based on Name but any property such as Type can be supplied. Note Seeq Workbench's search mechanism is used here, so wildcards and regular expressions can be included. Lastly, we specify the kind of roll-up we'd like to perform. @Asset.Attribute() def Regional_Compressor_Running_Poorly(self,metadata): return self.Cities().pick({'Name':'Compressor Running Poorly'}).roll_up('union') @Asset.Attribute() def Regional_Total_Energy_Consumption(self,metadata): return self.Cities().pick({'Name':'Total Daily Energy Consumption'}).roll_up('sum') Child Attributes The second example looks at how to reference child attributes without rolling them up. Maybe there's a particular attribute that needs to be included in a calculation used at a higher level in the asset tree. For this scenario, the pick function can be used once again. Rather than do a roll-up, we'll just index the particular item we want. Most of the time the goal is to reference a specific item using this method so the criteria passed into the pick function should be specific enough to find one item so the index will always be 0. One property that may be of interest for this is Template, where you can specify the particular class used that will contain the item wanted. @Asset.Attribute() def Child_Power_Low(self, metadata): child_power = self.Cities().pick({"Name": "Compressor Power", "Asset": "/Area (A|C|D)/"})[0] return { 'Name': "Child Power Low", 'Type': "Condition", "Formula": "$child_power < 5", "Formula Parameters" : {"child_power":child_power} } Parent Attributes The next example looks at how we can reference parent attributes in calculations that are beneath it. Rather than reference a particular component, we'll use the parent. From there we'll include the attribute we'd want to reference from our parent asset. If looking to reference attributes at higher levels of the tree, chain multiple ".parent". For example, "self.parent.parent" will look two levels above the current level. @Asset.Attribute() def Parent_Temp_Multiplied(self, metadata): parent_temp = self.parent.Temperature() return { 'Name': "Parent Temp Multiplied", 'Type': "Signal", "Formula": "$parent_temp * 10", "Formula Parameters" : {"parent_temp":parent_temp} } Advanced Selection In this example, we'll look at how can we combine the previously mentioned options to find items located in other parts of the tree. Here, we're looking to reference items located at the same level of the tree but in another class so it's not located beneath the same asset. We have two separate assets beneath the regions, Temperature Items and Power Items. The Temperature Item class has a calculation called Max Temperature 1 When Compressor Is On which references an attribute beneath its corresponding Power Item class. To fetch this attribute, we go up a level to the parent, navigate down to the Power_Items and then pick that attribute. class Region(Asset): @Asset.Component() def Temperature_Items(self,metadata): return self.build_components(template=Temperature_Item, metadata=metadata, column_name='Region Temp') @Asset.Component() def Power_Items(self,metadata): return self.build_components(template=Power_Item, metadata=metadata, column_name='Region Power') class Power_Item(Asset): @Asset.Attribute() def Power_1(self,metadata): return { 'Name':'Power 1', 'Type':'Signal', 'Formula':'$power', 'Formula Parameters': {'$power':metadata[metadata['Name'].str.contains('Power')].iloc[0]['ID']} } class Temperature_Item(Asset): @Asset.Attribute() def Temperature_1(self,metadata): return { 'Name':'Temperature 1', 'Type':'Signal', 'Formula':'$temp', 'Formula Parameters': {'$temp':metadata[metadata['Name'].str.contains('Temperature')].iloc[0]['ID']} } @Asset.Attribute() def Temp_When_Comp_On(self, metadata): power_adjacent_class = self.parent.Power_Items().pick({'Name':"Power 1"})[0] return { 'Name': "Max Temperature 1 When Compressor Is On", 'Type': 'Signal', 'Formula': '$temp1.aggregate(maxValue(), ($power1<5).removeLongerThan(7d), durationKey())', 'Formula Parameters':{ 'temp1':self.Temperature_1(), 'power1': power_adjacent_class } } Item Group To help with even more complex attribute selections, we introduced the ability to include ItemGroup rather than using the pick and parent functions. ItemGroup provides an alternate way of findings items located in other parts of the tree using established Python logic. Below are two examples using ItemGroup to perform selections that would be very complex to do with the pick function Advanced Roll-up Roll-ups using the pick reference one component beneath your class but what if there was a need for a roll-up across multiple components. ItemGroup can be used for a simple roll-up as well as this complex example. Rather than specifying a particular component and picking in it, we can use ItemGroup to iterate over every asset. Here, we retrieve every High Power attribute beneath the assets if the asset is a child of the current asset. @Asset.Attribute() def Compressor_High_Power(self, metadata): # Helpful functions: # asset.is_child_of(self) - Is the asset one of my direct children? # asset.is_parent_of(self) - Is the asset my direct parent? # asset.is_descendant_of(self) - Is the asset below me in the tree? # asset.is_ancestor_of(self) - Is the asset above me? (i.e. parent/grandparent/great-grandparent/etc) return ItemGroup([ asset.High_Power() for asset in self.all_assets() if asset.is_child_of(self) ]).roll_up('union') Referencing Items In A Different Section In this example, we're looking to reference attributes in other similar assets, but these assets are located in different sections of the tree. We can use the previous option in the Advanced Selection section but what if these compressors weren't necessarily at the same level of the tree or were beneath different components. This would mean they have different pathways and the method previously stated wouldn't work. Using ItemGroup we can iterate through all assets and find any that are also based on the Compressor class. Here we also exclude the current asset and then perform a roll-up based on all of the other High Powers. @Asset.Attribute() def Other_Compressors_Are_High_Power(self, metadata): return ItemGroup([ asset.High_Power() for asset in self.all_assets() if isinstance(asset, Compressor) and self != asset ]).roll_up('union')
  8. Yeah, I first tried the Prediction route, and didn't get anywhere. I'll have to revisit. But I'm still confused as to why xyTable can't return a table.
  9. You should be able to just use the built-in prediction tool under Model & Predict -> Prediction. If there is a delay in the off-line samples and you need to move the signal in time by a constant amount, you can use the $signal.move() function in a formula to create a new time-adjusted signal for use in the Prediction tool. The Prediction Model section of the Prediction tool will show you information regarding the regression such as rSquared, p-values, etc. The Prediction tool should take care of creating the value pairs from the input signals, perhaps a Seeq Engineer can give more specific info on this if needed.
  10. I have an in-line instrument value from the historian, at roughly four per minute. Simultaneously, off-line samples are measured using a different technology, so the scaling of the two measurements is different. These samples are measured by hand, minutes apart. The off-line samples are imported to the Workbench in a csv file, so the time stamps don't necessarily line up exactly with any of the in-line values from the historian. My goal is to determine the correlation between the two measurements, with the off-line sample measurement being the gold standard, and attempting to "prove out" the in-line measurement.
  11. Earlier
  12. So what is your objective, what signal/scalar/condition do you want to the formula to output? xyTable will produce a table of value pairs for your two signals, what are the next steps required to produce the signal/scalar/condition?
  13. I already have a visual of the data in Workbench. What I want to do with the table is to get the data in a format that will be easier to do formulas against.
  14. That's exactly what the formula does, it returns a table, but this is different from the Table View in Seeq Workbench. It's purpose is not to create a graphical table in Workbench. If you are trying to create a graphic table of samples, I'm not sure if this is your objective, you could use Table View in Condition Mode to do this. One way, would be to create a Score Card Metric for each signal and specify the rolling window for which you'd like a value in your table. Here's an example.
  15. I am trying to accomplish what the documentation says this function does: xyTable() Create a table of aligned samples from two signals." And this is the example formula given: xyTable($capsule, $xSignal, $ySignal, 100)
  16. What are trying to accomplish? This formula returns a table, but Seeq expects a condition, formula, or scalar so I imagine you are seeing the bad response error because of this. xyTable(capsule('2021'), $a, $b, 100) is the correct syntax, but you can't return a table.
  17. Thank you for your response. Can you show the syntax in the xyTable formula? This does not work: xyTable(capsule('2021'), $qs5, $a, 100) And this does not work: xyTable($capsule('2021'), $qs5, $a, 100)
  18. See capsule() in the formula documentation.
  19. xyTable($capsule, $xSignal, $ySignal, 100) What is the syntax to enter $capsule in this formula? Thanks.
  20. Technology investments, regardless of industry, come with risk, and startup investments are often met with even more hesitation. While startups promise to bring greater innovation, major organizations fear these young, unestablished companies could bring even greater risk to mission-critical projects. View the full article
  21. Can I connect my rotating equipment vibration sensors directly to SeeQ for spectrum analysis. Data sampling rate is in the range of 5kHz.
  22. You may have noticed that pushed data does not have a red trash icon at the bottom of its Item Properties. There's a simple way to move this (and any other) data to the trash through Data Lab. Read below. Pushed Data Normal Calculated Seeq Signal Moving data to trash through SDL Step 1: Identify data of interest and store in a dataframe For this example, I want to move all of the items on this worksheet to trash. Thus, I can use spy.search to store as a dataframe. remove_Data = spy.search('worksheet URL') Step 2: Create an 'Archived' column in the dataframe and set to 'true' remove_Data['Archived'] = 'true' Step 3: Push this dataframe back into Seeq as metadata spy.push(metadata = remove_Data) The associated data should now be in the trash and unable to be searchable in the Data pane.
  23. Hi Joe, Thank you for the help. I used your method and it worked for the "trend view", however, scientific notation still showed up for the "treemap" view. Is there any way to change this?
  24. That worked. Not sure why I could not perform the same thing within one single formula. Thanks Thorsten!
  25. Hi Rohan, You'll just want to edit the Number Formatting (https://seeq.atlassian.net/wiki/spaces/KB/pages/570490943/Number+Formatting) on the resulting formula. The precision is kept, but the formatting is just in scientific notation.
  26. Hi, I was using the toNumber() function to convert a string to a useable number, however, ran into a problem where the resulting number was converted to scientific notation and all of the non leading digits were lost. Is there any way to keep the precision of the number? Below is the formula I used $string = "123456789123456" $string.toNumber() Result was 1*10^14
  27. Hi Yanmin, Unfortunately, Seeq doesn't currently offer any contour map features; however, I've listed some options below to address your use case. In addition, while not directly applicable to what you're trying to achieve as contour across 9 separate tags, I recommend looking into the Density Plot feature available in Seeq as you may find some interest in this feature. Option 1: Create a simple scorecard for each Well and assemble them in an organizer in a neater format. It seems that you're using a 3x3 organizer table--one cell for each Well. You could use only one table cell to get them to better fit, emulating a single table. Something like below. I only used "Well 02" to demonstrate the layout, but the idea is your "mapping" will be on the left to understand what you're looking at on the right. To go about this, create a worksheet for each Well. Create a metric as you have (with thresholds specified) and goto Table view. Under Headers, select None. Under Columns: If you are creating the left table, only have Name checked. If you are creating the right table, only have Metric Value checked. Insert each into a single cell of a table in Organizer--I used a 1x2 table. For assembling adjacent columns, you'll want to make sure you insert each worksheet directly next to the other (no spaces between). For going to the next row, you'll want to make sure to SHIFT+ENTER, instead of a simple ENTER. Something like this should be the result. To remove the space between, simply click each individual cell (metric) and click Toggle Margin. After completing this for each metric, the table should resemble the first one I posted. You can resize the 1x2 Organizer table by clicking Table properties. For this example, I specified a width of 450 to narrow up the two columns. Option 2: Create a Treemap. This method will require that the Wells be a part of an asset group. If not already configured, this can be done within Seeq as of R52. This method may or may not give you the information you're looking for. Before considering this option, please be sure to read about Treemaps more on our Knowledge Base. Depending on the Priority colors and conditions you specify, your Treemap would look something like this. Note there is no way to change or specify the orientation within the normal user interface in Seeq (i.e. you can't easily specify a 3x3 layout). I hope this helps!
  1. Load more activity
  • Create New...