1. Data Simulation Rationale

1.1 The Challenge

During our site visit, Arani was unable to share proprietary quality data due to the competitive sensitivity of their industry. However, demonstrating statistical process control (SPC) implementation requires data to construct and interpret control charts.

1.2 Our Approach

We created realistic simulated data based on:

  • Information gathered during the site visit
  • Industry standards for LED lighting products
  • Arani’s stated tolerances (±5% for critical parameters)
  • Their testing frequency (3–4 products per day)
  • Their batch sizes and shipping patterns (50 batches/year, 2,000 units/batch)
  • AQL sampling approach (Level II, n = 125)

This approach allows us to demonstrate how SPC tools would function in Arani’s operational environment.


2. Chart Selection: X-bar and R Chart

2.1 Why X-bar and R Chart?

The X-bar and R chart is the most appropriate control chart for monitoring Arani’s LED lumen output for the following reasons:

Arani’s Reality Our Design Choice
Tests 3–4 products per day Rational subgroups of n = 4
Lumen output is the critical performance metric Continuous measurement data
Subgroup size is small (n < 10) R chart preferred over S chart
Need to monitor both process average and variation X-bar tracks mean; R tracks spread

2.2 Simulation Parameters

Based on industry standards and information from the site visit:

Parameter Value Rationale
Target 1000 lumens Industry standard for commercial LED
Tolerance ±5% (±50 lumens) Per Arani’s stated policy
LSL / USL 950 / 1050 lumens Target ± tolerance
Subgroup size (n) 4 Daily tests (3–4 products/day)
Number of subgroups (k) 25 Approximately 5 weeks of data
Process σ 18 lumens Realistic for uncontrolled process

2.3 Scenario Design

To demonstrate the chart’s ability to detect process shifts:

  • Days 1–18: Process in control (μ = 1000, σ = 18)
  • Days 19–25: Mean shift to μ = 975 lumens

This simulates a supplier batch issue, which is realistic given Arani’s 3–6 month offshore lead times and their acknowledged challenges with supplier quality consistency.

2.4 Data Generation

# Parameters
n <- 4
k_total <- 25
k_in_control <- 18
k_shifted <- 7

target <- 1000
sigma <- 18
shift <- -25

LSL <- 950
USL <- 1050

# Generate Phase 1: In control
phase1_matrix <- matrix(
  rnorm(n * k_in_control, mean = target, sd = sigma),
  nrow = k_in_control, 
  ncol = n, 
  byrow = TRUE
)

# Generate Phase 2: Process shift (supplier issue)
phase2_matrix <- matrix(
  rnorm(n * k_shifted, mean = target + shift, sd = sigma),
  nrow = k_shifted, 
  ncol = n, 
  byrow = TRUE
)

# Combine data
lumen_data <- rbind(phase1_matrix, phase2_matrix)
colnames(lumen_data) <- paste("Unit", 1:n)
rownames(lumen_data) <- paste("Day", 1:k_total)

2.5 Simulated Data

# Calculate subgroup statistics
x_bar <- apply(lumen_data, 1, mean)
R <- apply(lumen_data, 1, function(x) max(x) - min(x))

# Summary table
summary_df <- data.frame(
  Day = 1:k_total,
  Unit_1 = round(lumen_data[, 1], 1),
  Unit_2 = round(lumen_data[, 2], 1),
  Unit_3 = round(lumen_data[, 3], 1),
  Unit_4 = round(lumen_data[, 4], 1),
  X_bar = round(x_bar, 2),
  R = round(R, 2),
  Phase = c(rep("In Control", k_in_control), rep("Shifted", k_shifted))
)

