Super Seeqer

104

172

Super Seeqer

81

72

Seeq Team

77

128

46

95

## Popular Content

Showing content with the highest reputation since 08/08/2018 in all areas

1. ## Iterative Calculation in Seeq Data Lab

A few weeks ago in Office Hours, a Seeq user asked how to perform iterative calculation in which the next value of the calculation relies on its previous values. This functionality is currently logged as a feature request. In the meantime, users can utilize Seeq Data Lab and push the calculated result from Seeq Data Lab to Seeq Workbench. Let's check out the example below: There are a total of 4 signals, Signal G, Signal H, Signal J, and Signal Y added to Seeq workbench. The aim is to calculate the value of Signal Y, under the selected period. Step 1: Set the start date and end date of the calculation. #Set the start date and end date of calculation startdate = '2023-01-01' enddate = '2023-01-09' Step 2: Set the workbook URL and workbook ID. #Set the workbook URL and workbook ID workbook_url = 'workbook_url' workbook_id = 'workbook_id' Step 3: Retrieve all raw data points for the time interval specified in Step 1 using spy.pull(). #Retrieve all raw data points for the time internal specified in Step 1: data = spy.pull(workbook_url, start = startdate, end = enddate, grid = None) data Step 4: Calculate the value of Signal Y, (Yi = Gi * Y(i-1) + Hi * Ji) #Calculate the value of Signal Y (Yi = Gi * Y(i-1) + Hi * Ji) for n in range(len(data)-1): data['Signal Y'][n+1] = data['Signal G'][n+1] * data['Signal Y'][n] + data['Signal H'][n+1] * data['Signal J'][n+1] data Step 5: Push the calculated value of Signal Y to the source workbook using spy.push(). #Push the calculated result of Signal Y to the source workbook spy.push(data = data[['Signal Y']], workbook = workbook_id)
7 points
2. ## Does Seeq have dark mode?

While Seeq does not officially have dark mode, google chrome has a plug in that may be a feasible workaround. Here is what organizer topic looks like And here is workbench analysis screenshot Interested in getting one for your Seeq? Check out the dark reader plugin. DISCLAIMER: PLEASE CHECK WITH YOUR LOCAL IT BEFORE INSTALLING ANYTHING FROM THE INTERNET Here goes the link: https://chrome.google.com/webstore/detail/dark-reader/eimadpbcbfnmbkopoojfekhnkhdbieeh Cheers, Sanman
7 points

6 points

5 points

5 points
6. ## Push Scorecard from Seeq Data Lab

The SPy Documentation for spy.assets includes an example of specifying metrics as attributes in asset classes. It is also possible to push scorecard metrics using the spy.push functionality by defining the appropriate metadata. An example of this process is given in the code snippets below: #import relevant libraries import pandas as pd from seeq import spy Log in to the SPY module if running locally using spy.login, or skip this step if running Seeq Data Lab. #Search for data that will be used to create the scorecard. This example will search the Example asset tree to find tags in Area A. search_result = spy.search({'Path': 'Example >> Cooling Tower 1 >> Area A'}) The next code segment creates and pushes a signal that will be used as a threshold limit in the scorecard metric. This can be skipped if threshold signals will not be used in the final metric. #Define data frame for low limit threshold signal. my_lo_signal = { 'Type': 'Signal', 'Name': 'Lo Signal', 'Formula': '\$signal * 50', 'Formula Parameters': {'\$signal': search_result[search_result['Name'] == 'Optimizer']['ID'].iloc[0]} } #Push data frame for low limit threshold signal. lo_push_result = spy.push(metadata=pd.DataFrame([my_lo_signal]), workbook='Example Scorecard') Finally, create the and push the scorecard metric. This example metric measures the average temperature and apply a static high limit threshold of 90 and a moving low limit threshold using the signal defined above. #Define data frame for scorecard metric. my_metric_input = { 'Type': 'Metric', 'Name': 'My Metric', 'Measured Item': {'ID': search_result[search_result['Name'] == 'Temperature']['ID'].iloc[0]}, 'Statistic': 'Average', 'Thresholds': { 'Lo': {'ID': lo_push_result['ID'].iloc[0]}, 'Hi': 90 } } #Push data frame for scorecard metric. spy.push(metadata = pd.DataFrame([my_metric_input]), workbook='Example Scorecard') The final result can be seen in the created workbook.
5 points
7. ## Helper script to bulk transfer signal names from excel to Seeq workbench

A small team of us (with help from Seeq team members) built a short script to extract signal names from our legacy excel workbooks so that we could push them to Seeq workbench. Perhaps, like us, you are involved in migrating workbooks for monitoring/ reporting over to Seeq and could do with a boost to get started so you can get to real work of setting up the Seeq workbench. The attached script will extract the signal names (assuming you can craft your own regex search filter) from each excel worksheet and then push them to workbench with labeling for organization. Hopefully its a help to some 🙂 signal_transfer_excel2seeq_rev1.ipynb
5 points
8. ## Get previous value or interpolated value from past

Hi Mattheus, You can do this by using the move (v49+) or delay (<=v48) function. For example, your equation would be: (\$signal.move(5s)+\$signal.move(10s)+\$signal.move(60s))/3
5 points

5 points
10. ## Extracting A Substring From a Capsule Property

