I am building a library of functions that I would like to distribute as a single JSL file. But some of my functions reference image files. In this blog post I will explain the process I use for serialising the image file so that it can be embedded directly into my JSL script.
Here is one of my functions:
Assert = function({condition,title,msg,doThrow=1}, {default local}, if (!condition, iconDir = FileLocationClass:getIconsDir; img = open( resources  "asserterror.png", png ); img << setSize({194,248}); NewWindow(title, <<Modal, BorderBox(top(0),bottom(30),left(20),right(20), VListBox( HListBox( SpacerBox(size(40,0)), PictureBox( img ) ), TextBox(msg) ) ) ); if (doThrow,throw()) ); );
Central to this discussion is the PNG image file called ‘asserterror’ that sits in my resources folder.
If I distribute this code as part of a JMP addin, then I can include the resources folder as part of the addin build. But I don’t want to do that. I just want a simple JSL file that other programmers can include into their projects.
My first step is to look at the img object that I am producing. So I create a utility script:
img = open( resources  "asserterror.png", png ); show(img);
JMP’s log window shows the result:
img = New Image(Char To Blob( "63Yyz... waJ", "base64compressed" ), "png");
The entire output is long so I’ve put “…” in rather than the full text which is about 50,000 characters in length!
Structurally:
img = newImage( charToBlob( strImg, "base64compressed" ), "png" );
And this is the code that I can use to embed my image. The string representation I get from my log window output of my utility script:
strImg = "63Yyz... waJ”; // the full 50k characters here img = newImage( charToBlob( strImg, "base64compressed" ), "png" );
And that’s it. Problem solved.
]]>
The new syntax of iteration is based on the for each function. The documentation for this function describes its use for iterating over elements of ‘containers’. A container is just an abstract name for something that contains a collection of items: most commonly lists, but also matrices and associative arrays.
Here is an example of the traditional use of a forloop in JSL:
lstAges = {12,13,14}; for (i=1,i<=nitems(lstAges),i++, age = lstAges[i]; show(age) );
Output:
age = 12 age = 13 age = 14
lstAges = {12,13,14}; for each( {age},lstAges, show(age) );
Output:
age = 12 age = 13 age = 14
dt = data table("Big Class"); heights = dt:height << get values; for each( {height},heights, show(height) );
In example 1.3 above the height measurements are in inches. Do people really still l use inches? Let’s convert to centimetres:
newHeights = {}; for (i=1,i<=nrows(heights),i++, newHeights[i] = 2.54 * heights[i] );
newHeights = transform each( {height},heights, height * 2.54 );
The iteration index is explicit in a forloop:
for (i=1,i<=nitems(lstAges),i++,
age = lstAges[i];
show(i,age)
);
Example 3.2 using the index keyword
for each({index},lstAges,
show(index)
);
Notice that this is the identical syntax for the use of ‘for each’. The only difference is the name of the element is ‘index’. Index is a keyword that indicates you want the index of the item and not the item value. If you want both, see the next example.
Example 3.3 using elementindex pairs
for each ({age,i}, lstAges,
show(age,i)
);
Example 4.1 working with associative arrays
For each can also be used to work with associative arrays:
lstAges = {12,13,14};
strAges = {"twelve","thirteen","fourteen"};
arr = Associative Array(lstAges,strAges);
for each ( { {key,value} }, arr,
show(key,value)
);
key = 12
value = "twelve"
key = 13
value = "thirteen"
key = 14
value = "fourteen"
Example 5.1 working with multiple lists
Sometimes we work with collections of lists to track multiple associated quantities. Here is an example:
lstParameters = {"Temperature","pH"};
lstLSL = {20,5.5};
lstTarget = {25,6.0};
lstUSL = {30,7.0};
for (i=1,i<=nitems(lstParameters),i++,
parameter = lstParameters[i];
lsl = lstLSL[i];
target = lstTarget[i];
usl = lstUSL[i];
);
Example 5.2 for each item in multiple lists
foreach({parameter,lsl,target,usl},across(lstParameters,lstLSL,lstTarget,lslUSL),
show({parameter,lsl,target,usl)
)
Example 5.3 misasligned lists
When referencing items across lists the presumption is that the lists are of equal length. Problems occur if that is not the case:
lstParameters = {"Temperature","pH","Humidity"};
lstLSL = {20,5.5};
lstTarget = {25,6.0};
lstUSL = {30,7.0};
for each({ {parameter,lsl,usl} },across(lstParameters,lstLSL,lstUSL),
show(parameter,lsl,usl)
)
Output:
parameter = "Temperature"
lsl = 20
usl = 30
parameter = "pH"
lsl = 5.5
usl = 7
parameter = "Humidity"
lsl = 20
usl = 30
Example 5.4 using the count option to resolve differences across containers
lstP = {"Temperature","pH","Humidity"};
lstLSL = {20,5.5};
lstTarget = {25,6.0};
lstUSL = {30,7.0};
for each({ {p,lsl,usl} },across(lstP,lstLSL,lstUSL,count("Shortest")),
show(p,lsl,usl)
)
Output:
p= "Temperature"
lsl = 20
usl = 30
p= "pH"
lsl = 5.5
usl = 7
Example 5.5 strict enforcement
try(
for each({ {p,lsl,usl} },
across(lstP,lstLSL,lstUSL,
count("Enforce Equal")),
show(p,lsl,usl)
)
,
show("oops")
);
]]>
http://www.pegaanalytics.co.uk/blog/iteration/feed/
0