knitr::kable(summary_df, caption = "Simulated Lumen Output Data with Subgroup Statistics")
Simulated Lumen Output Data with Subgroup Statistics
Day Unit_1 Unit_2 Unit_3 Unit_4 X_bar R Phase
Day 1 1 969.1 966.4 1018.2 1006.3 990.02 51.85 In Control
Day 2 2 978.3 1027.4 1030.1 1015.5 1012.82 51.79 In Control
Day 3 3 1005.7 1011.2 1026.3 987.0 1007.56 39.36 In Control
Day 4 4 1017.2 981.3 991.0 1003.0 998.14 35.85 In Control
Day 5 5 992.1 956.6 1012.0 1019.7 995.10 63.06 In Control
Day 6 6 1006.0 1025.7 1006.1 1009.6 1011.87 19.70 In Control
Day 7 7 994.8 1023.8 1010.0 974.3 1000.71 49.54 In Control
Day 8 8 1023.2 1009.9 979.8 963.0 993.94 60.20 In Control
Day 9 9 956.0 996.1 982.5 1013.6 987.06 57.53 In Control
Day 10 10 1000.9 971.0 1016.6 1026.5 1003.73 55.55 In Control
Day 11 11 1018.1 1028.0 1021.1 1041.2 1027.10 23.05 In Control
Day 12 12 993.3 991.9 992.0 1006.9 996.03 15.01 In Control
Day 13 13 997.4 982.3 1012.6 1013.1 1001.33 30.84 In Control
Day 14 14 1014.9 982.1 994.2 984.7 993.98 32.80 In Control
Day 15 15 995.9 1005.3 1020.4 1017.0 1009.68 24.49 In Control
Day 16 16 1027.0 956.1 996.3 993.8 993.29 70.95 In Control
Day 17 17 973.8 996.5 1001.2 1003.5 993.76 29.72 In Control
Day 18 18 1003.3 999.9 990.3 966.6 990.01 36.64 In Control
Day 19 19 968.8 1011.8 996.3 997.4 993.58 43.00 Shifted
Day 20 20 969.6 961.6 977.8 1017.1 981.52 55.55 Shifted
Day 21 21 963.7 979.6 1019.1 999.9 990.56 55.33 Shifted
Day 22 22 967.4 1006.4 960.8 951.9 971.66 54.50 Shifted
Day 23 23 956.2 989.8 963.1 963.8 968.24 33.59 Shifted
Day 24 24 973.4 997.8 976.1 949.8 974.29 48.09 Shifted
Day 25 25 963.8 977.3 963.7 995.8 975.15 32.10 Shifted

2.6 X-bar Chart

xbar_chart <- qcc(lumen_data, type = "xbar",
                  title = "X-bar Chart: LED Lumen Output (Arani QC)",
                  xlab = "Day (Subgroup)",
                  ylab = "Mean Lumen Output")

# Add specification limits
abline(h = USL, col = "orange", lty = 2, lwd = 2)
abline(h = LSL, col = "orange", lty = 2, lwd = 2)
abline(h = target, col = "purple", lty = 3, lwd = 2)
legend("topright", 
       legend = c("Control Limits", "Spec Limits", "Target"),
       col = c("red", "orange", "purple"),
       lty = c(1, 2, 3),
       lwd = 2,
       cex = 0.8)

X-bar Chart Control Limits

cat("UCL:", round(xbar_chart$limits[1, 2], 2), "lumens\n")
## UCL: 1025.63 lumens
cat("Center (X-double-bar):", round(xbar_chart$center, 2), "lumens\n")
## Center (X-double-bar): 994.44 lumens
cat("LCL:", round(xbar_chart$limits[1, 1], 2), "lumens\n")
## LCL: 963.26 lumens

2.7 R Chart

r_chart <- qcc(lumen_data, type = "R",
               title = "R Chart: LED Lumen Output (Arani QC)",
               xlab = "Day (Subgroup)",
               ylab = "Range")

R Chart Control Limits

cat("UCL:", round(r_chart$limits[1, 2], 2), "lumens\n")
## UCL: 97.67 lumens
cat("Center (R-bar):", round(r_chart$center, 2), "lumens\n")
## Center (R-bar): 42.8 lumens
cat("LCL:", round(r_chart$limits[1, 1], 2), "lumens\n")
## LCL: 0 lumens

2.8 Process Capability Analysis