Contextual data is often brought into Seeq to add more information to time series data. This data tends to be brought in as a condition, with the capsule properties of this condition containing different pieces of information. In some cases, a particular capsule property may not contain just one piece of information; it may contain different pieces that are separated based on some logic or code. Rather than having users visually parse the code to extract the segments of interest, Seeq can be used to extract the substring continuously. The code below extracts a substring based on its location in the property. This code is based on incrementing from left to right, starting at the beginning of the string. Changing the inputs will extract a substring from different positions in the property selected. //Inputs Section (Start and end assume reading left to right) \$condition = \$hex_maint //Recommend to filter condition to only include correct property values \$property_to_capture = 'Reason Code' \$start_position = 1 //Incrementing starts from 1 \$number_of_characters = 2 //Including the start //Code Section \$property_signal = \$condition.toSignal(\$property_to_capture).toStep(2wk) //Change duration for interpolation \$start_position_regex = (\$start_position - 1).toString() //Regular exression indexes from 0 \$number_of_characters_regex = (\$number_of_characters - 1).toString() \$property_signal.replace('/.{'+\$start_position_regex+'}(?<Hold>.{'+\$number_of_characters_regex+'}.).*/','\${Hold}') This alternative version is based on incrementing right to left, starting at the end of the string. //Inputs Section (Start and end assume reading left to right) \$condition = \$hex_maint //Recommend to filter condition to only include correct property values \$property_to_capture = 'Reason Code' \$end_position = 1 //Relative to end, incremented from 1 \$number_of_characters = 4 //Including the end character //Code Section \$property_signal = \$condition.toSignal(\$property_to_capture).toStep(2wk) //Change duration for interpolation \$end_position_regex = (\$end_position).toString() \$number_of_characters_regex = (\$number_of_characters - 1).toString() \$property_signal.replace('/.*(?<Hold>.{'+\$number_of_characters_regex+'}.{'+\$end_position_regex+'})\$/','\${Hold}') Note the output of these formulas is a string. In the case that a numeric value is wanted, append .toNumber() after '\${Hold}') Below is an example of the results. With this substring parsed, all of Seeq's analytical tools can be further leveraged. Some examples are developing histograms based on the values of the substring and making conditions to highlight whenever a particular value in the substring is occurring.
5 points
11. ## Viewing Multiple Signal Profiles on a Non-Time Axis

To better understand their process, users often want to compare time-series signals in a dimension other than time. For example, seeing how the temperature within a reactor changes as a function of distance. Seeq is built to compare data against time but this method highlights how we can use time to mimic an alternate dimension. Step 1: Sample Alignment In order to accurately mimic the alternate dimension, the samples to be included in each profile must occur at the same time. This can be achieved through a couple methods in Seeq if the samples don't already align. Option 1: Re-sampling Re-sampling selects points along a signal at select intervals. You can also re-sample based on another signal's keys. Since its possible for there not to be a sample at that select interval, the interpolated value is chosen. An example Formula demonstrating how to use the function is shown below. //Function to resample a signal \$signal.resample(5sec) Option 2: Average Aggregation Aggregating allows users to determine the average of a signal over a given period of time and then place this average at a specific point within that period. Signal From condition can be used to find the average over a period and place this average at a specific timestamp within the period. In the example below, the sample is placed at the start but alignment will occur if the samples are placed at the middle or end as well. Step 2: Delay Samples In Formula, apply a delay to the samples of the signal that represents their value in the alternative dimension. For example, if a signal occurs at 6 feet from the start of a reactor, delay it by 6. If there is not a signal with a 0 value in the alternate dimension, the final graph will be offset by the smallest value in the alternate dimension. To fix this, in Formula create a placeholder signal such as 0 and ensure its samples align with the other samples using the code listed below. This placeholder would serve as a signal delayed by 0, meaning it would have a value of 0 in the alternate dimension. //Substitute Period_of_Time_for_Alignment with the period used above for aligning your samples 0.toSignal(Period_of_Time_for_Alignment) Note: Choosing the unit of the delay depends upon the new sampling frequency of your aligned signals as well as the largest value you will have in the alternative dimension. For example, if your samples occur every 5 minutes, you should choose a unit where your maximum delay is not greater than 5 minutes. Please refer to the table below for selecting units Largest Value in Alternate Dimension Highest Possible Delay Unit 23 Hour, Hour (24 Hour Clock) 59 Minute 99 Centisecond 999 Millisecond Step 3: Develop Sample Profiles Use the Formula listed below to create a new signal that joins the samples from your separate signals into a new signal. Replace "Max_Interpolation" with a number large enough to connect the samples within a profile, but small enough to not connect the separate profiles. For example, if the signals were re-sampled every 5 minutes but the largest delay applied was 60 seconds, any value below 4 minutes would work for the Max_Interpolation. This is meant to ensure the last sample within a profile does not interpolate to the first sample of the next profile. //Make signals into discrete to only get raw samples, and then use combineWith and toLinear to combine the signals while maintaining their uniqueness combineWith(\$signal1.toDiscrete() , \$signal2.toDiscrete() , \$signal3.toDiscrete()).toLinear(Max_Interpolation) Step 4: Condition Highlighting Profiles Create a condition in Formula for each instance of this new signal using the formula below. The isValid() function was introduced in Seeq version 44. For versions 41 to 43, you can use .valueSearch(isValid()). Versions prior to 41 can use .validityCapsules() //Develop capsule highlighting the profile to leverage other views based on capsules to compare profiles \$sample_profiles.isValid() Step 5: Comparing Profiles Now with a condition highlighting each profile, Seeq views built around conditions can be used. Chain View can be used to compare the profiles side by side while Capsule View can overlay these profiles. Since we delayed our samples before, we are able to look at their relative times and use that to represent the alternate dimension. Further Applications With these profiles now available in Seeq, all of the tools available in Seeq can be used to gain more insight from these examples. Below are a few examples. Comparing profiles against a golden profile Determine at what value in the alternate dimension does each profile reach a threshold Developing a soft sensor based on another sensor and a calibration curve profile Example Use Cases Assess rotating equipment performance based on OEM curve regressions that vary based on equipment speed due to a VFD (alternate dimension = speed) Monitor distillation cut points based on distillation lab data (alternate dimension = lab standard, boil % in this case) Observe temperature profile along a reactor or well (alternate dimension = distance, length and depth in these cases)
5 points
12. ## Error getting data: condition must have a maximum duration.