Curve Fitting
http://www.pegaanalytics.co.uk/blog/curvefitting/
http://www.pegaanalytics.co.uk/blog/curvefitting/#comments
Wed, 13 May 2020 13:56:41 +0000
http://www.pegaanalytics.co.uk/blog/?p=2438
Continue reading Curve Fitting ]]>
The curve fitting platform allows you to select from a library of model types.
In this post I take a closer look at the different model types that are available to support curve fitting.
Each of the model categories contain a variety of models with differing numbers of parameters:
Polynomial Models
If you use linear regression (standard least squares) you will be familiar with this type of model:
. . .
Whilst gradient descent algorithms can be used to estimate these parameters, the primary role of curve fitting is to fit parameters that form part of a nonlinear equation – typically representing some mechanistic model relating to a scientific application. All other model types fall into this category of nonlinear models.
Sigmoid / Logistic Curves
The basic sigmoid function takes the following form:
It characterises the case where an unbounded x variable is transformed into a y variable that is contained within a range 0 to 1. It is therefore particularly useful for modelling a response that represents a proportion.
The logistic function introduces one or more parameters to generalise the behaviour of this Scurve. For example, a parameter can be introduced to control the growth rate:
The curve has a point of inflection at x=0. The introduction of a second parameter allows the location of this inflection point to be adjusted:
This is the formula for the Logistic 2P model.
Whilst y is a continuous response, these types of model are often used to model a binary outcome (0 or 1). In this case the y value is interpreted as the probability of an outcome of 1 given a specified value of x.
The Logistic 3P model introduces a third parameter allowing the curve to have an upper asymptote other than 1:
And the Logistic 4P model provides a description of both upper and lower asymptotes with parameters c and d:
There is also a Logistic 5P model that allows the curve to be asymmetric about the inflection point:
Sigmoid/Probit Curves
The logistic functions described earlier typically represent the case where the response is derived from the probability of a binary outcome. Alternatively, we can model the Scurve on the basis that it represents the cumulative distribution function Φ of a Normal distribution:
where the parameter a represents the growth rate and b is the point of inflection. This is the Probit 2P model.
The Probit 4P model introduces parameters to control the lower and upper asymptotes:
Sigmoid/Gompertz Curves
The 5parameter logistic model describes an Sshaped curve that is asymmetric about the inflection point. A Gompertz curve can be considered to be a special case of this model. As described in Wikipedia the model was first proposed as a description of human mortality.
A fourparameter model is also available that provides parameters for both lower and upper asymptotes.
Sigmoid/Weibull Growth Curve
Another Sshaped curve is the Weibull Growth model, often used in reliability engineering:
Where a is the upper asymptote, b is the growth rate, and c is the inflection point.
Exponential Growth and Decay
Exponential 2P is the basic exponential model:
The parameter b is a scaling parameter and λ represents the growth rate. If λ is negative, then it represents the rate of decay.
The Exponential 3P model adds an additive term to control the asymptote of the curve:
An alternative parameterisation is the mechanistic growth model:
JMP also supports biexponential models. These models are the sum of two exponentials and appear as 4parameter and 5parameter models:
Cell Growth
Growth of cells in a bioreactor can be characterised by a number of phases:
JMP’s Cell Growth 4P model takes the form:
where:
a = peak value if mortality rate is zero
b = response at time zero
c = cell division rate
d = cell mortality rate
Peak Models
The bellshaped curve associated with a Normal distribution is more generically described by a Gaussian function of the form:
The Lorentzian curve is superficially similar to the Gaussian bellshape, but has heavier tails:
Peak curves are used, for example, to model spectroscopic peaks.
For both models the parameter a corresponds to the maximum value of the peak; b represents the growth rate, and c is the critical point: the value of x where the curve reaches its maximum value.
Pharmacokinetic Models
Pharmocokinetic models seek to describe the kinetics of a drug once it has been administered into the body. The One Compartment Oral Dose model has the following parameterisation:
where:
a = area under the curve
b = elimination rate
c = absorption rate
JMP also supports a Two Compartment IV Bolus Dose model, but that is beyond my latex skills!
MichaelisMenten Model
Named after the biochemists Leonor Michaelis (18751949) and Maud Menten (18791960), this model is used to describe enzyme kinetics:
The parameter a represents the maximum reaction rate (in literature often referred to as V_{max}), and the b parameter (in literature often referred to as the Michaelis constant K_{m}) is the value of x such that the response is half V_{max} ; it is an inverse measure of the substrates affinity for the enzyme.
And There Is More
We are not limited to selecting from a predefined library of curve types. Any nonlinear function can be expressed as a column formula and fitted using the Nonlinear Platform. In fact it is one of my most frequently used platforms. But that is a topic for another day.
]]>
http://www.pegaanalytics.co.uk/blog/curvefitting/feed/
2