Using only in-control data (Phase 1) to establish baseline capability:

xbar_phase1 <- qcc(phase1_matrix, type = "xbar", plot = FALSE)
process.capability(xbar_phase1, spec.limits = c(LSL, USL), target = target)

## 
## Process Capability Analysis
## 
## Call:
## process.capability(object = xbar_phase1, spec.limits = c(LSL,     USL), target = target)
## 
## Number of obs = 72           Target = 1000
##        Center = 1000            LSL = 950
##        StdDev = 20.18           USL = 1050
## 
## Capability indices:
## 
##        Value    2.5%   97.5%
## Cp    0.8259  0.6902  0.9613
## Cp_l  0.8315  0.6998  0.9632
## Cp_u  0.8203  0.6899  0.9506
## Cp_k  0.8203  0.6649  0.9756
## Cpm   0.8258  0.6911  0.9602
## 
## Exp<LSL 0.63%     Obs<LSL 0%
## Exp>USL 0.69%     Obs>USL 0%

2.9 Out-of-Control Analysis

# X-bar chart violations
xbar_violations <- which(x_bar < xbar_chart$limits[1, 1] | 
                          x_bar > xbar_chart$limits[1, 2])

cat("X-bar Chart - Points beyond control limits: ")
## X-bar Chart - Points beyond control limits:
if(length(xbar_violations) > 0) {
  cat("Days", paste(xbar_violations, collapse = ", "), "\n")
} else {
  cat("None\n")
}
## Days 11
# R chart violations
r_violations <- which(R < r_chart$limits[1, 1] | R > r_chart$limits[1, 2])

cat("R Chart - Points beyond control limits: ")
## R Chart - Points beyond control limits:
if(length(r_violations) > 0) {
  cat("Days", paste(r_violations, collapse = ", "), "\n")
} else {
  cat("None\n")
}
## None

2.10 X-bar and R Chart Interpretation

Key Observations:

  1. Days 1–18 (In Control): Points fluctuate randomly around the center line (~1000 lumens), indicating a stable process.

  2. Days 19–25 (Shifted): A clear downward trend is visible, with points clustering below the center line. This pattern indicates a mean shift — exactly what we would expect from a supplier batch issue.

  3. R Chart Stability: The R chart remains relatively stable throughout, confirming that the issue is a shift in the process mean, not an increase in variability.

Practical Implication: With control charts in place, Arani would have detected this supplier issue by Day 21–22 at the latest, allowing them to quarantine affected inventory and contact the supplier before many defective units entered the market.


3. Chart Selection: p-Chart

3.1 Why p-Chart?

The p-chart is the most appropriate control chart for monitoring Arani’s incoming shipment quality:

Arani’s Reality Our Design Choice
Uses pass/fail acceptance sampling Attribute data (defective vs. conforming)
Inspects samples from incoming shipments Each batch = one inspection opportunity
Sample size n = 125 (AQL Level II) Constant sample size per batch
~50 batches per year Simulated 30 batches (~7 months)

3.2 Why p-Chart Fits Their Workflow

  • Directly formalizes their existing pass/fail system
  • No change to current inspection process required
  • Monitors supplier quality trends over time
  • Provides early warning of supplier deterioration

3.3 Simulation Parameters

Parameter Value Rationale
Sample size (n) 125 per batch AQL Level II (ANSI/ISO 2859-1)
Normal defect rate (p) 0.02 (2%) Industry average per report Section 3.1
Number of batches 30 ~7–8 months of shipments

3.4 Scenario Design

  • Batches 1–22: Normal supplier quality (p = 0.02)
  • Batches 23–30: Supplier quality deterioration (p = 0.06)

This simulates a realistic scenario where a supplier’s quality gradually worsens, perhaps due to cost-cutting measures, equipment degradation, or personnel changes.

3.5 Data Generation

# Parameters
k_batches <- 30
n_sample <- 125
p_normal <- 0.02
p_shifted <- 0.06
k_normal <- 22
k_bad <- 8