For those like me who keep getting this error: Error getting data: condition must have a maximum duration. Consider using removeLongerThan() to apply a maximum duration. Click the wrench icon to add a Maximum Capsule duration. The resolution seemed to make sense to apply removeLongerThan() or setMaximumDuration() to the signal, but the correct answer is to set it to the capsule. For example, this is the incorrect formula I attempted. \$series.aggregate(maxValue(), \$capsules, endKey(), 0s) Here is the resolution: \$series.aggregate(maxValue(), \$capsules.setMaximumDuration(40h), endKey(), 0s) or \$series.aggregate(maxValue(), \$capsules.removeLongerThan(40h), endKey(), 0s) Hope this helps others who didn't have luck searching this specific alarm previously.
5 points
13. ## Data Cleansing Tips: Using the .remove() and .within() Formula Functions

A typical data cleansing workflow is to exclude equipment downtime data from calculations. This is easily done using the .remove() and .within() functions in Seeq formula. These functions remove or retain data when capsules are present in the condition that the user supplies as a parameter to the function. There is a distinct difference in the behavior of the .remove() and .within() functions that users should know about, so that they can use the best approach for their use case. .remove() removes the data during the capsules in the input parameter condition. For step or linearly interpolated signals, interpolation will occur across those data gaps that are of shorter duration than the signal's maximum interpolation. (See Interpolation for more details concerning maximum interpolation.) .within() produces data gaps between the input parameter capsules. No interpolation will occur across data gaps (no matter what the maximum interpolation value is). Let's show this behavior with an example (see the first screenshot below, Data Cleansed Signal Trends), where an Equipment Down condition is identified with a simple Value Search for when Equipment Feedrate is < 500 lb/min. We then generate cleansed Feedrate signals which will only have data when the equipment is running. We do this 2 ways to show the different behaviors of the .remove() and .within() functions. \$Feedrate.remove(\$EquipmentDown) interpolates across the downtime gaps because the gap durations are all less than the 40 hour max interpolation setting. \$Feedrate.within(\$EquipmentDown.inverse()) does NOT interpolate across the downtime gaps. In the majority of cases, this result is more in line with what the user expects. As shown below, there is a noticeable visual difference in the trend results. Gaps are present in the green signal produced using the .within() function, wherever there is an Equipment Down capsule. A more significant difference is that depending on the nature of the data, the statistical calculation results for time weighted values like averages and standard deviations, can be very different. This is shown in the simple table (Signal Averages over the 4 Hour Time Period, second screenshot below). The effect of time weighting the very low, interpolated values across the Equipment Down capsules when averaging the Feedrate.remove(\$EquipmentDown) signal, gives a much lower average value compared to that for \$Feedrate.within(\$EquipmentDown.inverse()) (1445 versus 1907). Data Cleansed Signal Trends Signal Averages over the 4 Hour Time Period Content Verified DEC2023
4 points

4 points

4 points

4 points
17. ## Signal forecasting trained on only the current cycle

When creating signal forecasts, especially for cyclic signals that degrade, we often use forecastLinear() in formula to easily forecast a signal out into the future to determine when a threshold is met. The methodology is often the same regardless of if we are looking at a filter, a heat exchanger, or any other equipment that fouls overtime or any equipment that needs to go through some periodic maintenance when a KPI threshold is met. A question that comes up occasionally from users is how to create a signal forecast that only uses data from the current operation cycle for signal forecasting. The forecastlinear() operator only takes into account a historical training period and does not determine if that data is coming from the current cycle or not (which results in unexpected results). Before entering the formula, you will need to define: a condition that identifies the current cycle, here i have called it "\$runningCycle" a Signal to do a linear forecast on, i have called it "\$signal" To forecast out into the future based on only the most recent cycle, the following code snippet can be used in formula: \$training = \$runningCycle.setmaximumduration(10d).toGroup(capsule(now()-2h, now())) \$forecast=\$Signal.predict(\$training, timesince(toTime('2000-01-01T00:00Z'))) \$signal.forecastSplice(\$forecast, 1d) In this code snippet, there are a few parameters that you might want to change: .setMaximumDuration(10d): results in a longest cycle duration of 10 days, this should be changed to be longer than the longest cycle you would expect to see capsule(now-2h, now()): this creates a period during which seeq will look for the most recent cycle. In this case it is any time in the last 2 hours. If you have very frequent data (data comes in every few seconds to minutes) then 2 hours or less will work. If you have infrequent data (data that comes in once a day or less) then extend this so that it covers the last 3-4 data points. \$signal.forecastSplice(\$forecast, 1d): When using forecastLinear(), there is an option to force the prediction through the last sample point. This date parameter (1 day in this case) does something similar- it blends the last historical data point with the forecast over the given time range. In other words, if the last data point was a value of 5, but my first forecasted datapoint had a value of 10, this parameter is the time frame over which to smooth from the historical data point to the forecast. Here is a screenshot of my formula : and the formula in action:
4 points