Working with String Variables
http://www.pegaanalytics.co.uk/blog/workingwithstringvariables/
http://www.pegaanalytics.co.uk/blog/workingwithstringvariables/#comments
Fri, 24 Apr 2020 10:43:35 +0000
http://www.pegaanalytics.co.uk/blog/?p=2473
Continue reading Working with String Variables ]]>
In this post I take a look at how JSL can be used to perform string manipulation.
Constructing a String Variable
A string variable is created by enclosing the text within doublequotes.
str = "this is a text string"
The script editor will automatically colour code string variables as purple (this behaviour can be customised under preferences).
Escape Sequences
What if the text string itself contains the doublequote character? In this instance the quote character needs to be preceded by a special escape notation that indicates that the character is part of the string and not the delimiter of the string:
str = "my name is "\!"David\!""
If a string requires a large number of doublequotes the use of escape sequences becomes tedious and error prone. Fortunately JSL provides an alternative notation that can be used:
str = " . . . \[ . . . ]\ . . . "
Text within the square brackets can be written without the need to use escape sequences, for example:
str = "\[ my name is "David"]\"
Concatenating Strings
Often a string variable is constructed by adding multiple strings together. String addition is referred to as concatenation and is performing using the concatenation operator: .
myName = "David";
str = "My name is "  myName;
Converting to a String
In the above example the string variable str was constructed from a literal quoted string plus a second variable that contained a string. Sometimes the second variable is numeric, in which case it must be explicitly converted to a string. This can be performed using the Char function:
age = 25;
str = "My age is "  Char(age)  " – yeah, I wish!"
String Substitution
In the above example it was necessary to concatenate three elements in order to construct the string that had the age variable embedded in it. Another technique is to use string substitution.
We could write the above string with a placeholder for the age:
str = "My age is pAge – yeah, I wish!"
And now we can substitute the actual value for the placeholder:
str = SubstituteInto(str,char(age))
Note that the value being substituted needs to be a string, so in this example the Char function is still required to convert age from a number to a string.
Conditional Logic and String Searches
With numeric values it is often the case that we want to perform some form of conditional logic based on their value:
If (yield > 80,
status = "good"
,
status = "poor"
);
With string values we can also perform conditional logic:
If (status == "good",
colour = "green"
,
colour = "red"
);
Or equivalently, using the Match function:
Match(status,
"good", colour = "green",
"bad", colour = "red"
);
String comparisons are casesensitive. JMP has functions to transform case: lowercase, uppercase, and titlecase. So a more robust comparison would be:
Match(lowercase(status),
"good", colour = "green",
"bad", colour = "red"
);
String Length
The number of a characters in a text string can be determined using the Length function:
Example:
str = "Hello World";
nChars = Length(str); // nChars = 11
Extracting Content
To locate portions of text within a string, JMP provides a variety of functions, including word, words, left, right, and substr.
strWord = Word( n, string, <delimiter> )
The word function returns the n’th word within a string. The default delimiter for each word within the string is a space character. However, the optional delimiter field can be used to identify an alternate character to be used.
Example:
str = "Hello 'John'";
secondWord = word(2,str); // secondWord = "'John'"
strName = word(2,str,"'"); // str = "John"
lstWords = Words( string, <delimiter> )
Whereas the word function identifies a single specific word within a string, the words function returns all the individual words as items of a list:
If an empty string is specified as the delimiter then each character of the string is treated as a separate word.
Example 1: isolating individual characters
strName = "John";
lstChars = Words(strName,"");
// lstChars = {"J", "o", "h", "n"}
Example 2: counting the number of words
Number Of Words = Function({str},{default local},
nitems(words(str))
);
str = "this is a sentence";
n = Number Of Words(str); // n = 4
Example 3: determining the file extension of a file
filePath = “c:\documents\big class.jmp”;
w = Words(filePath,”.”);
filetype = w[nitems(w)]; // filetype = “jmp”
strLeftMostChars = Left( string, n, <filler> )
The left function can be used to extract the n leftmost characters of a string. An optional filler character can be specified for instances where the string may be less than n characters in length.
Similarly there is a right function to extract the n rightmost characters.
Example : determining whether a file is a JMP table
filePath = “c:\documents\big class.jmp”;
if (right(filePath,4)==".jmp",
isJmpTable = 1
,
isJmpTable = 0
);
strSubstring = Substr( string, offset, <count> )
The substr function returns part of the string composed of count characters starting at position offset.
Example:
str = "Hello 'John'";
strQuotedName = Word(2,str);
strName = Substr(strQuotedName,2,length(strQuotedName)2);
// str = "John"
Pattern Matching
Pattern matching in JSL provides an exceptionally powerful and flexible mechanism for searching and manipulating text strings. Central to pattern matching is the creation of variables that contain pattern definitions. These definitions are then processing by pattern matching functions. I will illustrate the principle based on a scenario that I am currently working on.
I have a column formula that contains a model of the form:
Where K1, K2, N1 and C are parameters that are estimated using the nonlinear platform. I want to inspect the formula for the column and retrieve the K2 value, which represents the activation energy for this kinetic equation.
I can retrieve the formula by sending the getFormula message to the column; this is what it looks like:
Parameter(
{K1 = 0.016232665, K2 = 683.35374,
N1 = 1.6719301, C =0.06863445},
K1 * Exp( K2 / :Temperature) * :RH ^ N1 * :Time + C
)
Notice that there is a pattern to how the parameter values are specified:
K2 = <k2_value>,
I can describe this pattern by defining a pattern matching variable:
pattern = "K2 = " + PatArb()>>k2_value + ", "
This pattern variable says “find K2 followed by an equals sign, then some arbitrary text, then a comma”. It also stores the arbitrary text in the variable k2_value. The value is arbitrary in that it doesn’t have a known value, but it is the value I am seeking.
Now I can apply the pattern to a string representation to the formula, check that I have a successful match, and if so then I can convert the string value of k2_value to a number:
fml = char( :Y << get formula );
pattern = "K2 = " + PatArb()>>k2_value + ",";
success = patMatch(fml,pattern);
if (success,
k2 = num(k2_value);
,
write("Failed to find k2")
);
// now k2 = 683.35374;
]]>
http://www.pegaanalytics.co.uk/blog/workingwithstringvariables/feed/
2

