Jump to content
  • To Search the Seeq Knowledgebase:

    button_seeq-knowledgebase.png.ec0acc75c6f5b14c9e2e09a6e4fc8d12.png.4643472239090d47c54cbcd358bd485f.png

Search the Community

Showing results for tags 'formula'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Community Technical Forums
    • Tips & Tricks
    • General Seeq Discussions
    • Seeq Data Lab
    • Seeq Developer Club
    • Seeq Admin Forum
    • Feature Requests

Categories

  • Seeq FAQs
  • Online Manual
    • General Information

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Company


Title


Level of Seeq User

  1. Hi, I have a strange issue when aggregating data in a histogram. I am counting the number of samples for a signal and aggregate by first using "Year" and the using "Day of the Week" as the aggregation type: This gives me the following histogram with a count of 246 samples for monday in 2012: But these data should belong to sunday. I set up another histogram using the following condition as the second aggregation type: The result now looks like this (which is correct): This is for the other days as well. Is there any way to get around this issue? Installed Seeq version is R21.0.40.01-v201812312325 Regards, Thorsten
  2. Summary Chain View enables a nice visual of all the time periods stacked side-by-side; however, sometimes it is useful to create a new signal from all these capsules that has been scrunched together. This avoids the maximum limit of how many capsules can be shown in Chain View. Note this is different from "time warping" which realigns the samples by some amount. Signal scrunching keeps the relative sample alignment the same within each capsule - but it does move each "snippet" of the signal next to each other. Steps Here is a screenshot of all the signals and conditions needed for this analysis. Add signal to the display with the specified time range. Create the time periods, condition capsules, of interest. Using the Custom Condition tool, create a new capsule that surrounds all the capsules containing the data for the new signal. Note, the signal will start at the beginning of this capsule. Create Inverse of the time periods of interest that occurs within the 'Condition for New Signal'. This will be used to calculate the time lag between the capsules in the 'Condition for Time Periods of Interest'. $cftp.inverse().removeLongerThan(1wk).intersect($cfns) Create the signal snippets that occur only within the 'Condition for Time Periods of Interest' and the 'Condition for New Signal'. $t.within($cftp.intersect($cfns)) Create a new signal to calculate the delay between each of the 'Condition for Time Periods of Interest' capsules. 1.toSignal().aggregate(totalized(), $icfc, startKey()).convertUnits('h').toStep() Create a running sum of the delay - this will be used to shift all the snippets to the beginning of the 'Condition for New Signal' capsule. $dbtp.runningSum($cfns) Scrunch the signal. $ts.delay(0-$rsod, 1wk)
  3. I've got a signal with drop-outs and I want to filter my signal to only visualize samples with values above a threshold. Is there a quick way to do this in Seeq?
  4. We often do calculations where we are interested in having one result if one condition is true and a second result if another condition is true. In this post we will discuss how to do this calculation in Seeq. We will create a new single signal which runs different calculations during different periods of time. This technique can be used to replicate "if" logic or "if / else" logic currently being used in excel. Example existing code from excel or other systems IF Temperature > 90 then show a result of (Temperature * 100) IF Temperature < 90F then show a result of (Temperature + 10) Step 1: Identify two modes of operation In the Tools tab identify the following conditions using the Value Search tool: Step 2: Use formula to reconstruct "if/then statement" using Seeq's Splice Tool Local Variables: Name Item Type $Temperature Temperature Signal $HighTempCondition Greater than 90 Condition Seeq Formula: $HighTempCalc = $Temperature * 100 $LowTempCalc = $Temperature + 10 $LowTempCalc.splice($HighTempCalc,$HighTempCondition) Section 1 - $HighTempCalc This is a local variable which is to be run during periods of high temperature Section 2 - $LowTempCalc This is a local variable which is to be run when NOT in periods of high temperature Final - $LowTempCalc.splice($HighTempCalc,$HighTempCondition) Combine your two series. Use the LowTempCalc series, unless you are in the High Temperature condition, in which case use the HighTempCalc Content Verified DEC2023
  5. Use Case: It is common in industry to seek to use the behavior of upstream process variables to predict what the behavior of a downstream variable might be minutes, hours or days from the present time. Solution: A traditional predictive modeling workflow can be applied to solve this problem. Identify an appropriate training data set Perform any necessary data cleansing Create a predictive model Evaluate the model fit Improve the model Operationalize the model What differentiates this use case from any other predictive modeling use case is a specific data cleansing step for adjusting signals to remove process lag. 1. Load Data Load your target signal and the relevant upstream signals into the display pane. In this example, the target signal is the product viscosity, measured in an analytical lab based off a sample from a downstream sample point. Three upstream signals: the reactor temperature, reactant conversion, and viscosity modifier flow to the reactor significantly influence the product viscosity measurement and will be used as inputs into the model signal. 2. Identify Training Data Set Identify an appropriate training data set for your regression model. This may involve a longer time window to include variability in product type or seasonality. In this example, we will pan out to 3 months to capture multiple cycles of different product types. With an appropriate training window identified, you can also limit your training data set to a subset of samples present during a particular condition. If this interests you, consult the "advanced options" section of the Prediction Tool KB article for more information. This method is particularly useful if you're wishing to create different models for different modes of operation. 3. Cleanse Signals -- Adjust for Process Lag We can time-shift our upstream signals using either a known constant delay, a known variable delay (like a calculated residence time signal), or an unknown delay of maximum correlation to the target signal. The first two of these options will utilize the .move() function in Formula (or .delay() in earlier versions of Seeq). The latter will utilize the .correlationOffset() function. In this example, we have a known lag of 1.5 hours between the reactor and the product sampling point. We will use the move function with an input scalar of 1.5h, as shown below. The time shift calculation should be applied across all relevant input signals. More information on the different options for time shifting signals using fixed, variable, or calculated offsets is available in this forum post: 4. Cleanse Signals -- Remove signal noise, outliers, abnormal operating data In this example, we apply an agileFilter to each of our time-shifted model input signals. Apply the same technique to each of the model inputs. Note that steps 3 & 4 could have been combined into a single formula. An example of this would be: $reactor_temp.move(1.5h).agileFilter(1min) For guidance on additional cleansing techniques, consult the Interactive Training. 5. Build the Predictive Model Use the Prediction tool panel to create a model of your target signal based on your cleansed, time-adjusted input signals. Ensure your model training window matches the date range that you identified in step 2. You can view the model parameters like coefficients, rSquared, and p-values using the "+ Prediction Model" option. 6. Evaluate the Model Fit Use Scatter Plot view and the model parameters to evaluate the goodness of fit of the model. Switch to a time range outside of your training data set to ensure your model is a good fit for data throughout time. 7. Improve Model (as needed) If the scatter plot indicates a non-linear relationship, test out additional model scales in the prediction tool panel. Consider eliminating variables with p-values higher than your significance level cutoff (frequently 0.05). Add additional variables if relevant. If distinct modes of operation introduce significant signal variability, consider creating a model for each operating mode and stitch the models together into a single model using the splice() function in Formula. 8. Deploy the Model The model should project out into the future by the amount of the process lag between the upstream and target signals.
  6. FAQ: I have a condition for events of variable duration. I would like to create a new condition that comprises the first third of the time (or 4th, or 10th) of the original condition. Solution: A stepwise approach can be taken to achieve this functionality. 1. Begin with your condition loaded in the display pane. 2. Create a new Signal using Signal from Condition that calculates the total duration of each of your event capsules, interpolated as a step signal. 3. Create a new signal that is your total event duration multiplied by the proportion of the event that you would like to capture. e.g. for the first 1/3 of the event, divide your total duration signal by 3, as shown below. 4. Create an arbitrary discrete signal with a sample at the start of each of your event capsules. 5. Shift the arbitrary discrete signal in time by the value of your signal calculated in step 3. In this example, the 1/3 duration signal. Note, depending on your version of Seeq, the function to do this may be called move() or delay(). 6. Use the toCapsules() function in Formula to create a tiny (zero duration) capsule at each of your shifted, discrete samples. 7. Join the start of your original condition with the capsules created in step 6 using the composite condition tool.
  7. FAQ: I have a CSV file that has the start and end times of some historical events and various information about the events that I would like to use in my analysis in Seeq. How do I go about getting these events and all of their associated information into Seeq? Solution: Use the Import from CSV tool and Seeq Formula to bring in a condition comprised of each of these events and assign the data in each column of the CSV as a property of the condition. 1. Ensure your CSV file is formatted correctly for import into Seeq. The first column should be the event start time, the second column should be the event end time, and all other data columns should be to the right of these. A list of acceptable timestamp formats can be found on the Seeq Knowledge Base in this article. 2. Use the Import CSV File tool to bring the condition into Seeq. Drag and drop your CSV file or navigate to your file through Windows (Mac) Explorer. Under "Import File as" select "condition". Choose the start-time and end-time columns in the "Choose columns" section. Specify a max capsule duration that is just longer than your longest event. 3. Once your condition is imported, use Seeq Formula to assign the data from the other columns of our CSV as properties of each capsule. Begin by using the item properties for the CSV imported condition to duplicate the condition to Formula. Once in Formula, add the column headers from your CSV to the query in line 1 of the code, separated by commas. Then use the setProperty() function to assign each of the columns of the CSV as a property of each capsule. Once executed, the output is a new condition that looks exactly like the original from trend view in the display pane. However, this new condition has properties, that can be added to the capsules pane using the gridded+ button.
  8. 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.
  9. 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.
  10. 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
  11. 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.
  12. 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
  13. 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:
  14. 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.
  15. As a Seeq user, you may have created a condition for a particular event of interest and would like to create a signal that is the running count of these events over 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. This use case can be done very efficiently in Seeq Formula. The assumptions for the below solution are: You have a condition ($condition) of interest that you would like to understand the running count for There is a defined timeframe of interest, where counting will start and end. Note the end date can be sometime in the future. For the below example, this condition is referenced as $manualCondition, but could very well be another condition that wasn't created via the Manual Condition tool. Just note that for each capsule in this condition, the count will restart at 0. Solution - Utilize the runningCount() formula function: 1) runningCount() currently only accepts signals as inputs, so convert your $condition to a signal by using .toSignal(), which produces a single sample for each capsule: $condition.toSignal(SAMPLE_PLACEMENT) SAMPLE_PLACEMENT should be specified as startKey(), middleKey(), or endKey(). If you want your count to increase at the start of each event, then use startKey(). If wanting the count to increase in the middle or end of each event, then use middleKey() or endKey() 2) Use the runningCount() function on the signal created above. $signal.runningCount($conditionToStartAndEndCounting) Both steps are shown below in a unified Formula: /* This portion yields a SINGLE point for each capsule. startKey() generates the point at the START of each capsule, where middleKey() and endKey() could also be used to generate a point at the MIDDLE or END of each capsule. Where these points are placed matter, as that is the point in time the count will increase. */ $samplePerCapsule = $condition.toSignal(startKey()) /* This portion yields the running count of each sample (capsule). The 15d in toStep() can be adjusted. Ideally this number will be the duration of the longest expected time between two events that are being counted. */ $samplePerCapsule.runningCount($manualCondition).toStep(15d) .toStep(15d) ensures the output signal is step interpolated, interpolating points at most 15 days apart. If step interpolation is not required, then this can be removed or replaced with something like .toLinear(15d). Below shows the associated output. Content Verified DEC2023
  16. 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.
  17. 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...
  18. 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.
  19. 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:
  20. 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
  21. 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
  22. Can I compare signals in Formula to create conditions rather than doing a Value Search?
  23. 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.
  24. 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 changes in the signal such as a delta or derivative with Value Searches have also been applied. Combine the periods where the derivative is positive and the flow is low to identify the transitions. Alternative methods using the Profile Search tool can also be 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: Content Verified DEC2023
  25. Scenario: I have created a regression or prediction model for my process but i want to apply that same regression model to another set of signals or a different period of time. This could be helpful for comparing how one piece of equipment is operating when compared against a regression built for another system. It could be used to predict how a system will behave based on how some other similar system behaved. It could be used predict how a system will behave before you have enough information to build that system or run its own model, or any number of applications where we might want to apply a regression or prediction model built on one set of signals to another set of signals. Solution: First off, we have to build a prediction model! In this case i have modeled a Filtration system, predicting filter head loss. I took into account the time the filter has been in service, the raw water turbidity, and the Filter turbidity. Next, if i click on the information icon for my prediction signal, i am able to see the formula that was used to create this prediction. We will need to copy this formula: Next, I need to identify my new signals. In my case, i am going to apply this prediction model to Filter 12. Once i have all of my signals that will be sued to the prediction i can paste my formula into a new formula and make sure all my variables line up (or, alternately and a bit easier, just use the duplicate to formula function from the information screen shown above by clicking on the down arrow next to the duplicate button). Finally, I need to update the PREDICT section of my formula denoted by the .predict() function with the signals i will apply my prediction model to. I can do this by using the search button in the formula tool to add my new signals, and then update the .predict() section of my formula with my new variables, make sure to put them in correctly and in the right order otherwise your model will be off! Finally, i can use my prediction model that i built for Filter 1 on Filter 12 and derive further insight, in this case i might question whether my systems are truly as similar as i think they are or whether there is something causing my model to deviate from what was expected for filter 12. In my case, both prediction models are in red:
×
×
  • Create New...