# Search the Community

Showing results for tags 'formula'.

• ### Search By Tags

Type tags separated by commas.

### Forums

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

### Calendars

• Community Calendar

### Categories

• Seeq FAQs
• Online Manual
• General Information

• Published
• Code
• Media

• 0 Replies

• 0 Reviews

• 0 Views

### Level of Seeq User

Found 49 results

2. 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. I have an interesting question that I need some assistance on. We have a signal that generally has no dominant frequency. However, it sometimes does get a dominant frequency and when it does, we are really interested in two things: What is the dominant frequency? How dominant is it? ( Let's call this "magnitude." ) Tracking both the dominant frequency and the intensity over time using a rolling 2 to 3 hour window every 5 minutes. This value has predictive capability when it does show up, and it intensifies as it gets closer to a particular event we are trying to predict. I've been able get the peak frequency because the formulas are clear enough to figure this out. The problem is the magnitude. The "Frequency Analysis" panel results show something like this: How do I get that peak value? I don't want to have to specify a hard-coded frequency band for this. The problem is that I don't see a function for that. I can call the fft() function in a way in which it returns a "Table" type. signal.fft ( bounds , period , units ) : Table Create a table of frequency magnitudes by analyzing the signal in the bounds. The table will have 2 columns, frequency and magnitude. Then I can use the top() function to return the top 1 row ordered by the greatest "magnitude" column: table.top ( limit , columnName , direction ) : Table However, I cannot for the life of me figure out how to get the "mangitude" value out of the first row returned in "Table" the above function and convert it into a sample at the ending point of the rolling 3 hour/5min period. Is this even possible. Is there a better way? // Getting a rolling 3 hour window every 5 minutes. \$periods = periods(3h, 5min) // for condition, get a signal with samples ending at each capsule representing: // key: end of 3hr window // value: peak magnitude of the fft of the \$waveSignal \$periods.transformToSamples( \$cap -> { // excute the expression for each capsule in condition. \$tbl = \$waveSignal.fft(\$cap, 1s, 's') // want the results in period lengths, not frequencies. // get the largest magnitude, filtering for the frequency/period length range of interest // get the first row of that table. \$r = \$tbl.filter('frequency'. isBetween(30s, 150s)) .top(1, 'magnitude', 'desc') .getFirstRow() // *******HOW DO I DO THIS???****** // convert that magnitude calculated to sample located at the end of this capsule. sample(\$cap.getEnd(), \$r.get('magnitude')) } ) Thanks in advance! Even better would be: getting the sum of the values in the peakFrequency +-/ 2s window.
4. 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.
5. Hello, I am trying to create a polynomial formula using the formula tool but I get the following error message "t is not compatible with t² at" with 'add' or 'subtract' after. Same with t² and t³. How can I create such formula? Example: 2 * \$a^3 + 5 * \$a^2 - 8 * \$a + 200
6. Hi, Is it possible to calculate the duration of valve opening (from time when change from "close" to "not close" to time when change from "not close" to "close") I've tried to do this by derivative function, but the values are string type. For the period of time, e.g. a year need to receive the number of the scalar values of these periods and then perform some calculations with formula with each of that scalar value.
7. Hey there, My question splits into two parts: Firstly, I want to create a condition based on multiple criteria: if signal A equal to 3, B equal to 4, C is greater than 5 than condition is valid. I know i could create 3 individual capsule and overlap them. Is there a simple way to use formula to do so? Secondly, in my analysis i have 10 signals and associated conditions(alert), then I want to know in the past 7 days how many alert in total(repeated instance or capsule doesnt count) ? and How long is the total alert time? Thank you
8. Background: When looking to identify trends or step changes in a signal, we typically recommend an approach of smoothing the signal, taking the first derivative, then identifying when that derivative is positive or negative. This method works well most of the time, but employing this technique in combination with others can be more effective at capturing trends/step changes when the value change in the signal is more subtle. Solution: When looking for step changes, we can use a technique of calculating a range of the signal on a rolling periodic basis and search for when the range exceeds some limit. We can then combine this condition with when the derivative is positive (increasing step changes) or negative (decreasing step changes) to capture our final condition. 1. Create a rolling window over which you will look at the range (max-min value) of the signal. In my example I used a 4h window every 30 minutes, because my tank draining events were typically never longer than 4h. Select the smallest time period that you can that is still longer than your longest draining event. 2. Use Signal from Condition to calculate the range (max-min) of your signal over each of the rolling windows. Make sure to place the time stamp of the statistic at the end of each rolling capsule. 3. Identify time periods when that range calculation is above some threshold. In this example we used a threshold of 2 based looking at the trend output of our step 2. If we zoom in on a smaller range of time, we see that our capsules for when the range value is high actually extend beyond the completion of our decreasing signal. 4. We can intersect this condition that we have identified for high range in the signal with a condition for when the derivative of the signal is negative to capture our desired events. First calculate the first derivative of the signal. We apply a smoothing agileFilter in this step as well to remove signal noise. 5. Identify when that derivative value is less than zero using the value search tool. 6. Now take the intersection of the condition for negative derivative of the level and the condition for high range. The final view of the original signal and the events identified: Use chain view to validate your calculations:
9. Seeq is often used to contextualize data with respect to production runs. These product runs may be a text or string signal that is the product code, or a very large numerical signal. Users commonly use Value Search to find a specific product run to further analyze. If they want to work with a couple of similar product runs, for example ones that start with or end with the same few letters or numbers, a few Value Searches followed by Composite Condition may be acceptable. This approach may not be realistic if there are hundreds of different product codes to analyze. Recently a user asked for a trim function because they wanted to categorize all product codes by the first few letters the product code. For example, ABC-123-XYZ and ABC-456-DEF would both fall under the "ABC" product category. In Excel, users might use something like the functions LEFT and RIGHT to return the first few characters (LEFT(3) in this ABC example). One way to do this text or string manipulation in Seeq is to use the replace() function with a regular expression. Regular expressions can be intimidating to those who have not used them before, but they can also be very powerful. A little exploration on sites like https://regex101.com can help evaluate what kind of regular expression is appropriate for a specific use case. Given the above example product codes, the below Seeq Formula incorporates a regular expression within the replace() function to parse the string signal by the "-" and then return only the first part of that parsed string based on the "\$1". \$productcode.replace('/(.*)-(.*)-(.*)/', '\$1') I could similarly categorize by the last three characters with a function like \$productcode.replace('/(.*)-(.*)-(.*)/', '\$3') Once this simplified text signal is available, any other tools can be used in the analysis. If the product code was a very large number instead of a string, apply toString() to benefit from the replace() function. There are often many ways to solve a problem. An alternate approach to categorize product codes like this might be to pair toCapsules() and filter() off the Value property in Formula. Perhaps the best solution is incorporating regular expressions into Value Search like in the example below to create conditions any time the product code starts with ABC (/^ABC.*/) or any time it ends with XYZ (/.*XYZ\$/). The slashes here indicate regular expressions should be used, similar to searching with regex in the Data Pane. But this approach is likely not obvious or easy without a little experience with regular expressions. So while regular expressions may feel foreign at first, do not be intimidated! They really can pay off in the long run.
10. FAQ: How do I put a pump curve in Seeq? As of R21.0.44.00 this can be done the with the scatter-plot tool. This method does require version R21.0.44.00 or newer to work. See the steps below for details. Determine the X&Y components of the curve. This can be done with a tool such as https://apps.automeris.io/wpd/. Enter or paste the components in columns A and B in the CurveFitter excel sheet. See screenshot below for details. The CurveFitter file can be found here. CurveFitter.zip Once the new Flow and Head data has been pasted into excel copy the contents in from D2 to E9 and paste them into the Seeq formula tool. See screenshots below for copy paste details Copy: Paste: Paste the following syntax in the same formula under the coefficients. Be sure that the flow signal has the variable name “\$flow”. \$f=\$flow.remove(\$flow.isNotBetween(\$lower,\$upper)).setunits('') \$coeff4*\$f^4+\$coeff3*\$f^3+\$coeff2*\$f^2+\$coeff1*\$f+\$const Final formula view: Add the line to the Scatterplot by selecting the f(x) in the Scatterplot tool bar and pick the correct item from the select item dropdown. If adding more than one curve, then click on the item properties “i” of the first curve and click on duplicate. Once in the formula tool copy the new coefficients from excel replacing the old one and hit execute. Follow step 5 to add the curve to the plot. Final View:
11. FAQ: I've created a condition for a particular event of interest and now I would like to create a signal that is the running count of these events in a given time period. This analysis is common in equipment fatigue use cases when equipment degrades slowly based on a number of cycles (thermal, pressure, tension, etc) that it has undergone during it's life or since a last component replacement. Solution: We can convert each of these capsules into a signal comprised of a single sample (with value of 1) per capsule, then take a running sum of this new signal over the current equipment life condition. 1) Use Formula to create a signal with a constant value of 1 and a sample every 1 second. (1).toSignal(1sec) 2) Use Signal from Condition to create a new signal with a single sample of value 1 per capsule. Take the average of the "1 signal" during each of the event capsules. 3) Use Formula to calculate the running sum of the 1 sample per capsule signal during the Current Equipment Life capsule. \$OneSamplePerCapsule.runningSum(\$CurrentLife).toLinear(7d)
12. I have a piece of equipment that regularly goes through cycles and I want to compare the cycles. In this case I know the exact date and time of the equipment runs so I have used the Custom Condition tool to specify my Previous Run and Current Run. Custom Condition allows you to enter dates for the condition you are interested in. This can also be done in formula. To create the condition for my Next Run I used Seeq's formula because this run is currently on going and I do not know the end date. This approach allows me to specify that this condition end at now. condition(2d, capsule('2020-06-01T17:48Z', now())) Now that I have defined my Previous, Current and Next runs I want to calculate the run time of each of those periods. I can do this in Seeq's formula tool using the time since function. This will allow me to create a signal whose value is the time since the start time of a condition. This signal will end at the end of the condition. In this case my time counter will be in hours, if you wanted it in days instead you would change the 1h to 1d. timeSince(\$condition, 1h) I duplicated this formula three times for my previous, current and next runs. Remember, you can always duplicate a formula by clicking the "i" by item properties. You can compare the run lengths of the 3 runs by putting them on the same lane and same axis. You'll noticed my Next Run has just started so the time since for it is much smaller. Lastly, you can switch to capsule time view to compare the run length as well as different signals over the run. In this case we are looking at the temperature of each run as well as the run length. You could imagine using this approach to monitor heat transfer coefficients, reactor temperature, reactor conversion, or % sulfur removed.
• 1
• 13. Question: How do I normalize a signal in Seeq? Sometimes it can be helpful to view data on a normalized scale or used normalized inputs in a model. Solution: This solution is posted using R22.0.47 but is applicable to earlier versions. Slight modifications of the formula may be required for earlier versions. 1. Let's start by loading our signal... 2. Next we'll use Formula to create a normalized signal. In Formula we do the following steps Define the time period over which we will do the normalization Calculate the min and max values which occur during that time period Calculate the delta between the min and max Finally, calculate the normalized signal Here is the code snippet if you'd like to copy and paste... \$timePeriod = capsule('2019-01-01T00:00-05:00', '2020-01-01T00:00-05:00') \$max = \$signal.maxValue(\$timePeriod) \$min = \$signal.minValue(\$timePeriod) \$delta = \$max - \$min (\$signal - \$min) / \$delta 3. View the results in Seeq. Note that I optionally created scalar boundaries at 0 and 1 to highlight the normalization of my signal...
• 1
• 14. Hello Everyone, I hope you are doing well. I need some help with creating a function. I have multiple conditions that I have created that tell me if the equipment is stopped, lag, standby, or other attributes. I want to be able to be able to: ADD Durations for when equipment is stopped and in lag OR when the equipment is stopped or standby. ADD Durations for when equipment is stopped but not in lag or standby. The example variables are in hours. Stopped (\$i5) Standby(\$i6) Lag (\$i) I would appreciate the help.
15. Recently an interesting question came up about converting a number to binary within Seeq. The goal was to convert an integer (0-255) to an 8-bit binary number. This can be done by dividing the integer by 2, 8 times and keeping track of the remainders. More information about binary numbers can be found here. https://en.wikipedia.org/wiki/Binary_number Note: For this conversion to work the input signal needs to be an integer between 0 and 255, also it cannot have units. Below is the formula syntax that will do the conversion. \$i=\$signal.ceiling().setUnits('') \$div1=(\$i/2).floor() \$div2=(\$div1/2).floor() \$div3=(\$div2/2).floor() \$div4=(\$div3/2).floor() \$div5=(\$div4/2).floor() \$div6=(\$div5/2).floor() \$div7=(\$div6/2).floor() \$div8=(\$div7/2).floor() \$rem1=(\$i/2-\$div1).ceiling().toString() \$rem2=(\$div1/2-\$div2).ceiling().toString() \$rem3=(\$div2/2-\$div3).ceiling().toString() \$rem4=(\$div3/2-\$div4).ceiling().toString() \$rem5=(\$div4/2-\$div5).ceiling().toString() \$rem6=(\$div5/2-\$div6).ceiling().toString() \$rem7=(\$div6/2-\$div7).ceiling().toString() \$rem8=(\$div7/2-\$div8).ceiling().toString() \$rem8+\$rem7+\$rem6+\$rem5+\$rem4+\$rem3+\$rem2+\$rem1 Below is a screenshot of the syntax in the formula tool. Result:
• 2
• • 16. As of Seeq R21.044 we have a couple interesting new ways to compare signals in formula! When creating a value based condition, the usual default is the value search tool, but it has always been possible using formula as well, however these functions have typically been limited to signal against scalar comparisons. As of R21.044 however, common math operators like <, <=, >, >=, == (is equal to), != (is not equal to), and && (logical and) are all available for use as signal against scalar, or signal against signal comparisons! Whenever the mathematical condition is met, a condition will be created just like a typical value search, however unlike value search the mathematical operators in formula will also work with two signals. For more information, search for "Comparison Functions for Signals" in your formula documentation. Here are a few examples of these operators in use: Signal and scalar comparison: Signal and scalar comparison with logical and: Signal against Signal: For a full list of whats new in R21.044 check out this KB article: https://seeq12.atlassian.net/wiki/spaces/KB/pages/571375775/What+s+New+in+R21.0.44
17. In many industries (pharmaceuticals, food and beverage, etc.), mean kinetic temperature (MKT) is used to measure the temperature fluctuations of a material during storage and shipment. Mean Kinetic Temperature is a non-linear weighted average temperature that is set up to provide an impact on product stability. In general, product stability follows an exponential trend with temperature as it is inherently a decomposition reaction of the desired product. Therefore, the mean kinetic temperature takes into account the exponential reaction rate to determine the average temperature weighted by the kinetics of the reaction over time. The formula for mean kinetic temperature is: Where: is the mean kinetic temperature in Kelvin is the activation energy (in kJ mol−1) is the gas constant (in J mol−1 K−1) to are the temperatures at each of the sample points in kelvins to are time intervals at each of the sample points This formula can be inserted into Seeq through a couple of steps: 1. Calculate the time intervals for each of the data points (tn). In many cases these are evenly spaced and the formula simplifies, but in case they are not, this can be calculated in Seeq Formula by creating capsules for each data point and then aggregating the duration of those capsules: \$temp.tocapsules().aggregate(totalduration(),\$temp.tocapsules(),startkey()).tostep() 2. Calculate the exponential relationship for each sample point (t*exp(-deltaH/RTn)) using Seeq Formula. For this example, delta H was set to 83.14 kJ/mol: \$H = 83.14kJ/mol \$TimeInterval*CONSTANT.E^(-\$H/CONSTANT.R/\$temp) 3. At this point, the desired time period to perform the MKT calculation over must be selected. This can be done by creating a capsule with the Custom Condition tool. The desired time period can be as long or short as desired. 4. The next step is to sum the numerator and denominator of the natural log portion of the MKT calculation. These summations across the time period signified in step 3 can be performed with the Signal from Condition tool by selecting the sum statistic, the time period from step 3, and the aggregation at the middle timestamp of the condition. This step should be performed for both calculated signals from steps 1 (time intervals for denominator) and 2 (exponential rates for numerator). 5. Finally, the MKT calculation can be calculated with Seeq Formula: \$H = 83.14kJ/mol ((\$H/CONSTANT.R)/(-ln(\$TotalizedNumerator/\$TotalizedDenominator))) .convertUnits('K') As an example, below is a graph showing this calculation being done over multiple time periods of interest (green capsules at top):
18. FAQ: I would like to capture the value of a signal at the exact center of each capsule within a condition. Is there a way to do this with Seeq? Solution: 1. Begin with your signal and the condition over which you want the middle value in the display pane. 2. Open a new formula window and use the getMiddles() function to create a zero length capsule at the center of each capsule within your condition of interest. \$myCondition.getMiddles() Note, depending on which tool what used to create the red condition shown in your screenshot, you may need to add a max capsule duration during this step as well. If you receive an error saying that the condition needs a maximum duration, try instead: \$myCondition.removelongerthan(1d).getMiddles() the 1d in the removelongerthan() function above applies a max capsule duration of 1d to \$mycondition. Ensure your max capsule duration is longer than the longest capsule in your condition. 3. Now you can use the Signal from Condition tool to calculate the value of your signal during each capsule of your "middle of each capsule" condition. Note: The statistic you select is not important here because the capsule is infinitesimally small so Average, Median, Value at End, etc will return the same value. The final result in chain view:
19. Is it possible to create an inverse or NOT capsule? For example, I have capsules that mark equipment failures, I would like a capsule that is the inverse of failure, not failed. The reason I would like to do this is so I can aggregate run hours between failures. Thanks for any pointers! Regards, Ivan
20. FAQ: For reporting purposes, I want to calculate statistics based on the current period to date and display that next to the periods immediately preceding it. This is easy to do using the custom date range tool in Organizer Topic (Creating a Periodic Condition and the grabbing the capsule closest to or offset by 1 from the end). Is there a way to create these same date ranges relevant to the current time in Seeq Workbench? Solution: We can create identical conditions in Seeq Workbench by following the methods below. The first method defines how to create conditions for current and previous conditions for years, days, weeks, shifts. The second method includes an extra step that is necessary for current and previous months and quarters since the exact duration of these periods can vary based on the number of days each month. Method 1 - when the length of time in each period is definitive (e.g. year, week, day, shift). This example shows how to create conditions for "Current Week" and "Previous Week" 1. Create a Periodic Condition for "Weekly" using the Periodic Condition tool. 2. Create a Condition around the current time ("Now") using Formula --> condition(1min, capsule(now() - 1min, now())) 3. Use the Composite Condition tool to create a condition for "Current Week" when the Periodic Condition "Weekly" touches the tiny capsule at "Now". 4. Use Formula to create a condition for the "Previous Week" --> \$currentWeek.beforeStart(7d) Method 2 - when the length of time in each period is variable (e.g. month, quarter). This example creates a condition for "Current Month" and "Previous Month" 1. Create a Periodic Condition for "Monthly" using the Periodic Condition tool. 2. Create a Condition around the current time ("Now") using Formula --> condition(1min, capsule(now() - 1min, now())) 3. Use the Composite Condition tool to create a condition for "Current Month" when the Periodic Condition "Monthly" touches the tiny capsule at "Now". 4. Use Formula to create a Condition for the last day of the last period (in this case "Last Day of the Last Month") \$currentMonth.beforeStart(1d) 5. Use the Composite Condition tool to create a condition for the "Previous Month" when the Periodic Condition "Monthly" touches the "Last Day of Last Month".
21. Use Case: Users are often interested in identifying when a particular process is operating in a specific mode, or when it is in transition between modes. When looking at these transition periods, you may want to know what the modes of operation were immediately before and after the transition. If you can assign the starting and ending modes during a transition period to each transition capsule, you can filter for specific types of transitions and get a better idea of what to expect during like transitions. Solution: For Versions R.21.0.43 + 1. Add a signal to your display that describes the mode of operation you are interested in. In this example I have added the Example Data > Cooling Tower 1 > Area A > Compressor Stage string signal. Other signals that this use case applies to may include: production grade code, equipment operating mode, signal for step in a sequential or batch process. 2. Next we can use Formula to create a new condition comprised of capsules each time our Compressor Stage signal changes value. These capsules will contain a new capsule property called 'StartModeEndMode' that represents the value of the compressor stage immediately before and immediately after the signal changed value, or transitioned. The formula syntax to achieve this is: //creates a condition for 1 minute of time encompassing 30 seconds on either side of a transition \$Transition = \$CompressorStage.toCondition().beforeStart(0.5min).afterStart(1min) //Assigns the mode on both sides of the step change to a concatenated string that is a property of the capsule. \$Transition .transform( \$cap -> \$cap.setProperty('StartModeEndMode', \$CompressorStage.toCondition() .toGroup(\$cap, CAPSULEBOUNDARY.INTERSECT) .reduce("", (\$seq, \$stepCap) -> \$seq + \$stepCap.getProperty('Value') //Changes the format of the stage names for more clear de-lineation as a property in the capsules pane. .replace('STAGE 1','-STAGE1-').replace('STAGE 2','-STAGE2-').replace('TRANSITION','-TRANSITION-').replace('OFF','-OFF-') ))) and the Output is: Note that we added the new property 'StartModeEndMode' to the Capsules Pane. 3. We can now filter this condition to look for specific transitions of interest. In this example, we are interested in every time our compressor went from a TRANSITION state to STAGE2. Use Formula and the filter() function with the following syntax to achieve this. //Create a new condition comprised only of capsules where the 'StartModeEndMode' property is equal to '-TRANSITION--STAGE2-' \$ConditionCreatedInStep2.filter( \$capsule -> \$capsule.getProperty('StartModeEndMode').isEqualTo('-TRANSITION--STAGE2-')) and the Output is: 4. Now we are able to add other signals of interest to the display and switch to Capsule Time view to observe how those signals behave during these similar transition events.
23. Starting with Seeq R.21.0.44.0 release, user can specify maxValue() and maxKey() on a signal during a capsule to return the scalar values of maximum value and associated time stamp respectively. The example below shows that on Temperature signal, during 16th October (capsule), maxValue() function results in 106.07 ºF and maxKey() function results in associated timestamp 2019-10-16 02:18 am i.e. when maximum temperature occurred. See the 1st image for this example in Seeq: Feel free to try out these formulas on your own: \$temperature.maxKey(capsule('2019-10-16T00:00Z','2019-10-17T00:00Z')) \$temperature.maxValue(capsule('2019-10-16T00:00Z','2019-10-17T00:00Z')) Oh one more thing, you can also create signals that return one value from each capsule within a condition. Where value can be maxValue(), minValue(), maxKey(), minKey(). Below is one such example and an image showing that you can create signal that represents minimum values at minimum key (time) on daily basis: \$signal.aggregate(minValue(), \$condition, minKey()) As always detailed information can be found in formula tool panel documentation search box in Seeq application. Still want more Seeq info? Check out what else is new in R21.0.44.00: https://seeq12.atlassian.net/wiki/spaces/KB/pages/571375775/What+s+New+in+R21.0.44
24. Tangential Flow Filtration Resistance in Seeq Many pharmaceutical and beverage processes involve a filtration process where a common type of filtration is tangential flow filtration. In biopharmaceutical processing, this is commonly found in a perfusion bioreactor and in the ultrafiltration/diafiltration (UF/DF) concentrating step. Beverage processes also typically involve a UF/DF type process to remove potential contaminants or further refine the concentration of the desired beverage. A typical tangential flow filtration set up looks like the picture below where you have an inlet stream and two outlet streams: the retentate, which did not pass through the filter and is returned to bulk inlet, and the permeate, which is typically the product stream that has been filtered. The goal of the process is to concentrate the product while removing large contaminants that may be present by filtering them out. During the filtration process, particles can build up on the filter membrane, causing additional resistance that reduces the effectiveness of the filter and slows down the filtration process. Therefore, it is imperative to effectively clean and sanitize the filter membrane between each batch and to monitor the membrane resistance over time to determine whether the unit operation is still effective. One method for monitoring this is through filter resistance calculations. In order to calculate the filter resistance, the following signals are required: · Feed Inlet Pressure · Retentate Pressure · Permeate Pressure · Permeate Flow Rate If the permeate flow rate is not present, it can be calculated, by way of the Conservation of Mass using the feed and retentate flow rates, in Seeq through the Formula tool: \$FeedFlowRate = \$RetentateFlowRate + \$PermeateFlowRate The first step in solving for the resistance is to calculate a variable called the Transmembrane Pressure (TMP). This is an average pressure differential, or driving force, across the filter and can be calculated by the following formula in Seeq: (\$FeedInletPressure + \$RetentatePressure) / 2 - \$PermeatePressure Membrane flux (J) is the amount of permeate per unit area of the filter. This can be calculated in Seeq Formula as well: \$PermeateFlowRate / MembraneArea where MembraneArea is a value input by the user. Membrane flux (J) and TMP are related by the Darcy Equation, which is: J = TMP / (μ * R) Therefore, this equation can be rearranged to calculate the resistance (R), which includes both the inherent membrane resistance and the added resistance due to fouling. The resistance can be calculated in Seeq Formula: \$TMP / (\$MembraneFlux * Viscosity) where Viscosity is a value input by the user. If the viscosity value is unknown, the value can simply be removed from the equation to be grouped with resistance since it is a constant and will not impact the analysis of monitoring the change in resistance over time. This resistance value should be evaluated over time or multiple batches to determine whether there is any fouling occurring or inadequate cleaning or sanitization between batches. It is recommended to use the Boundaries tool in Seeq to set limits based on historical data sets. Lower membrane resistance than historical values may represent breakthrough in the filter due to quality defects in the filter membrane. Higher membrane resistance may represent fouling of the membrane over time and result in a loss of yield if additional filtration time is not included. This higher membrane resistance may signify that additional cleaning or membrane replacement is required. These deviations from the expected resistance values can be flagged using the Deviation Search tool within Seeq.
• 1
• 25. 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:
×