4 points

4 points
20. ## Add Color Thresholds to the Highest and 2nd Highest Values on a Scorecard

It is common in manufacturing processing plants such as oil and gas refineries, to monitor the temperature trend in furnaces. Example in the refineries, the furnaces tube metal temperature (TMT) monitoring severity increases for dirty services such as crude distillation and coker units. Operation team uses this information to decide either to go for rate cut or feed rate skewing before the TMT reaching mechanical limits to prolong the run length. Upon reaching the limit, the furnace will be taken out-of-service by means of spalling or pigging, and consequently impacts the production rate. Use case: The objective is to highlight the highest and the second highest temperature out of several temperatures in a matrix. Seeq enables users to build a matrix table (or Scorecard prior to R51) to highlight the temperature priority sequence by using a combination of functions and tools including max(), splice(), composite condition and scorecard metrics. Step 1: Start by loading all of the signals we want to include in the matrix into the display. Step 2: Use max() to look for the highest value signal at any time in the formula tool. Type in formula below into formula editor. \$t.max(\$t2).max(\$t3).max(\$t4).max(\$t5).max(\$t6).max(\$t7).max(\$t8) Step 3: Create the second highest signal using splice() and composite condition. To capture the second highest signal, we need first to exclude a signal with the highest temperature at any time and then identify the highest value out of the remaining seven signals. To achieve that, use the highest temperature signal we created in step 2, we then create a condition when a signal reads the highest value, for each eight signals. //Which is the max \$if_t1_is_the_max = \$t1 == \$max \$if_t2_is_the_max = \$t2 == \$max \$if_t3_is_the_max = \$t3 == \$max \$if_t4_is_the_max = \$t4 == \$max \$if_t5_is_the_max = \$t5 == \$max \$if_t6_is_the_max = \$t6 == \$max \$if_t7_is_the_max = \$t7 == \$max \$if_t8_is_the_max = \$t8 == \$max Prior to looking for the max a second time, we must remove or replace the values from each of the signals when they are equal to the max. In this method, we will replace the highest signal values with zero using the splice function during the condition when that signal was the max. With these highest values replaced by zero (or removed), applying the same technique with the max function will yield the value of the second highest signal. //replace the max with 0 \$removing_the_max_value = (\$t1.splice(0,\$if_t1_is_the_max)) .max(\$t2.splice(0,\$if_t2_is_the_max)) .max(\$t3.splice(0,\$if_t3_is_the_max)) .max(\$t4.splice(0,\$if_t4_is_the_max)) .max(\$t5.splice(0,\$if_t5_is_the_max)) .max(\$t6.splice(0,\$if_t6_is_the_max)) .max(\$t7.splice(0,\$if_t7_is_the_max)) .max(\$t8.splice(0,\$if_t8_is_the_max)) .toStep() return \$removing_the_max_value Step 4: Create Metric Threshold Limits Subtract the highest signal by a fairly small value using Formula tool in order to use signal as a threshold limit. Repeat the step for second highest limit. \$max-0.001 Step 5: Create scorecard metric for each signal. Create scorecards for all 8 signals, as an example we choose value at the end for statistic for daily condition and apply the threshold accordingly. In the table view: Do check this post by Nick. He used different approach to yield the maximum of three signals, and displayed signal string in a matrix table.
4 points
21. ## Create a condition for a variable portion of another condition

For those Formula-savvy users, a one Formula approach to this would be as follows where you would define your percentage of the capsule in the first line: \$percent = 10%.tosignal().resample(1s) \$condition.transform(\$capsule ->{ \$movetime = \$capsule.duration()*\$percent.toScalars(\$capsule).first() capsule(\$capsule.startKey(),\$capsule.startKey()+\$movetime)})
4 points

4 points
23. ## Display Start or End Time in Specific Format

Various parts of the world display date and time stamps differently. Often times, we get requests for changing the order of month and day in the timestamp string or to display the date as a Scorecard metric in a specific format. This can be done using the replace() operator in Formula. For example, let's say we wanted to pull the start time for each capsule in a condition and display it as mm/dd/yyyy hh:mm format: \$condition.transformToSamples(\$cap -> Sample(\$cap.getStart(),\$cap.getProperty('Start')), 1d) .replace('/(?<year>....)-(?<month>..)-(?<day>..)T(?<hour>..):(?<minute>..):(?<sec>..)(?<dec>.*)Z/' , '\${month}/\${day}/\${year} \${hour}:\${minute}') This takes the original timestamp (for example: '2019-11-13T17:04:13.7220714157Z') and parses it into the year, month, day, hour, minute, second, and decimal to be able to set up any format desired. The various parts of the string can then be called in the second half of the replace to get the desired format as shown above with \${month}/\${day}/\${year} \${hour}:\${minute}. From there, you can either view this data in the trend or use Scorecard Metric to display the Value at Start in a condition based metric. If the end time is desired instead of the start, the only changes needed would be to (1) switch the .getStart operator to .getEnd, and (2) switch the .getProperty('Start') to .getProperty('End'). Note: The '1d' at the end of the 2nd line of the formula represents the maximum interpolation for the data, which is important if you want to view this as a string signal. This value may need to be increased depending on the prevalence of the capsules in the condition.
4 points
24. ## Jupyter Docstring Shortcut

