Use C# to create a simple SP, CP and CPK chart
Introduction
In this article, we can see in detail how to create a simple SPC (Statistical Process Control) CP, CPK Chart.
I have been working on several automation projects. Nowadays, automobile industry is interested in automated measuring machines to ensure quality and to compete in the global industry. The main part of any automation software is to get the accurate result with Quality check, for this purpose, we use the SPC (Statistical Process Control) to find the quality result.
You can also view my previous articles related to Factory Automation like:
Capability is to get the continuous data from any part and compare the result with Cp, Cpk, Pp and Ppk. Where Cp, Cpk are Process Capability and Pp, Ppk are process performance. Let’s consider one of my real time projects, which is using in a Manufacturing Automation Measuring machines. Let’s consider now Camshaft, Crankshaft or any part of Car Engine which need to be checked with Quality control. The check part will be measured using some kind for Sensors, for example, in our project, we use a digital sensor for measuring Camshaft and Crankshaft. Using the sensor, we get continuous data and the real time data will be checked with SPC Cp, Cpk, Pp and Ppk charts. Display the final output to the operator and to the Quality control Engineer. Here is my real time project screen. All the Measurement data has been received from the Digital Sensor.
I have hidden the SPC Cp, Cpk, Pp and Ppk chart as we used some third party chart control at that time. For the SPC chart in the market, there are very few third party chart controls available and there is no any free chart for SPC Cp, Cpk, Pp and Ppk. I thought of creating a simple SPC Cp, Cpk, Pp and Ppk chart. As a result, after a long study about SPC and all its functionality, I have created a simple SPC Cp, Cpk, Pp and Ppk chart. Hope you all will like it.
I created the SPC chart as a User Control. You can just add my User Control DLL to the project and use it.
Shanu CpCpkChart User Control Features
- Display chart with Sum, Mean and Range values
- Cp, Cpk, Pp, Ppk with alert result text warning with Red for NG and green for OK result
- Mean (XBAR) and Range (RBAR) chart with Alert image with Red for NG and green for OK result
- Automatic Calculate and display UCL(Upper Control Limit), LCL(Lower Control Limit) Value with both XBAR and RBAR value
- Save Chart as Image (Note to save the Chart image double click the chart or right click and save as Image).
- Real Time data Gathering and display in the Chart
- User can add Chart Watermark text
First, let’s see what is Cp
and Cpk
.
Cp and Cpk -> Process Capability
- Cp - measures how well the data fits within the spec limits (USL, LSL)
- Cpk - measures how centered the data is between the spec limits
Cp, Cpk Formula
Cp=(USL-LSL/6SIGMA) -> USL-LSL/6*RBAR/d2 Cpk=min(USL-XBAR/3Sigma,LSL-XBAR/3Sigma)
Pp and Ppk -> Process Performance
- Pp - measures how well the data fits within the spec limits (USL, LSL)
- Ppk - measures how centered the data is between the spec limits
Pp, Ppk Formula
Pp=(USL-LSL/6SIGMA) -> USL-LSL/6 STDEV Ppk=min(USL-XBAR/3STDEV,LSL-XBAR/3STDEV)
Reference Websites
- CP, CPK, PP and PPK: Know how and when to use them
- Process Capability Index - Cp vs. Cpk Visual Animation
- Cp Cpk Formulas versus Pp Ppk Formulas
- Cpk
- CP, CPK, PP AND PPK: Know how and when to use them
- How to Calculate Cp and Cpk
- What is Process Capability?
Now let’s see how I have created a SPC Cp, Cpk chart. My main aim is to make a very simple SPC Chart which can be used by the end users.
I have created a SPC Cp, Cpk Chart as a User Control so that it can be used easily in all projects.
I have attached a zip file named as ShanuSPCCpCpkChart.zip which you can download from the link at the top of this article. It contains my SPC chart user control source and a demo program.
- "ShanuCPCPKChart.dll": You can use this user controls in your project and pass the data as
DataTable
touserControl
.
In the user control, I will get theDataTable
value and calculate the result to display as:
Sum
Mean
Range
Cp
Cpk
Pp
Ppk
Bind all the results to the chart with smiley alert image. If the data is good, then display the green smiley and if the data is NG(Not Good). Using the mean and Range values, I will plot the result as Mean and Range chart with Alert Image.
User can pass the USL (upper Specification Limit), LSL (lower Specification Limit) Cpk Limit values to the ShanuCPCPKChart
user control. Using the USL, LSL and Cpk value, the result will be calculated and display the appropriate alert with red if NG for Cp, Cpk ,Pp, Ppk values. If the result is good, then green text will be displayed to Cp, Cpk, Pp, Ppk in the chart.
"ShanuSPCCpCPK_Demo" folder - This folder contains the demo program which includes the ShanuCPCPKChart
user control with Random Data sample.
Note: I have used DataTable
as the data input for the User Control. From the Windows Form, we need to pass the DataTable
to User control to plot the Cp, Cpk, Pp and Ppk result with SPC Range Chart.
Save Chart User can save the Chart by double clicking on the chart control or by right click the chart and click Save.
Using the Code
I have used Visual Studio 2010.
1) SPC User Control Program
First, we will start with the User Control. To create a user control:
- Create a new Windows Control Library project.
- Set the Name of Project and click OK (here, my user control name is
ShanuCPCPKChart
). - Add all the controls which are needed.
- In code behind, declare all the
public
variables andPublic
method. In User control, I have added one panel and one Picture Box Control.
public DataTable dt = new DataTable();
Font f12 = new Font("arial", 12, FontStyle.Bold, GraphicsUnit.Pixel);
Pen B1pen = new Pen(Color.Black, 1);
Pen B2pen = new Pen(Color.Black, 2);
Double XDoublkeBAR = 0;
Double RBAR = 0;
Double XBARUCL = 0;
Double XBARLCL = 0;
Double RANGEUCL = 0;
Double RANGELCL = 0;
Double[] intMeanArrayVals;
Double[] intRangeArrayVals;
Double[] intSTDEVArrayVals;
Double[] intXBARArrayVals;
int First_chartDatarectHeight = 80;
Font f10 = new Font("arial", 10, FontStyle.Bold, GraphicsUnit.Pixel);
LinearGradientBrush a2 = new LinearGradientBrush(new RectangleF(0, 0, 100, 19),
Color.DarkGreen, Color.Green, LinearGradientMode.Horizontal);
LinearGradientBrush a3 = new LinearGradientBrush(new RectangleF(0, 0, 100, 19),
Color.DarkRed, Color.Red, LinearGradientMode.Horizontal);
LinearGradientBrush a1 = new LinearGradientBrush(new RectangleF(0, 0, 100, 19),
Color.Blue, Color.DarkBlue, LinearGradientMode.Horizontal);
Once the variable is declared, I create a public
function as Bindgrid
. This function will be used from Windows Form to pass the DataTable
. In this function, I will check for the DataTable
and if the DataTable
is not null
, I refresh the PictureBox
which will call the PictureBox paint
method to Plot all new values for SPC Chart.
public void Bindgrid(DataTable dtnew)
{
if (dtnew != null)
{
dt = dtnew;
PicBox.Refresh();
}
}
In PictureBox paint
event, I will check for the DataTable
data. Using the data, I calculate and draw the result of all Sum, Mean, Range, Cp, Cpk, Pp and Ppk to the SPC Chart. Using this information, I have created UCL and LCL by Standard formula. For details about UCL and LCL calculation, kindly check the above links. After all the values are calculated, I will draw the SPC chart in PictureBox
using GDI+ and display the result to the end user.
public void PicBox_Paint(object sender, PaintEventArgs e)
{
if (dt.Rows.Count <= 0)
{
return;
}
int opacity = 68; // 50% opaque (0 = invisible, 255 = fully opaque)
e.Graphics.DrawString(ChartWaterMarkText,
new Font("Arial", 72),
new SolidBrush(Color.FromArgb(opacity, Color.OrangeRed)),
80,
PicBox.Height / 2 - 15);
int NoofTrials = dt.Rows.Count;
int NoofParts = dt.Columns.Count - 1;
intMeanArrayVals = new Double[NoofParts];
intRangeArrayVals = new Double[NoofParts];
intSTDEVArrayVals = new Double[NoofParts];
intXBARArrayVals = new Double[NoofParts];
if (dt.Rows.Count <= 0)
{
return;
}
PicBox.Width = dt.Columns.Count * 50 + 40;
// 1) For the Chart Data Display ---------
e.Graphics.DrawRectangle(Pens.Black, 10, 10, PicBox.Width - 20,
First_chartDatarectHeight + 78);
// for the chart data Horizontal Line Display
e.Graphics.DrawLine(B1pen, 10, 25, PicBox.Width - 10, 25);
e.Graphics.DrawLine(B1pen, 10, 45, PicBox.Width - 10, 45);
e.Graphics.DrawLine(B1pen, 10, 65, PicBox.Width - 10, 65);
e.Graphics.DrawLine(B1pen, 10, 85, PicBox.Width - 10, 85);
e.Graphics.DrawLine(B1pen, 10, 105, PicBox.Width - 10, 105);
e.Graphics.DrawLine(B1pen, 10, 125, PicBox.Width - 10, 125);
e.Graphics.DrawLine(B1pen, 10, 145, PicBox.Width - 10, 145);
// e.Graphics.DrawLine(B1pen, 10, 165, PicBox.Width - 10, 165);
// for the chart data Vertical Line Display
e.Graphics.DrawLine(B1pen, 60, 10, 60, First_chartDatarectHeight + 87);
e.Graphics.DrawLine(B1pen, 110, 10, 110, First_chartDatarectHeight + 87);
//-------------
// DrawItemEventArgs String
e.Graphics.DrawString("SUM", f12, a1, 14, 10);
e.Graphics.DrawString("MEAN", f12, a1, 14, 30);
e.Graphics.DrawString("Range", f12, a1, 14, 50);
e.Graphics.DrawString("Cp", f12, a1, 14, 70);
e.Graphics.DrawString("Cpk", f12, a1, 14, 90);
e.Graphics.DrawString("Pp", f12, a1, 14, 110);
e.Graphics.DrawString("Ppk", f12, a1, 14, 130);
// load data
//Outer Loop for Columns count
int xLineposition = 110;
int xStringDrawposition = 14;
Double[] locStdevarr;
for (int iCol = 1; iCol <= dt.Columns.Count - 1; iCol++)
{
//inner Loop for Rows count
Double Sumresult = 0;
Double Meanresult = 0;
Double Rangeresult = 0;
Double minRangeValue = int.MaxValue;
Double maxRangeValue = int.MinValue;
locStdevarr = new Double[NoofTrials];
for (int iRow = 0; iRow < dt.Rows.Count; iRow++)
{
Sumresult = Sumresult +
System.Convert.ToDouble(dt.Rows[iRow][iCol].ToString());
Double accountLevel = System.Convert.ToDouble(dt.Rows[iRow][iCol].ToString());
minRangeValue = Math.Min(minRangeValue, accountLevel);
maxRangeValue = Math.Max(maxRangeValue, accountLevel);
locStdevarr[iRow] = System.Convert.ToDouble(dt.Rows[iRow][iCol].ToString());
}
xLineposition = xLineposition + 50;
xStringDrawposition = xStringDrawposition + 50;
e.Graphics.DrawLine(B1pen, xLineposition, 10, xLineposition,
First_chartDatarectHeight + 87);
//Sum Data Display
e.Graphics.DrawString(Math.Round(Sumresult, 3).ToString(), f10,
a2, xStringDrawposition, 12);
//MEAN Data Display
Meanresult = Sumresult / NoofTrials;
e.Graphics.DrawString(Math.Round(Meanresult, 3).ToString(),
f10, a2, xStringDrawposition, 30);
//RANGE Data Display
Rangeresult = maxRangeValue - minRangeValue;
e.Graphics.DrawString(Math.Round(Rangeresult, 3).ToString(),
f10, a2, xStringDrawposition, 50);
//XDoubleBar used to display in chart
XDoublkeBAR = XDoublkeBAR + Meanresult;
//RBAR used to display in chart
RBAR = RBAR + Rangeresult;
intMeanArrayVals[iCol - 1] = Meanresult;
intRangeArrayVals[iCol - 1] = Rangeresult;
intSTDEVArrayVals[iCol - 1] = StandardDeviation(locStdevarr);
}
//End 1 ) -------------------
// 2) --------------------------
// XdoubleBAr/RBAR/UCL and LCL Calculation.
//XDoubleBar used to display in chart
XDoublkeBAR = XDoublkeBAR / NoofParts;
//RBAR used to display in chart
RBAR = RBAR / NoofParts;
//XBARUCL to display in chart
XBARUCL = XDoublkeBAR + UCLLCLTYPE("A2", RBAR, NoofTrials);
//XBARLCL to display in chart
XBARLCL = XDoublkeBAR - UCLLCLTYPE("A2", RBAR, NoofTrials);
//XBARUCL to display in chart
RANGEUCL = UCLLCLTYPE("D4", RBAR, NoofTrials);
//XBARLCL to display in chart
RANGELCL = UCLLCLTYPE("D3", RBAR, NoofTrials);
//2.1) Status Display inside pic grid +++++++++++++++++++++++++++
int XCirclegDrawposition = 24;
int YCirclegDrawposition = 147;
xStringDrawposition = 14;
for (int i = 0; i < intMeanArrayVals.Length; i++)
{
Color pointColor = new Color();
pointColor = Color.YellowGreen;
XCirclegDrawposition = XCirclegDrawposition + 50;
Point p1 = new Point();
p1.X = XCirclegDrawposition;
p1.Y = YCirclegDrawposition;
if (intMeanArrayVals[i] < XBARLCL)
{
pointColor = Color.Red;
}
else if (intMeanArrayVals[i] > XBARUCL)
{
pointColor = Color.Red;
}
Pen pen = new Pen(Color.SeaGreen);
e.Graphics.DrawPie(pen, p1.X, p1.Y, 18, 18, 0, 360);
e.Graphics.FillPie(new SolidBrush(pointColor), p1.X, p1.Y, 18, 18, 10, 360);
pen = new Pen(Color.Black);
e.Graphics.DrawPie(pen, p1.X + 3, p1.Y + 4, 2, 2, 10, 360);
e.Graphics.DrawPie(pen, p1.X + 11, p1.Y + 4, 2, 2, 10, 360);
e.Graphics.DrawPie(pen, p1.X + 5, p1.Y + 12, 8, 4, 10, 180);
// 1)
//Cp Calculation (((((((((((((((((((((((((((
//Cp=(USL-LSL/6SIGMA) -> USL-LSL/6*RBAR/d2
Double d2 = d2Return(NoofTrials);
Double USLResult = USLs - LSLs;
Double RBARS = intRangeArrayVals[i] / NoofTrials;
Double Sigma = RBARS / d2;
Double CpResult = USLResult / 6 * Sigma;
xStringDrawposition = xStringDrawposition + 50;
e.Graphics.DrawString(Math.Round(CpResult, 3).ToString(),
f10, a2, xStringDrawposition,