Working with Zip Files
http://www.pegaanalytics.co.uk/blog/workingwithzipfiles/
http://www.pegaanalytics.co.uk/blog/workingwithzipfiles/#respond
Sat, 04 Apr 2020 14:58:08 +0000
http://www.pegaanalytics.co.uk/blog/?p=2426
Continue reading Working with Zip Files ]]>
Zip files are a common file format for sharing collections of files or for compressing large files. I’m going to take a look at how JSL can be used to handle these files without first manually unzipping the file.
The Zip Archive Object
Version 12 of JMP introduced the Zip Archive object for manipulating zip files. A zip archive object is created using the Open function with the zip keyword:
za = open("Data.zip", zip);
Interrogating the Zip File
The first thing that we might want to do is to determine the contents of the zip file. The dir message can be sent to a zip archive object to product a directory list of the contents:
Opening the First JMP Table
To read the contents of the first JMP table within the zip file I can send the read message to the zip archive object:
blobdata = za << read( lst[1], format(blob) )
The JMP file is in a binary format, not straight text. I deal with that by adding ‘format(blob)’ to the message. The data that describes the contents of this file is contained in a variable that I have named blobdata.
To create the physical file I need to save this data:
path = “c:\documents\”  lst[1];
savetextfile(path,blobdata) ;
Now I can access the JMP data in the usual way:
dt = open(path);
Processing the Entire Zip File
Now that I have established the code framework for handling the contents of the zip file, I can iterative over all of the contained files:
za = open("Data.zip", zip);
lst = za << dir;
for (i=1,i<=nitems(lst),i++,
blobdata = za << read(lst[i],format(blob));
path = “c:\documents\”  lst[i];
savetextfile(path,blobdata);
);
An Extended Example
Let’s say that I want to perform the following tasks:
 Allow the user to select the zip file
 Present the user a list of files contained within the zip file
 Allow the user to select a file
 Open the selected file