Sometimes users want to find more documentation on the SPy functions than what is provided in the SPy Documentation Notebooks. A quick way to access SPy object documentation from your notebook is by using the Shift + Tab shortcut to access the docstring documentation of the function. Example view of the docstrings after using the Shift + Tab shortcut: You can expand the docstrings to view more details by clicking the + button circled in red in the above image. Expanded docstrings: From here, you can scroll through the documentation in the pop-up window. Another useful shortcut is the Tab shortcut. This will show a list of available functions or methods for either the SPy module or any other python object you have in memory. Example view of the Tab shortcut:
4 points
25. ## Adjusting the size of lanes

Hi Theresa, no, you cannot adjust the size of the lanes itself.But you can use the "Dimming" feature of Seeq to show only lanes with items selected in the Details Pane: Regards, Thorsten
4 points
26. ## Create function to calculate total duration with multiple conditions

Hi Esther, you can do this the following way: 1. Create a Periodic Condition (found in Tools - Pane): 2. Use Signal from Condition to calculate the total duration. Result: Regards, Thorsten
4 points
27. ## Truncating string signals

The replace operator can be applied a signal without a transform. Using the replace function without the transform will be less computationally expensive, resulting in better performance. Both ways will get to the same answer. Syntax for replace function without transform: \$signal.replace('/(\\d+)_\\d+_\\w+/', '\$1')
4 points
28. ## Truncating string signals

Hi Pablo, you can use transform() and replace() to do this. I made an example with a signal that contains the following data: To create a signal that contains only the numeric values I used the following formula: \$originalSignal.transform((\$p, \$c) -> sample(\$c.getKey(), \$c.getValue().replace('/\\w+\\s(\\d+)/', '\$1'))) Transform is used to access every sample in the signal by specifying a lambda expression. The current sample is temporarily stored in the variable \$c. \$p contains the previous sample which is not used here. For each sample of the original signal a new sample is created by using the timestamp (key) of the original sample. The value for the new sample is determined by the value of the sample of the original signal on which replace() is executed. As the name suggests replace() is used to replace portions of a string. In this case I make use of a regular expression to determine the numeric value inside the original string and replace the original string by the determined value. The result looks like this: For your example (12345_20200326_PJR) you have to modify the replace part to: .replace('/(\\d+)_\\d+_\\w+/', '\$1') Hope this helps. Regards, Thorsten
4 points
29. ## Using formulas to get duration of a capsule

Hi Banderson, you can create a duration signal from each capsule in a condition, using "signal from condition" tool. As you may know these point and click tools create a Seeq formula underneath. So after using point and click signal from condition tool, you can find the syntax of formula in item properties of that calculation. You can copy this syntax and paste it in Formula and use it to further develop your calculations.
4 points
30. ## Create condition for past N batches

Here's an alternative method to getting the last X batches in the last 30 days: // return X most recent batches in the past Y amount of time \$numBatches = 20 // X \$lookback = 1mo // Y // create a rolling condition with capsules that contain X adjacent capsules \$rollingBatches = \$batchCondition.removeLongerThan(\$lookback) .toCapsulesByCount(\$numBatches, \$lookback) // find the last capsule in the rolling condition that's within the lookback period \$currentLookback = capsule(now()-\$lookback, now()) \$batchWindow = condition( \$lookback, \$rollingBatches.toGroup(\$currentLookback, CAPSULEBOUNDARY.ENDSIN).last() ) // find all the batches within the capsule identified // ensure all the batches are within the lookback period \$batchCondition.inside(\$batchWindow) .touches(condition(\$lookback, \$currentLookback)) This is similar to yours in that it uses toGroup, but the key is in the use of toCapsulesByCount as a way to get a grouping of X capsules in a condition. You can see an example output below. All capsules will show up as hollow because by the nature of the rolling 'Last X days' the result will always be uncertain.
3 points
31. ## Replace Gaps in Data with an Average Value from Previous Time Frame

FAQ: I have a signal with a gap in the data from a system outage. I want to replace the gap with a constant value, ideally the average of the time period immediately before the data. Solution: 1. Once you've identified your data gaps, extend the capsules backwards by the amount over which time you want to take the average. In this example, we want to fill in the gap with the average of the 10 minutes before the signal dropped, so we will extend the start of the data gap capsule 10 minutes in the past. This is done using the move function in Formula: \$conditionForDataGaps.move(-10min,0min) 2. Use Signal from Condition to calculate the average of the gappy signal during the condition created in step 1. Make sure to select "Duration" for the timestamp of the statistic. 3. Stitch the two signals together using the splice function. The validvalues() function at the end ensures a continuous output signal. \$gappysignal.splice(\$replacementsignal,\$gaps).validvalues()
3 points
32. ## Convert wind direction degrees to N,S, etc

