Jump to content
  • To Search the Seeq Knowledgebase:

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

Search the Community

Showing results for tags 'spc'.

  • 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

Found 2 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. Statistical Process Control (SPC) can give production teams a uniform way to view and interpret data to improve processes and identify and prevent production issues. Control charts and run rule conditions can be created in Seeq to monitor near-real time data and flag when the data indicates abnormal or out of control behavior. Creating a Control Chart 1. Find the signal of interest and a signal that can be used to detect the current production grade (ideally a grade code or similar signal - if this does not exist for your product, you can use process set points to stitch together a calculated grade signal). Use .tocondition() in formula to create a condition for each change in the Grade_Code signal. 2. Check data for normalcy and other statistical assumptions prior to proceeding. To check for normalcy, use the Histogram tool in Seeq. Find more information on the Histogram tool in the Seeq Knowledge Base. Note that for this analysis we are using a subgroup size of one and assuming normalcy. 3. Determine the methodology to use to create the average and standard deviation for each grade. In this case, we will identify periods after start-up when the process was in control using Manual Condition, and select these times across each grade. 4. Calculate the mean and standard deviation for each grade, based on the times the process was in-control. Choose a time window that captures all capsules created for the in-control period. To use an unweighted mean, use .toDiscrete() before calculating average. The same calculation for the mean can be used for the standard deviation, by replacing average() with stddev(). //Define the time period that contains all in control capsules $capsule = capsule('2020-10-16T00:00-00:00', '2021-09-21T00:00-00:00') //Narrow down data to when process is in control, use keep() to filter the condition by the specific grade code capsule property $g101 = $allgrades.keep('Grade Code',isMatch('Grade 101')).intersect($inControl) $g102 = $allgrades.keep('Grade Code',isMatch('Grade 102')).intersect($inControl) $g103 = $allgrades.keep('Grade Code',isMatch('Grade 103')).intersect($inControl) //Create average based on the times the product is in control, use .toDiscrete to create an unweighted average $g101_ave = $viscosity.remove(not $g101).toDiscrete().average($capsule) $g102_ave = $viscosity.remove(not $g102).toDiscrete().average($capsule) $g103_ave = $viscosity.remove(not $g103).toDiscrete().average($capsule) //Create average for all grades in one signal using splice(), use keep() to filter the condition by the specific grade code capsule property //use within() to show only average only during the condition 0.splice($g101_ave, $allgrades.keep('Grade Code',isMatch('Grade 101'))) .splice($g102_ave, $allgrades.keep('Grade Code',isMatch('Grade 102'))) .splice($g103_ave, $allgrades.keep('Grade Code',isMatch('Grade 103'))) .within($allgrades) 5. Use the mean and standard deviation to create +/- 1 sigma limits, +/-2 sigma limits, and +/-3sigma limits (sometimes called upper and lower control limits). Here is an example of creating the +2 sigma limit: //Add 2*standard deviation to the mean to create the $plus2sd limit, use within() to show limits only during the time periods of interest ($mean + (2*$standardDeviation)).within($grade_code) 6. Overlay the standard deviation limits and mean with the signal of interest by placing on one lane and one y-axis, remove standard deviation. Creating Run Rules Once the control chart is created, run rule conditions can be created to detect instability and the presence of assignable cause in the process. In this example, Western Electric Run Rules are used, but other run rules can be applied using similar principles. Western Electric Run Rules: Run Rule 1: Any single data point falls outside the 3sigma-limit from the centerline. Run Rule 2: Two out of three consecutive points fall beyond the 2sigma-limit, on the same side of the centerline. Run Rule 3: Four out of five consecutive points fall beyond the 1sigma-limit, on the same side of the centerline. Run Rule 4: NINE consecutive points fall on the same side of the centerline. 7. The following formulas can be used to create a condition for each run rule: Run Rule 1: //convert to a step signal $signalStep = $signal.toStep() //find when one data point goes outside the plus3sigma or minus 3sigma limits ($signalStep < $minus3sd or $signalStep > $plus3sd) //set the property on the condition .setProperty('Run Rule', 'Run Rule 1') Run Rule 2: *Note that the function toCapsulesByCount() is available in Seeq versions R54+ //Create step-interpolated signal to keep from capturing the linear interpolation between sample points $signalStep = $signal.toStep() //create capsules for every 3 samples ($toCapsulesbyCount) and for every sample ($toCapsules) $toCapsulesbyCount = $signalStep.toCapsulesByCount(3,3*$maxinterp) //set the maximum interpolation based on the longest time you would expect between samples $toCapsules = $signalStep.toCapsules() //Create condition for when the signal is not between +/-2 sigma limits //separate upper and lower to capture when the rule violations occur on the same side of the centerline $condLess = ($signalStep <= $minus2sd) $condGreater = ($signalStep >= $plus2sd) //within 3 data points ($toCapsulesByCount), count how many sample points are not between +/-2 sigma limits $countLess = $signal.todiscrete().remove(not $condLess).aggregate(count(),$toCapsulesbyCount,durationKey()) $countGreater = $signal.todiscrete() .remove(not $condGreater).aggregate(count(),$toCapsulesbyCount,durationKey()) //Find when 2+ out of 3 are outside of +/-2 sigma limits //by setting the count as a property on $toCapsulesByCount and keeping only capsules greater than or equal to 2 $RR5below = $toCapsulesbyCount.setProperty('Run Rule 5 Violations', $countLess, endvalue()) .keep('Run Rule 5 Violations', isGreaterThanOrEqualto(2)) $RR5above = $toCapsulesbyCount.setProperty('Run Rule 5 Violations', $countGreater, endvalue()) .keep('Run Rule 5 Violations', isGreaterThanOrEqualto(2)) //Find every sample point capsule that touches a run rule violation capsule //Combine upper and lower into one condition and use merge to combine overlapping capsules and to remove properties $toCapsules.touches($RR5below or $RR5above).merge(true) .setProperty('Run Rule', 'Run Rule 2') Run Rule 3: *Note that the function toCapsulesByCount() is available in Seeq versions R54+ //Create step-interpolated signal to keep from capturing the linear interpolation between sample points $signalStep = $signal.toStep() //create capsules for every 5 samples ($toCapsulesbyCount) and for every sample ($toCapsules) $toCapsulesbyCount = $signalStep.toCapsulesByCount(5,5*$maxinterp) //set the maximum interpolation based on the longest time you would expect between samples $toCapsules = $signalStep.toCapsules() //Create condition for when the signal is not between +/-1 sigma limits //separate upper and lower to capture when the rule violations occur on the same side of the centerline $condLess = ($signalStep <= $minus1sd) $condGreater = ($signalStep >= $plus1sd) //within 5 data points ($toCapsulesByCount), count how many sample points ($toCapsules) are not between +/-1 sigma limits $countLess = $signal.toDiscrete().remove(not $condLess).aggregate(count(),$toCapsulesbyCount, durationkey()) $countGreater = $signal.toDiscrete() .remove(not $condGreater).aggregate(count(),$toCapsulesbyCount,durationkey()) //Find when 4+ out of 5 are outside of +/-1 sigma limits //by setting the count as a property on $toCapsulesByCount and keeping only capsules greater than or equal to 4 $RR6below = $toCapsulesbyCount.setProperty('Run Rule 6 Violations', $countLess, endvalue()) .keep('Run Rule 6 Violations', isGreaterThanOrEqualto(4)) $RR6above = $toCapsulesbyCount.setProperty('Run Rule 6 Violations', $countGreater, endvalue()) .keep('Run Rule 6 Violations', isGreaterThanOrEqualto(4)) //Find every sample point capsule ($toCapsules) that touches a run rule violation capsule //Combine upper and lower into one condition and use merge to combine overlapping capsules and to remove properties $toCapsules.touches($RR6below or $RR6above).merge(true) .setproperty('Run Rule', 'Run Rule 3') Run Rule 4: //Create step-interpolated signal to keep from capturing the linear interpolation between sample points $signalStep = $signal.toStep() //create capsules for every 9 samples ($toCapsulesbyCount) and for every sample ($toCapsules) $toCapsulesbyCount = $signalStep.toCapsulesByCount(9,9*$maxinterp) //set the maximum interpolation based on the longest time you would expect between samples $toCapsules = $signalStep.toCapsules() //Create condition for when the signal is either greater than or less than the mean //separate upper and lower to capture when the rule violations occur on the same side of the centerline $condLess = $signalStep.isLessThan($mean) $condGreater = $signalStep.isGreaterThan($mean) //Find when the last 9 samples are fuly within the greater than or less than the mean //use merge to combine overlapping capsules and remove properties $toCapsules.touches(combinewith($toCapsulesbyCount.inside($condLess), $toCapsulesbyCount.inside($condGreater))).merge(true) .setproperty('Run Rule', 'Run Rule 4') **To make it easier to use these run rules in Seeq, custom formula functions can be created for each run rule using the User Defined Formula Function Editor Add-on which can be found in Seeq’s Open Source Gallery along with user guides and instructions for installation. For example, Run Rule 2 can be simplified to the following formula using the User-Defined Formula Functions Add-on with Seeq Data Lab: $signal.WesternElectric_runRule2($minus2sd, $plus2sd) 9. If desired, all run rules can be combined into one condition in formula using .combinewith(): combineWith($runRule1,$runRule2,$runRule3, $runRule4) 10. As a final step, a table can be created detailing the run rule violations in the trend view. Here, the header column is set as ‘Capsule Property’ >> ‘Run Rule’ and the capsule properties, start, end, and duration were added as columns. The last value of the signal ‘Grade_Code’ was also added as a column to the table. For more information on Tables, see the Seeq Knowledge Base.
×
×
  • Create New...