# Generate Phase 1: Normal supplier quality
defects_phase1 <- rbinom(k_normal, size = n_sample, prob = p_normal)

# Generate Phase 2: Supplier quality deterioration
defects_phase2 <- rbinom(k_bad, size = n_sample, prob = p_shifted)

# Combine
defects <- c(defects_phase1, defects_phase2)
sample_sizes <- rep(n_sample, k_batches)
p_hat <- defects / sample_sizes

3.6 Simulated Data

p_chart_df <- data.frame(
  Batch = 1:k_batches,
  Sample_Size = sample_sizes,
  Defectives = defects,
  Proportion = round(p_hat, 4),
  Phase = c(rep("Normal", k_normal), rep("Deteriorated", k_bad))
)

knitr::kable(p_chart_df, caption = "Simulated Incoming Inspection Data")
Simulated Incoming Inspection Data
Batch Sample_Size Defectives Proportion Phase
1 125 4 0.032 Normal
2 125 2 0.016 Normal
3 125 3 0.024 Normal
4 125 3 0.024 Normal
5 125 2 0.016 Normal
6 125 1 0.008 Normal
7 125 5 0.040 Normal
8 125 1 0.008 Normal
9 125 4 0.032 Normal
10 125 1 0.008 Normal
11 125 1 0.008 Normal
12 125 0 0.000 Normal
13 125 2 0.016 Normal
14 125 1 0.008 Normal
15 125 3 0.024 Normal
16 125 3 0.024 Normal
17 125 6 0.048 Normal
18 125 2 0.016 Normal
19 125 4 0.032 Normal
20 125 1 0.008 Normal
21 125 0 0.000 Normal
22 125 1 0.008 Normal
23 125 7 0.056 Deteriorated
24 125 9 0.072 Deteriorated
25 125 9 0.072 Deteriorated
26 125 11 0.088 Deteriorated
27 125 9 0.072 Deteriorated
28 125 5 0.040 Deteriorated
29 125 12 0.096 Deteriorated
30 125 7 0.056 Deteriorated

3.7 p-Chart

p_chart <- qcc(defects, 
               sizes = sample_sizes,
               type = "p",
               title = "p-Chart: Incoming Batch Defect Rate (Arani QC)",
               xlab = "Batch Number",
               ylab = "Proportion Defective")

# Add target reference line
abline(h = 0.02, col = "purple", lty = 3, lwd = 2)
legend("topright",
       legend = c("Control Limits", "Target p = 0.02"),
       col = c("red", "purple"),
       lty = c(1, 3),
       lwd = 2,
       cex = 0.8)

p-Chart Control Limits

cat("UCL:", round(p_chart$limits[1, 2], 4), "\n")
## UCL: 0.0788
cat("Center (p-bar):", round(p_chart$center, 4), "\n")
## Center (p-bar): 0.0317
cat("LCL:", round(max(0, p_chart$limits[1, 1]), 4), "\n")
## LCL: 0

3.8 Out-of-Control Analysis

p_violations <- which(p_hat > p_chart$limits[1, 2])

cat("Batches beyond UCL: ")
## Batches beyond UCL:
if(length(p_violations) > 0) {
  cat("Batches", paste(p_violations, collapse = ", "), "\n")
} else {
  cat("None\n")
}
## Batches 26, 29

3.9 Summary Statistics

cat("Overall:\n")
## Overall:
cat("  Total units inspected:", sum(sample_sizes), "\n")
##   Total units inspected: 3750
cat("  Total defectives:", sum(defects), "\n")
##   Total defectives: 119
cat("  Overall proportion defective:", round(sum(defects)/sum(sample_sizes), 4), "\n\n")
##   Overall proportion defective: 0.0317
cat("Phase 1 (Normal, Batches 1-22):\n")
## Phase 1 (Normal, Batches 1-22):
cat("  Average proportion defective:", round(mean(p_hat[1:k_normal]), 4), "\n\n")
##   Average proportion defective: 0.0182
cat("Phase 2 (Deteriorated, Batches 23-30):\n")
## Phase 2 (Deteriorated, Batches 23-30):
cat("  Average proportion defective:", round(mean(p_hat[(k_normal+1):k_batches]), 4), "\n")
##   Average proportion defective: 0.069