If you modify your wind_dir variable to \$wind_dir = group( capsule(0, 22.5).setProperty('Value', 'ENUM{{0|N}}'), capsule(22.5, 67.5).setProperty('Value', 'ENUM{{1|NE}}'), capsule(67.5, 112.5).setProperty('Value', 'ENUM{{2|E}}'), capsule(112.5, 158.5).setProperty('Value', 'ENUM{{3|SE}}'), capsule(158.5, 202.5).setProperty('Value', 'ENUM{{4|S}}'), capsule(202.5, 247.5).setProperty('Value', 'ENUM{{5|SW}}'), capsule(247.5, 292.5).setProperty('Value', 'ENUM{{6|W}}'), capsule(292.5, 337.5).setProperty('Value', 'ENUM{{7|NW}}'), capsule(337.5, 360).setProperty('Value', 'ENUM{{8|N}}') ) You will get an ordered Y axis: This is how Seeq handles enum Signal values from other systems - it has some limitations, but it seems like it should work well for your use case.
3 points
33. ## Osisoft PI Vision Integration with Seeq

Hi Coolhunter, I have seen this requested multiple times and one solution might be to use a custom PI Vision symbol that enables you to embed Seeq content into PI Vision. A solution to this challenge can be found here: Get the most out of PI Vision - Seeq Analytics in PI Vision - Seeq in PI Vision (werusys.de) If you want to know more about the PI Vision integration with Seeq feel free to drop me a mail: julian.weber@werusys.de Cheers, Julian Seeq-WerusysPIVision.pdf
3 points
34. ## How do I apply Machine Learning Algorithm at Scale in Seeq?

Check out the data lab script and video that walks through it to automate data pull->apply ml->push results to workbench in an efficient manner. Of course you can skin the cat many different ways however this gives a good way to do it in bulk. Use case details: Apply ML on Temperature signals across the whole Example Asset Tree on a weekly basis. For your case, you can build you own asset tree and filter the relevant attributes instead of Temperature and set spy.jobs.schedule frequency to whatever works for you. Let me know if there are any unanswered questions in my post or demo. Happy to update as needed. apply_ml_at_scale.mp4 Apply ML on Asset Tree Rev0.ipynb
3 points

3 points
36. ## Capsule Based Regression/Prediction

The following steps will create a prediction model for every capsule in a condition. Step 1. pick a condition with capsules that isolate the desired area of regression. Any condition with non-overlapping capsules will work as long as there are enough sample points within its duration. For this example, an increasing temperature condition will be used. However, periodic conditions and value search conditions will work as well. Step 2. Create a time counter for each capsule in the condition. This can be done with the new timesince() function in the formula tool. The timesince() function will have samples spaced depending on the selected period so it is important to select a period that has enough points to build a model with. See below for details on the timesince() formula setup. Step 3. In this step a condition with capsule properties that hold the regression constants will be made. This will be done in the formula tool with one formula. The concept behind the formula below is to split the condition from step one into individual capsules and use each of the capsules as the training window for a regression model. Once the regression model is done for one capsule the coefficients of the model are assigned as properties to the capsule used for the training window. The formula syntax for a linear model-based condition can be seen below. An example of a polynomial regression model can be found in the post below. \$Condtition.removeLongerThan(24h).transform(\$cap-> { \$model=\$SignalToModel.validValues().regressionModelOLS( group(\$cap),false,\$Time) \$cap.setProperty('Slope',\$model.get('coefficient1')) .setProperty('Intercept',\$model.get('intercept'))}) Below is a screenshot of how the formula looks in Seeq. Note: The regression constants can be added to the capsule pane by clicking on the black stats button and selecting add column. Below is a screen shot of the results. Step 4. Once a condition with the regression coefficients has been created the information will need to be extracted to a signal form. The following formula syntax will extract the information. This will need to be repeated for every constant from your regression model. e.g.(So for a linear model this must be done for both the slope and for the intercept.) The formula syntax for extracting the regression coefficients can be seen below. \$signal=\$Condition.transformToSamples( \$cap -> sample(\$cap.getmiddle(), \$cap.getProperty('Intercept').toNumber()), 1min) \$signal.aggregate(average(),\$Condition,durationKey()) Below is a screenshot of the formula in Seeq. Below is a screenshot of the display window of how the signals should look. Step 5. Use the formula tool to plot the equation. See screenshot below for details. Final Result
3 points
37. ## Chemical Usage Report