Here is the code:
namesdefaulttohere(1);
// let the user pick the zip file
zipPath = pickfile("Select File:",,{"Zip Fileszip"});
if (ismissing(zipPath),throw());
// list contents of zip file
za = open(zipPath,zip);
lst = za << dir;
// let the user select a file from the list
nw = NewWindow("Selection",<<modal,
<<onClose(
sel = lb << getSelected
),
BorderBox(top(10),bottom(20),left(20),right(20),
VListBox(
TextBox("Select a file:"),
SpacerBox(size(0,6)),
lb = ListBox(lst,maxselected(1)),
)
)
);
if (nw["Button"]==1,throw());
// grab the name of the file from the list selection
if (nitems(sel)>0,
file = sel[1]
,
throw()
);
// unzip the file
blob = za << read(file,format(blob));
// open the table
filePath = convertfilepath(file,base("$TEMP"));
show(filePath);
savetextfile(filePath,blob);
dt = open(filePath);
]]>
http://www.pegaanalytics.co.uk/blog/workingwithzipfiles/feed/
0

Online Learning Zone
http://www.pegaanalytics.co.uk/blog/onlinelearningzone/
http://www.pegaanalytics.co.uk/blog/onlinelearningzone/#respond
Fri, 27 Mar 2020 18:07:30 +0000
http://www.pegaanalytics.co.uk/blog/?p=2421
Coming soon …
]]>
http://www.pegaanalytics.co.uk/blog/onlinelearningzone/feed/
0

Transparency
http://www.pegaanalytics.co.uk/blog/transparency/
http://www.pegaanalytics.co.uk/blog/transparency/#respond
Sun, 10 Nov 2019 09:30:06 +0000
http://www.pegaanalytics.co.uk/blog/?p=2413
Here’s a handy little function to apply a transparency effect to a solid (r,g,b) colour:TransparentRGB = function({r,g,b,opacity=0.65},{default local},
red = opacity*r + (1opacity);
green = opacity*g + (1opacity);
blue = opacity*b + (1opacity);
return(RGBColor(red,green,blue));
);
]]>
http://www.pegaanalytics.co.uk/blog/transparency/feed/
0

File Handling
http://www.pegaanalytics.co.uk/blog/filehandling/
http://www.pegaanalytics.co.uk/blog/filehandling/#respond
Sun, 10 Mar 2019 09:29:59 +0000
http://www.pegaanalytics.co.uk/blog/?p=2406
The JMP scripting language has a number of convenient functions for handling files external to JMP. Here’s an example:// purge the temporary folder
files = filesIndirectory(tmpDir);
for (i=1,i<=nItems(files),i++,
path = convertFilePath(files[i],base(tmpDir));
if (!isDirectory(path),
deleteFile(path)
)
);
]]>
http://www.pegaanalytics.co.uk/blog/filehandling/feed/
0

Code Folding
http://www.pegaanalytics.co.uk/blog/codefolding/
http://www.pegaanalytics.co.uk/blog/codefolding/#comments
Sat, 02 Feb 2019 14:05:30 +0000
http://www.pegaanalytics.co.uk/blog/?p=2400
Continue reading Code Folding ]]>
Code folding allows you to collapse a block of code – you can use it to focus on highlevel structure without getting lost in the detail.
To enable code folding enable to option under the Script Editor section of Preferences, found under the File menu.
I use it with my userdefined functions to give me an overview of contents within an include file. Combined with appropriately placed comments this helps to summarise the contents of a library of functions. Here is an example:
]]>
http://www.pegaanalytics.co.uk/blog/codefolding/feed/
4