3.10 p-Chart Interpretation

Key Observations:

  1. Batches 1–22 (Normal): Points fluctuate randomly around p̄ ≈ 0.02, within control limits. This represents normal supplier variation.

  2. Batches 23–30 (Deteriorated): Multiple points exceed the UCL, signaling that the process is out of control. The supplier’s defect rate has increased significantly.

Practical Implication: Without a p-chart, Arani’s current pass/fail system would continue accepting batches even as quality deteriorates — each batch might still pass the acceptance number (c = 7), but the trend would go unnoticed. The p-chart provides early warning of supplier problems, allowing Arani to:

  • Contact the supplier before quality becomes unacceptable
  • Increase inspection intensity
  • Seek alternative suppliers if necessary

4. Summary: Chart Selection Logic

                    ┌─────────────────────┐
                    │   What data type?   │
                    └──────────┬──────────┘
                               │
              ┌────────────────┴────────────────┐
              ▼                                 ▼
      Continuous                           Attribute
    (measurements)                        (pass/fail)
              │                                 │
              ▼                                 ▼
    ┌─────────────────┐               ┌─────────────────┐
    │ Subgroup size?  │               │ Tracking what?  │
    └────────┬────────┘               └────────┬────────┘
             │                                  │
             ▼                                  ▼
         n = 4                          Proportion
      (daily tests)                     defective
             │                                  │
             ▼                                  ▼
    ┌─────────────────┐               ┌─────────────────┐
    │  X-bar and R    │               │     p-chart     │
    │     Chart       │               │                 │
    └─────────────────┘               └─────────────────┘

Key Takeaways

Chart Purpose Detects
X-bar Chart Monitor process mean Shifts in average quality
R Chart Monitor process variation Increases in inconsistency
p-Chart Monitor defect rate Supplier quality deterioration

Together, these charts would transform Arani’s quality system from reactive (catching defects after they occur) to proactive (detecting problems before many defective units are produced or shipped).


5. Data Export

# Export X-bar/R data
write.csv(data.frame(
  Day = 1:k_total,
  lumen_data,
  X_bar = round(x_bar, 2),
  R = round(R, 2)
), "arani_xbar_r_data.csv", row.names = FALSE)

# Export p-chart data
write.csv(p_chart_df, "arani_p_chart_data.csv", row.names = FALSE)

cat("Data exported to:\n")
## Data exported to:
cat("  - arani_xbar_r_data.csv\n")
##   - arani_xbar_r_data.csv
cat("  - arani_p_chart_data.csv\n")
##   - arani_p_chart_data.csv

Appendix: Control Chart Formulas

X-bar Chart

\[\bar{\bar{X}} = \frac{\sum_{i=1}^{k} \bar{X}_i}{k}\]

\[UCL_{\bar{X}} = \bar{\bar{X}} + A_2 \bar{R}\]

\[LCL_{\bar{X}} = \bar{\bar{X}} - A_2 \bar{R}\]

For n = 4: \(A_2 = 0.729\)

R Chart

\[\bar{R} = \frac{\sum_{i=1}^{k} R_i}{k}\]

\[UCL_R = D_4 \bar{R}\]

\[LCL_R = D_3 \bar{R}\]

For n = 4: \(D_3 = 0\), \(D_4 = 2.282\)

p-Chart

\[\bar{p} = \frac{\sum_{i=1}^{k} D_i}{\sum_{i=1}^{k} n_i}\]

\[UCL_p = \bar{p} + 3\sqrt{\frac{\bar{p}(1-\bar{p})}{n}}\]

\[LCL_p = \bar{p} - 3\sqrt{\frac{\bar{p}(1-\bar{p})}{n}}\]

(LCL set to 0 if negative)


Report generated for MATH 427 - Statistical Quality Control, McGill University