I know this is an old thread, but I am including what I did in case posterity finds it useful. I am more or less working the the same issue, but with a somewhat noisier and less reliable signal. I found the above a helpful starting point, but had to do a bit of tweaking to get something reliable that didn't require tuning. The top lane is the raw signal, from which I remove all the drop outs, filled in any gaps with a persisted value, and did some smoothing with agile to get the cleansed level on the next lane. For the value decreasing condition I used a small positive threshold (since there were some small periods of the levels fluctuating and the tank being refilled was a very large positive slope) and a merge to eliminate any gaps in the condition shorter than 2 hours (since all the true fills were several hours). For the mins and maxes I did not use the grow function on the condition like was done above, instead just used relatively wide max durations and trusted that the cleansing I did on value decreasing was good enough. I was then able to use the combinewith and running delta function on the mins and maxes, and filter to get the deliveries and the usage. One additional set of calculations I added was to filter out all the periods of deliveries by converting the Delta function to a condition and removing all the data points in conditions that started positive from the cleansed signal. I then subtracted a running sum of the delta function over a quarter, yielding a signal that without the effect of an of the deliveries over each quarter. I could then aggregate the delta for days and quarters of that signal to get the daily and quarterly consumption figures. Chart showing all the calculated signals for this example. Top lane is the raw signals. Next lane shows the cleansed signal with the nexus of the mins and maxes between deliveries. Middle lane combines the mins and maxes and takes the running deltas, and then filters them into delivery and usage numbers. The next lane removes the deliveries from the cleansed signal and does a running sum of the consumption over the quarter. The last two lanes are daily and quarterly deltas in those consumption figures. Calculation for identifying the periods in which the chemical level is decreasing. I used a small positive threshold and removed two hour gaps, and that allowed it to span the whole time between deliveries. Aggregate the cleansed signal over those decreasing time periods to find the min and max values. Used the combinewith and running delta functions to get the next deltas of consumption and deliveries. Filtered based on positive and negative value to separate into deliveries and consumption numbers. Removed the delivery numbers from the cleansed signal in order to get a running sum of consumption over a quarter. aggregated the deltas in the consumption history over days and quarters to calculate daily and quarterly consumption.
3 points
38. ## Metric Calculations

I believe the unbounded error is because the original code creates conditions for >=0 and <0 with no maximum duration. You can change \$gte and \$lte to have max durations and this may fix the issue. \$gte = (\$delta >= 0).setMaximumDuration(7d) \$lt = (\$delta < 0).setMaximumDuration(7d) In your example, the reversal count will not count 3, it will count one. Let's transform your example as runningDelta() would and assume the previous value was also 5. 5 -> 5 -> 10 -> 15 -> 10 becomes 0 -> 5 -> 5 -> -5 Now let's identify the gte and lt conditions. We would see an \$gte {0 -> 5 -> 5->}, and an \$lt at {-> -5}. Use our formula and the result would be 1 reversal. However this does bring up a potential issue. If the example had another 10 at the end, the delta samples would become 0 -> 5 -> 5 -> -5 -> 0 and that would create an additional \$gte capsule at the very end, resulting in 2 reversals. You could fix this by change the \$gte to only greater than instead of greater than or equal zero. Thanks, Andrew
3 points
39. ## Adding Line Segments to XY Plots

Sometimes when looking at an xy plot, it can be helpful to use lines to designate regions of the chart that you'd like users to focus on. In this example, we want to draw a rectangle on the xy plot showing the ideal region of operation, like below. We can do this utilizing Seeq's ability to display formulas overlaid against an xy plot. 1. For this first step, we will create a ~horizontal line on the scatter plot at y=65. This can be achieved using a y=mx+b formula with a very small slope, and a y-intercept of 65. The equation for this "horizontal" line on the xy plot is: 0.00001*\$x+65 2. If we want to restrict the line to only the segment making the bottom of our ideal operation box, we can leverage the within function in formula to clip the line at values we specify. Here we add to the original formula to only include values of the line between x=55 and 5=60. (0.00001*\$x+65) .within(\$x>55 and \$x<60) 3. Now let's make the left side of the box. A similar concept can be applied to create a vertical line, only a very large positive or negative slope can be used. For our "vertical" line at x=55, we can use the following formula. Note some adjustment of the y-axis scale may be required after this step. (-10000*(\$x-55)) 4. To clip a line into a line segment by restricting the y values, you can use the max and min functions in Formula, combined with the within function. The following formula is used to achieve the left side boundary on our box: (-10000*(\$x-55)) .max(65) .min(85) .within(\$x<55.01 and \$x>54.99) The same techniques from steps 1-4 could be used to create the temperature and wet bulb max boundaries. Formula for max temp boundary: (0.00001*\$x+85).within(\$x>55 and \$x<60) Formula for max wet bulb boundary: (-10000*(\$x-60)) .max(65) .min(85) .within(\$x<60.01 and \$x>59.99) CONTENT VERIFIED MAY2024
3 points
40. ## Create a Condition Each Time Value Changes

Hi Julian, The first formula (\$signal.toCondition()) will create a capsule the length of each time frame between step changes. From there, you can use Signal from Condition to calculate the "Total Duration" statistic for each of the capsules created (use the result of the formula for both the condition of interest and bounding condition).
3 points
41. ## Change Color of Overlayed Signals in Capsule Time View Based on Conditions

To change the color of signals overlaid in capsule time view to highlight the different capsules, coloring options have been made available in versions R22.0.48.00 and later. For more information on the this capability visit our Knowledge Base. Users can utilize Rainbow, Gradient, or Gradient by Condition to distinguish signals in the trend Content Verified MAY2024
3 points
42. ## Polynomial formula

Hello Arnaud, the error is occuring because of the unit of the signal. I guess the unit of your signal is "t" which is converted to "t²" and "t³" for the respective parts of the formula. Therefore they cannot be used in an addition or subtraction. To get the fomula working simply convert the signal to a unitless one before calculating the polynom. The resulting signal is unitless. You can use the setUnits() function to specify a unit if you need one. Hope this helps. Regards, Thorsten
3 points
43. ## Search and Display SEEQ signals/KPIs for related AF assets