Reverse Process Capability
http://www.pegaanalytics.co.uk/blog/reverseprocesscapability/
http://www.pegaanalytics.co.uk/blog/reverseprocesscapability/#respond
Thu, 10 Jan 2019 11:44:03 +0000
http://www.pegaanalytics.co.uk/blog/?p=2318
Continue reading Reverse Process Capability ]]>
Process capability is a wellestablished technique for evaluating the degree to which a process is capable of delivering a product within specification. But what if the specifications are unknown or at best tentative?
The calculations of process capability analysis can be reversed so that for a given set of target capability values the associated specification limits can be generated. The calculation is straightforward for a normal distribution but needs a bit more thought when it comes to asymmetric distributions.
Reverse Calculation for a Normal Distribution
Traditionally process capability is defined with respect to a normal distribution. The capability index is the ratio of the specification width to process width:
Where σ is the standard deviation of the process variation and twosided spec limits (USL,LSL) are assumed. The width of the specification window can be identified simply by rearranging the above formula:
In the case where we haven’t established our spec limits then we can substitute a target value for Cp to generate the width of the specification window (USLLSL).
If our spec limits are symmetric with respect to our target, and the process is ontarget, then the symmetry can be used to determine the levels of the lower and upper specs:
,
Where TGT represents our process target. I’ve used the ‘target’ superscript to make it more explicit that I am using a Cp value that represents the target value, and not the value derived from the data.
I can illustrate this with a specific example. Suppose that we have a process with a mean value of 100 and a standard deviation of 10 and that we want to identify spec limits that would result in a Cp of 2.0.
I can simply plug the numbers into the above formulae:
The reverse calculation requires simple algebraic operations applied to the standard definitions of process capability indices. No knowledge of statistical theory is required.
Verifying the Calculations
The above calculations can be verified by taking a (large) random sample from a normal distribution and performing a process capability study using the proposed specification limits:
The simulation confirms that my proposed specification limits yield values a value of 2.0 for Cp.
Process Capability for NonNormal Distributions
The reverse calculation for nonnormal (asymmetric) distributions is more complex and first it is necessary to understand how the definition of capability indices is generalised for distributions such as lognormal and Weibull.
Whilst capability studies can be summarised by simple indices, they encapsulate the notion of defective parts per million. To illustrate this let’s take a simple case where we have a process on target and a process capability of 1. In this instance, by definition, the specification width is identical to the process width of 6σ.
The conversion of capability indices to dppm is dependent on the underlying distribution
We know that for a normal distribution 99.73% of the data is contained with this range. That’s another way of saying that 0.27% of data is outside of spec, equivalent to 2700 defective parts per million (dppm). The conversion of capability indices to dppm is therefore dependent on using the underlying distribution to generate probability outcomes.
Without loss of generality let’s assume that we have asymmetric process data that can be characterised using a Weibull distribution. If 6σ is the width of a normal distribution then what is the width of a Weibull distribution?
The appropriate way to define the width of the Weibull distribution is so that it has equivalent probability outcomes to the normal distribution: the width can be defined so that it contains 99.73% of the data. Furthermore this interval can be located in such a way that 0.135% of the data falls either side of this interval.
To illustrate this principle I have generated some random data sampled from a lognormal distribution and through a process of trial and error identified specification limits that satisfy the above criteria:
Reverse Calculation for the Weibull Distribution
Having established the principle for generalising capability indices I now want to explore the calculations that are required to generate proposed spec limits.
The 6σ width that we associate with a normal distribution can be generalised to an interval that contains 99.73% of the data. More specifically:
Where Pu is the upper percentile (100%0.135%) and Pl is the lower percentile (0.135%).
This can be used to generalise the definition of process capability:
Furthermore the onesided capability indices can be generalised by replacing the average value (Ybar) with the median (P50):
and
Let me take the case where the process is ontarget. In that case Cpl = Cpu = Cp.
Therefore
I can rearrange this to get an expression for LSL:
Taking the same approach for Cpu reveals:
Using Simulation to Verify the Result
As usual I want to verify my calculations, which I can do using simulated data. The first step is for me to generate a sample of data selected randomly from a Weibull distribution:
Let me assume that my target value for Cp is 1.50. I can use this value in my expressions for the specification limits:
But I also need to calculate the percentiles P50, Pu and PL. I can do this using the Weibull Quantile function:
Using the alpha and beta parameter estimates from the fitted distribution I calculate the following values:
Now I have all the information that I need to calculate the spec limit values required to generate my desired Cp goal. In fact let me do it as a short JSL script:
I estimate the specs to be 70 and 319.
Am I right? I can use JMP to perform the process capability analysis using these numbers:
Spot on!
]]>
http://www.pegaanalytics.co.uk/blog/reverseprocesscapability/feed/
0