Jump to content
  • To Search the Seeq Knowledgebase:


Search the Community

Showing results for tags 'aggregate'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • Community Technical Forums
    • General Seeq Discussions
    • Seeq Admin Forum
    • Training Resources
    • Product Suggestions
    • Seeq Data Lab
  • Community News
    • Seeq Blog Posts
    • News Articles
    • Press Releases
    • Upcoming Events
    • Resources


  • Seeq FAQs
  • Online Manual
    • General Information

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start



About Me



Level of Seeq User

Found 7 results

  1. Seasonal variation can influence specific process parameters whose values are influenced by ambient conditions, or perhaps raw material make up changes over the year's seasons based on scheduled orders from different vendors. For these reasons and more, it may not suffice to compare your previous month's process parameters against current. For these situations, it may be best to compare current product runs against previous product runs occurring the same month, but a year ago in order to assess consistency or deviations. In Seeq, this can be achieved through utilizing Condition Properties. 1. Bring in raw data. For this example, I will utilize a single parameter (Viscosity) and a grade code signal. 2. Convert Product step-signal into a condition. Add properties of Product ID, Variable statistic(s), and month start/end times. // Create a month condition. Be sure to specify your time zone so that start/end times are at 12:00 AM $m = months('US/Eastern') // Create a signal for start and end times to add into "Product ID" condition $start_signal = $m.toSignal('Start', startKey()).toStep() $end_signal = $m.toSignal('End', startKey()).toStep() $p.toCondition('Product ID') // Convert string signal into a condition, with a capsule at each unique string // Specifying 'Product ID' ensures the respective values in Signal populate // a property named 'Product ID' .removeLongerThan(100d) // Bound condition. 100d as arbitrary limit .setProperty('Avg Visc', $vs, average()) // Set 'Avg Visc' property reflecting avg visc over each Product ID .setProperty('Month Start', $start_signal, startValue()) // Set 'Month Start' property to know what month Product ID ran .setProperty('Month End', $end_signal, startValue()) // Set 'Month End' property to know what month Product ID ran 3. Create another condition that has a capsule ranging the entire month for each product run within the month. Add similar properties, but note naming differences of 'Previous Month Start' and 'Previous Month Avg Visc'. This is because in the next step we will move this condition forward by one year. $pi.grow(60d) // Need to grow capsules in the condition to ensure they consume the entire month .transform($capsule -> // For each capsule (Product Run) in 'Product ID'.... capsule($capsule.property('Month Start'), $capsule.property('Month End')) // Create a capsule ranging the entire month .setProperty('Product ID', $capsule.property('Product ID')) // Add property of Product ID .setProperty('Previous Month Start', $capsule.property('Month Start')) // Add property of Month Start named 'Previous Month Start' .setProperty('Previous Month Avg Visc', $capsule.property('Avg Visc')) // Add property of Avg Visc named 'Previous Month Avg Visc' ) Notice we now have many overlapping capsules in our new condition ranging an entire month -- one for each Product Run that occurred within the month. 4. Move the previous 'Month's Product Runs' condition forward a year and merge with existing 'Product ID' condition. Aggregate properties of 'Previous Month Avg Visc'. This ensures that if a product was ran multiple times and had different avg visc values in each run, then what is displayed will be the average of all the avg visc values for each product. $previousYearMonthProductRun = $mspi.move(1y) // Move condition forward a year $pi.mergeProperties($previousYearMonthProductRun, 'Product ID', // Merge the properties of both conditions only if their // capsules share a common value of 'Product ID' keepProperties(), // keepProperties() will preserve all existing properties aggregateProperty('Previous Month Avg Visc', average())) // aggregateProperty() will take the average of all 'Previous // Month Avg Visc' properties if multiple exist... I.e. if // there were multiple Product Runs, each with a different value // for 'Previous Month Avg Visc', then take the average of all of // them. The resulting condition will match our original condition, except now with two new properties: 'Previous Month Start' & 'Previous Month Avg Visc' We can then add these properties in a condition table to create a cleaner view. We could also consider creating any other statistics of interest such as % difference of current Avg Visc vs Previous Month Avg Visc. To do this, we could use a method similar to gathering $start_signal and $end_signal in Step 2, create the calculation using the signals, then add back to the condition as a property.
  2. Chromatography Transition Analysis in Seeq Many biopharmaceutical companies use Transition Analysis to monitor column integrity. Transition Analysis works by using a step change in the input conductivity signal and tracking the conductivity at the outlet of the column. The output conductivity transition can be analyzed via moment analysis to calculate the height of a theoretical plate (HETP) and the Asymmetry factor as described below. Step 1: Load Data and Find Transition Periods In order to perform this analysis in Seeq, we start by loading outlet conductivity and flow rate data for the column: Note: Depending on the density of the conductivity data, many companies find that some filtering of the data needs to be performed to get consistent results when performing the above differential equations. The agilefilter operator in Formula can be helpful to perform this filtering if needed: $cond.agileFilter(0.5min) Once the data is loaded, the next step is to find the transition periods. The transition periods can be found using the Profile Search tool as shown in the screenshot below. Alternate methods using changes in the signal such as a delta or derivative with Value Searches have also been applied. Step 2: Calculate HETP As the derivatives are a function of volume instead of time, the next step is to calculate the volume using the following formula: Volume = $flow.integral($Trans) The dC/dV function used in the moment formulas can then be calculated: dCdV = runningDelta($Cond) / runningDelta($vol) Using that function, the moments (M0 through M2) can be calculated: M0 = ($dCdV*runningDelta($vol)).aggregate(sum(), $Trans, middleKey()) M1 = (($vol*$dCdV)*runningDelta($vol)).aggregate(sum(), $Trans, middleKey()) M2 = (($dCdV*($vol^2))*runningDelta($vol)).aggregate(sum(), $Trans, middleKey()) The moments are then used to calculate the variance: Variance = ($M2/$M0) - ($M1/$M0)^2 Finally, the HETP can be calculated: HETP = ((columnlength*$variance)/($M1/$M0)^2) In this case, the column length value needs to be inserted in the units desired for HETP (e.g. 52mm). The final result should look like the following screenshot: Alternatively, all of the calculations can be performed in a single Formula in Seeq as shown in the code below: $vol = $flow.integral($Trans) $dCdV = runningDelta($cond) / runningDelta($vol) $M0 = ($dCdV*runningDelta($vol)).aggregate(sum(), $Trans, middleKey()) $VdCdV = $vol*$dCdV $M1 = ($VdCdV*runningDelta($vol)).aggregate(sum(), $Trans, middleKey()) $V2dCdV = $dCdV*$vol^2 $M2 = ($V2dCdV*runningDelta($vol)).aggregate(sum(), $Trans, middleKey()) $variance = ($M2/$M0) - ($M1/$M0)^2 (52mm*$variance)/(($M1/$M0)^2) //where 52mm is the column length, L Step 3: Calculate Asymmetry Asymmetry is calculated by splitting the dC/dV peak by its max value into a right and left side and comparing the volume change over those sides. This section assumes you have done the calculations to get volume and dC/dV calculated already as performed for HETP in Step 2 above. The first step for Asymmetry is to determine a minimum threshold for dC/dV to begin and end the peaks. This is often done by calculating a percentage of the difference between the maximum and minimum part of the transition period (e.g. 10%): $min = $dCdV.aggregate(minValue(), $Trans, durationKey()) $max = $dCdV.aggregate(maxValue(), $Trans, durationKey()) $min + 0.1*($max - $min) The Deviation Search tool can then be used to identify the time when dC/dV is greater than the 10% value obtained above. Next, the maximum point of the dC/dV peaks can be determined by calculating the derivative of dC/dV in the Formula tool: $dCdV.derivative() The derivative can then be searched for positive values (greater than 0) with the Value Search tool to identify the increasing part of the dC/dV curve. Finally, a Composite Condition intersecting the positive dC/dV derivative and the transition values above 10% of the curve will result in the identification of the left side of the dC/dV curve: The right side of the dC/dV curve can then be determined using Composite Condition with the A minus B operator to subtract the positive dC/dV derivative from the transition above 10%: The change in volume can then be calculated by aggregating the delta in volume over each side of the peak using Formula: $Vol.aggregate(delta(), $LeftSide, middleKey()).aggregate(maxValue(), $Trans, middleKey()) Finally, the Asymmetry ratio can be calculated by dividing the volume change of the right side of the peak divided by the volume change of the left side of the peak. $VolRightSide/$VolLeftSide The final view should look similar to the following: Similar to HETP, all of the above formulas for Asymmetry may be calculated in a single formula with the code below: $vol = $flow.integral($Trans) $dCdV = (runningDelta($cond) / runningDelta($vol)).agileFilter(4sec) //calculate 10%ile of dCdV $min = $dCdV.aggregate(minValue(), $Trans, durationKey()) $max = $dCdV.aggregate(maxValue(), $Trans, durationKey()) $dCdV10prc = $min + 0.1*($max - $min) //Deviation search for when dCdV is above the 10%ile $deviation1 = $dCdV - $dCdV10prc $Above10 = valueSearch($deviation1, 1h, isGreaterThan(0), 0min, true, isLessThan(0), 0min, true) //Calculate filtered derivative of dCdV $dCdVderiv = $dCdV.derivative() //Value Search for Increasing dCdV (positive filtered derivative of dCdV) $dCdVup = $dCdVderiv.validValues().valueSearch(40h, isGreaterThan(0), 30s, isLessThanOrEqualTo(0), 0min) //Composite Conditions to find increasing left side above 10% and right side $LeftSide = $Above10.intersect($dCdVup) $RightSide = $Above10.minus($dCdVup) //Find change in volume over left side and right sides, then divide b/a $VolLeftSide = $Vol.aggregate(delta(), $LeftSide, middleKey()).aggregate(maxValue(), $Trans, middleKey()) $VolRightSide = $Vol.aggregate(delta(), $RightSide, middleKey()).aggregate(maxValue(), $Trans, middleKey()) $VolRightSide/$VolLeftSide Optional Alteration: Multiple Columns It should be noted that oftentimes the conductivity signals are associated to multiple columns in a chromatography system. The chromatography system may switch between two or three columns all reading on the same signal. In order to track changes in column integrity for each column individually, one must assign the transitions to each column prior to performing the Transition Analysis calculations. Multiple methods exist for assigning transitions to each column. Most customers generally have another signal(s) that identify which column is used. This may be valve positions or differential pressure across each column. These signals enable a Value Search (e.g. “Open” or “High Differential Pressure”) to then perform a Composite Condition to automatically assign the columns in use with their transitions. Alternatively, if no signals are present to identify the columns, the columns can be assigned manually through the Custom Condition tool or assigned via a counting system if the order of the columns is constant. An example of Asymmetry calculated for multiple columns is shown below:
  3. Summary There are many use cases where the user wants to do an aggregation over a periodic time frame, but only include certain values. Examples abound: for cement calculate the average daily clinker production only when the kiln is running, for biotech pharma the standard deviation of dissolved oxygen only when the batch is running, etc. Here our user is looking into equipment reliability for compressors. She wants to calculate the average daily compressor power to examine its performance over time. Steps 1. Add the signal into Seeq. 2. Use the 'Periodic Condition' or 'Formula' Tool to add a condition for days. This doesn't have to be days, it can be any arbitrary time, but it is usually periodic in nature. To use a custom periodic Condition, consider using the periods() function. For example to do this for days, the formula is: periods(1day) As an example, to change this to 5-minute time periods the formula is: periods(5min) Here are how the days and statistics in the Capsule Pane look for her: 3. Find only the desired values to be used in the aggregate (e.g. Average) statistic. From the values in the Capsule Pane she sees that the average compressor powers results are too low. This is because all the time when the compressor was OFF, near 0, are included in this calculation. She wants to only include times when the compressor is running because that will provide a true picture of how much energy is going into the equipment - and can indicate potential problems. To do this, she creates a 'Value Search' for times to include in this calculation, in this case when the Compressor is ON or > 0.5kW. 4. Create a new signal to only have values *within* the 'Compressor ON' condition. Use the aptly named 'within' function in the 'Formula' Tool. Notice how the resulting Signal in the bottom lane only has values within the 'Compressor ON' condition. Now she can use this because all those 0's that were causing the time-weighted Average to be low... are now gone. 5. Examine the resulting statistical values. She now sees that the calculations are correct and can use this resulting 'Compressor Power only when ON' Signal in other calculations using 'Signal from Condition', 'Scorecard Metric', and other Seeq Tools!
  4. There are many cases where a moving average needs to be monitored. To create any statistic that is associated with a sliding time frame, first use the periods() function in Formula to create the periodic capsules. A few examples are listed below. Intent Seeq Formula 30 day average every 1 day periods(30d,1d) 24 hour average every 1 hour periods(1d,1h) 30 minute average every 5 minutes periods(30min,5min) Once the periodic condition is created, use Signal from Condition to calculate a moving average, max, min, or other statistic. The sliding capsules will appear overlapped in the capsules lane. Refer to the capsules pane to verify the capsules meet your expectation of start time and duration, then apply the desired "moving" aggregation (average, standard deviation, etc.) to any signal with the Signal from Condition tool. Below shows a moving 30 minute average sampled every 5 minutes on the Example Temperature data.
  5. FAQ: I've got a signal for which the average and standard deviation are believed to be drifting over time. When I view the average and standard deviation in calendar time, it isn't helpful because they are highly dependent upon the production grade that I am running. Is there a better way that I could be viewing my data to get a sense of the drift of the average and standard deviation by production grade over time? Solution 1: Histogram 1. Add your signal of interest and your production grade code signal to the display. 2. Create a condition for all production grades using formula: $gradeCode.toCondition() 3. Use the Histogram tool to calculate the average reactor temperature during each grade campaign and display them aggregated over production grade, and time. The same methods from step 3 can be applied to get a second histogram of the distribution of the standard deviation of the signal of interest by grade over time. Solution 2: Chain View 1. Add your signal of interest and your operating state signal to the display. 2. Use Formula to create a condition for all operating states: $stateSignal.toCondition() 3. Use the Signal from Condition tool to calculate the average temperature over the all operating states condition. 4. Use the Signal from Condition tool to calculate the standard deviation of temperature over the all operating states condition. 5. Use Formula to calculate two new signals for “Avg + 2 SD” and “Avg – 2 SD”. 6. Filter your all operating states condition for only the state that you are interested in viewing. In this example we want to view only the capsules during which the compressor is in stage 2, for which the syntax is: $AllOperatingStates.removeLongerThan(7d).removeShorterThan(4h).filter($capsule -> $capsule.getProperty('Value').isEqualTo('STAGE 2')) This formula is taking our condition for all operating states, keeping only capsules that are between 4h and 7d in length, then filtering those capsules to include only those for which the value is equal to stage 2. 7. Swap to chain view and view a longer time range.
  6. The histogram tool when aggregated over time can cause some confusion as to what hours of the day the values of the bins reflect. The bin labels that are generated by Seeq reflect the hour of the day beginning at midnight. So for example, 0 = midnight, 2 = 2 AM, 14 = 2 PM, etc. When the display range interval is set to one day beginning at midnight, the histogram bins line up with the signal value quite nicely (see attached screenshot 2). When the display range is not set to begin at midnight, or is set to multiple days, the histogram bins may not appear to line up with the process data (see attached screenshot 1), but the distribution that they reflect is correct for the day(s) in the display range. histogram tool discussion - screenshot 1.pdf histogram tool discussion - screenshot 2.pdf
  7. Hi, Referring to the given example, '$condition.transformToSamples($capsule -> sample($capsule.getStart(), $capsule.duration()), 1d)', how do I plot the starting value instead of the duration? Thank you.
  • Create New...