This week, I used the Journal link approach suggested by Kjell for 40 similar assets ! (Yes 40) and created couple of scorecard tables and output them to an organizer topic. This exercise was a good test of hand eye coordination and patience 🙂 Hopefully in a near future, I can rely on better and more efficient experience in seeq for this use case.
3 points
44. ## EXCEL IF(x,y1,y2)

Hi Tommy, The easiest way to do this in Seeq is to use a condition to define the if condition, and then splice in a new signal when your condition is true. Follow the steps below to achieve this. 1) Use the Value Search tool to find when your signal .OP <= 0 2) In Formula, enter the following: \$flowsignal.splice(0.toSignal(), \$conditionclosed) where \$flowsignal is your Flow Rate signal, and \$conditionclosed is the condition we created in Step 1. What we are doing here is splicing in a new signal we create ( 0.toSignal() ) which will equal 0 when the .OP <= condition is true. You could also write all of this into 1 Formula (combining steps 1 & 2 together) by writing the following: \$conditionclosed = \$OP.validValues().valueSearch(isLessThanOrEqualTo(0)) \$flowsignal.splice(0.toSignal(),\$conditionclosed) Please let me know if this solved your question. -Kjell
3 points
45. ## Creating Capsules based on when a signal changes by a given amount

Hi Greg Since you already have a condition identifying when your signal changes, to identify the magnitude of the change all you need to do is use Signal From Condition. Here is an example of how it might look: In this case i am using "Range" because it will always give me a positive value of the change in my power signal. If i wanted to know if it was positive or negative I would use "Delta" instead. Here i am using the Duration as my timestamp so i can more easily accomplish the next step- filtering the original change condition. Since you want to count the number of instances the value changes by more than some amount, we can then filter our original condition (the one that identified the change) so it only retains the capsules where the change was over your threshold. To do this i will use Formula: In this case, i am filtering my Load Swing to keep capsules where the swing is greater than 25kW. You can see the filtered condition is shown in blue where my original Condition is shown in green. From here, you can use the Scorecard Metric to count the number of the filtered capsules. Hope this helps!
3 points

3 points
47. ## Creating a Condition for Equipment Start-up

Hi Chris- I think this can be achieved using a combination of the Value Search and Composite Condition tools. In the following screenshot, I have a signal (temperature) and a condition (Start Capsule). Let's say I'd like to create a new condition that starts at the start of each capsule in Start Capsule and ends when the temperature is 90. First, use the Value Search tool to identify when the temperature is 90 F. This results in several small capsules each time the temperature is 90 F. Next, combine these 2 conditions using the join operator in the Composite Condition tool: This results in a new condition (Start to Temp=90) where each capsule starts at the start the Start Capsule capsule and ends at the start of the Temp=90 capsule. Please let me know if you have any additional questions. Thanks, Lindsey
3 points
48. ## Monthly Average under certain conditions

Hi Moriel, you can use a formula to calculate this: In this example I calculate the average power consumption for each month only when "Compressor Stage" equals "STAGE 2". Regards, Thorsten
3 points
49. ## Incorrect derivative result

FAQ: Why does the derivative look funny? When taking a derivative and the result looks like the screenshot below, but a smoother signal is expected it is likely that the input signal is step interpolated. To verify this, click on the item properties “I” on the input signal and check the interpolation method. Item Properties View The interpolation method can be corrected by simply adding toLinear() in front of the derivative. See screen shot below of the formula. Final Results
3 points
50. ## How can I identify a profile on one signal and find when it occurs on a different signal?

Seeq Version: R21.0.43.03 but the solution is applicable to previous versions as well. The Profile Search Tool is great for specifying a profile in Signal A and then looking for occurrences of that profile throughout time. In the screenshot below I've used Profile Search to identify when the Compressor Power Area A resembles the shape of a chair. For basics about how to use the tool check out the Seeq KB article Profile Search. However, what if I want to look for that same profile on another signal? In the screenshot below, I've added a second signal, Compressor Power Area G. I'd like to identify when the "chair" profile I previously specified for Compressor Power Area A is present in Compressor Power Area G. I can do this by using the profileSearch() function in Seeq Formula. Here is how... 1. Start with the Chair in Area A condition I previously made and use Duplicate to Formula. The duplicated formula looks like (note that \$cpA refers to Compressor Power Area A): profileSearch(\$cpA, toTime("2019-09-02T15:43:30.135Z"), toTime("2019-09-03T06:28:09.629Z"), 98, 0.5, 0.3, 0.3) 2. Modify the formula to add \$cpG (Compressor Power Area G) to the start of the function. This is an optional argument in Profile Search which allows us to use the profile identified on signal \$cpA and look for when it occurs on signal \$cpG. For more information on the Profile Search function, check out the documentation available in the Formula Tool. \$cpG.profileSearch(\$cpA, toTime("2019-09-02T15:43:30.135Z"), toTime("2019-09-03T06:28:09.629Z"), 98, 0.5, 0.3, 0.3) Here is a screenshot of what it looks like in the Formula Tool: 3. View the final result. In this example two "chairs" where identified in Area G.
3 points
This leaderboard is set to Los Angeles/GMT-07:00
×
×
• Create New...