🌐 EN | 🇯🇵 JP | Last sync: 2025-11-16

Chapter 4: Taguchi Methods and Robust Design

Practical Quality Engineering through SN Ratio, Loss Function, and Inner-Outer Arrays

📖 Reading Time: 35-40 min 📊 Level: Intermediate-Advanced 💻 Code Examples: 8

Chapter 4: Taguchi Methods and Robust Design

The Taguchi Method (Quality Engineering) is a technique for enhancing the robustness of products and processes against disturbances. It uses SN ratio (signal-to-noise ratio), loss function, and inner-outer arrays to optimize performance while minimizing variation.

Learning Objectives

By reading this chapter, you will be able to:


4.1 Fundamentals of Taguchi Methods

What is the Taguchi Method?

The Taguchi Method is a quality engineering technique developed by Dr. Genichi Taguchi. It aims to make products and processes robust (enhance robustness) against disturbances (noise factors).

Three Design Stages:

  1. System Design: Determine the basic structure and configuration of the product
  2. Parameter Design: Determine optimal levels of control factors to improve robustness
  3. Tolerance Design: Determine the tradeoff between component precision and cost

Differences from Traditional Optimization:

Item Traditional Optimization Taguchi Method
Goal Maximize average performance Optimize performance while minimizing variation
Disturbance Strategy Keep disturbances constant Design that remains stable despite disturbances
Cost Address with high-precision components (high cost) Address through parameter adjustment (low cost)
Metrics Mean value (μ) SN ratio (η) and variation (σ)

Control Factors and Noise Factors

Control Factors:

Noise Factors:

Three Categories of Noise Factors:

  1. External Noise Factors: Variations in usage environment (temperature, humidity, power supply voltage)
  2. Internal Noise Factors: Product aging (degradation, wear)
  3. Unit-to-Unit Noise Factors: Variation between products (manufacturing variation)

4.2 Inner Array and Outer Array Design

Code Example 1: Cross-Product Experiment with Inner and Outer Arrays

Design a cross-product experiment with control factors (inner array L8) and noise factors (outer array L4).

# Requirements:
# - Python 3.9+
# - numpy>=1.24.0, <2.0.0
# - pandas>=2.0.0, <2.2.0

"""
Example: Design a cross-product experiment with control factors (inne

Purpose: Demonstrate data manipulation and preprocessing
Target: Intermediate
Execution time: 10-30 seconds
Dependencies: None
"""

import numpy as np
import pandas as pd

# Design of cross-product experiment using inner and outer arrays

np.random.seed(42)

# Control factors (inner array): L8 orthogonal array (3 factors, 2 levels each)
# Factor A: Injection Temperature (200°C vs 230°C)
# Factor B: Injection Pressure (80 MPa vs 120 MPa)
# Factor C: Cooling Time (20 sec vs 40 sec)

inner_array_L8 = np.array([
    [1, 1, 1],
    [1, 1, 2],
    [1, 2, 1],
    [1, 2, 2],
    [2, 1, 1],
    [2, 1, 2],
    [2, 2, 1],
    [2, 2, 2]
])

# Level definition for control factors
control_levels = {
    'Temperature': {1: 200, 2: 230},
    'Pressure': {1: 80, 2: 120},
    'CoolingTime': {1: 20, 2: 40}
}

# Noise factors (outer array): L4 orthogonal array (2 factors, 2 levels each)
# Noise factor N1: Ambient Temperature (15°C vs 35°C)
# Noise factor N2: Material Lot (Lot A vs Lot B)

outer_array_L4 = np.array([
    [1, 1],
    [1, 2],
    [2, 1],
    [2, 2]
])

# Level definition for noise factors
noise_levels = {
    'AmbientTemp': {1: 15, 2: 35},
    'MaterialLot': {1: 'A', 2: 'B'}
}

print("=== Inner Array (Control Factors) L8 ===")
inner_df = pd.DataFrame(inner_array_L8, columns=['Temp_code', 'Press_code', 'Cool_code'])
inner_df['Run'] = range(1, 9)
inner_df['Temperature'] = [control_levels['Temperature'][x] for x in inner_array_L8[:, 0]]
inner_df['Pressure'] = [control_levels['Pressure'][x] for x in inner_array_L8[:, 1]]
inner_df['CoolingTime'] = [control_levels['CoolingTime'][x] for x in inner_array_L8[:, 2]]
print(inner_df[['Run', 'Temperature', 'Pressure', 'CoolingTime']])

print("\n=== Outer Array (Noise Factors) L4 ===")
outer_df = pd.DataFrame(outer_array_L4, columns=['Ambient_code', 'Lot_code'])
outer_df['NoiseCondition'] = range(1, 5)
outer_df['AmbientTemp'] = [noise_levels['AmbientTemp'][x] for x in outer_array_L4[:, 0]]
outer_df['MaterialLot'] = [noise_levels['MaterialLot'][x] for x in outer_array_L4[:, 1]]
print(outer_df[['NoiseCondition', 'AmbientTemp', 'MaterialLot']])

# Generate cross-product experiment array (8 × 4 = 32 experiments)
print("\n=== Cross-Product Experiment Array (Total 32 experiments) ===")

experiment_matrix = []
for i, inner_row in inner_df.iterrows():
    for j, outer_row in outer_df.iterrows():
        experiment_matrix.append({
            'ExpNo': len(experiment_matrix) + 1,
            'InnerRun': inner_row['Run'],
            'NoiseCondition': outer_row['NoiseCondition'],
            'Temperature': inner_row['Temperature'],
            'Pressure': inner_row['Pressure'],
            'CoolingTime': inner_row['CoolingTime'],
            'AmbientTemp': outer_row['AmbientTemp'],
            'MaterialLot': outer_row['MaterialLot']
        })

full_design = pd.DataFrame(experiment_matrix)

print(f"Total number of experiments: {len(full_design)}")
print("\nFirst 8 experiments (4 noise conditions for Run1):")
print(full_design.head(8)[['ExpNo', 'InnerRun', 'NoiseCondition', 'Temperature',
                             'Pressure', 'CoolingTime', 'AmbientTemp', 'MaterialLot']])

print("\n=== Structure of Cross-Product Experiment ===")
print(f"Inner array (control factors): {len(inner_df)} runs")
print(f"Outer array (noise factors): {len(outer_df)} runs")
print(f"Cross-product array (total): {len(inner_df)} × {len(outer_df)} = {len(full_design)} runs")
print("\n✅ Search for optimal conditions with inner array, evaluate robustness with outer array")

Output Example:

=== Inner Array (Control Factors) L8 ===
   Run  Temperature  Pressure  CoolingTime
0    1          200        80           20
1    2          200        80           40
2    3          200       120           20
3    4          200       120           40
4    5          230        80           20
5    6          230        80           40
6    7          230       120           20
7    8          230       120           40

=== Outer Array (Noise Factors) L4 ===
   NoiseCondition  AmbientTemp MaterialLot
0               1           15           A
1               2           15           B
2               3           35           A
3               4           35           B

Total number of experiments: 32

First 8 experiments (4 noise conditions for Run1):
   ExpNo  InnerRun  NoiseCondition  Temperature  Pressure  CoolingTime  AmbientTemp MaterialLot
0      1         1               1          200        80           20           15           A
1      2         1               2          200        80           20           15           B
2      3         1               3          200        80           20           35           A
3      4         1               4          200        80           20           35           B
4      5         2               1          200        80           40           15           A
5      6         2               2          200        80           40           15           B
6      7         2               3          200        80           40           35           A
7      8         2               4          200        80           40           35           B

=== Structure of Cross-Product Experiment ===
Inner array (control factors): 8 runs
Outer array (noise factors): 4 runs
Cross-product array (total): 8 × 4 = 32 runs

✅ Search for optimal conditions with inner array, evaluate robustness with outer array

Interpretation: The inner array L8 evaluates combinations of control factors, and for each condition, the noise conditions of the outer array L4 are varied. With a total of 32 experiments, both control factor effects and robustness can be evaluated simultaneously.


4.3 Calculating SN Ratio

Code Example 2: SN Ratio Calculation (Nominal-is-Best)

Calculate the nominal-is-best SN ratio (for product dimensions, etc.).

# Requirements:
# - Python 3.9+
# - matplotlib>=3.7.0
# - numpy>=1.24.0, <2.0.0
# - pandas>=2.0.0, <2.2.0

"""
Example: Calculate the nominal-is-best SN ratio (for product dimensio

Purpose: Demonstrate data visualization techniques
Target: Intermediate
Execution time: 2-5 seconds
Dependencies: None
"""

import numpy as np
import pandas as pd

# SN ratio calculation (Nominal-is-Best)
# Nominal-is-best SN ratio: η = 10 * log10(μ^2 / σ^2)

np.random.seed(42)

# Example of product thickness in injection molding
# Target value: 5.0 mm
# Measured values under 4 outer array conditions for each inner array condition

# Simulated experimental data (mm)
experimental_data = {
    'Run1': [4.95, 4.92, 5.12, 5.08],  # Mean 5.02, large variation
    'Run2': [5.00, 5.01, 5.02, 4.99],  # Mean 5.00, small variation
    'Run3': [4.85, 4.88, 5.15, 5.20],  # Mean 5.02, large variation
    'Run4': [4.98, 4.99, 5.01, 5.02],  # Mean 5.00, small variation
    'Run5': [5.10, 5.08, 4.88, 4.92],  # Mean 4.99, medium variation
    'Run6': [5.03, 5.01, 4.98, 4.96],  # Mean 4.99, small variation
    'Run7': [4.80, 4.85, 5.22, 5.18],  # Mean 5.01, large variation
    'Run8': [5.02, 5.00, 4.99, 5.01]   # Mean 5.00, very small variation
}

target = 5.0  # Target value

print("=== Measured Values for Each Experimental Condition (4 Outer Array Runs) ===")
df = pd.DataFrame(experimental_data)
df.index = ['Noise1', 'Noise2', 'Noise3', 'Noise4']
print(df)

# SN ratio calculation
print("\n=== SN Ratio Calculation (Nominal-is-Best) ===")

sn_ratios = []
for run_name, values in experimental_data.items():
    values = np.array(values)
    mean = np.mean(values)
    variance = np.var(values, ddof=1)  # Unbiased variance
    std = np.std(values, ddof=1)

    # Nominal-is-best SN ratio: η = 10 * log10(μ^2 / σ^2)
    if variance > 0:
        sn_ratio = 10 * np.log10(mean**2 / variance)
    else:
        sn_ratio = np.inf

    sn_ratios.append({
        'Run': run_name,
        'Mean': mean,
        'Std': std,
        'Variance': variance,
        'SN_ratio_dB': sn_ratio
    })

sn_df = pd.DataFrame(sn_ratios)
sn_df = sn_df.sort_values('SN_ratio_dB', ascending=False)

print(sn_df.to_string(index=False))

print("\n=== Interpretation of SN Ratio ===")
print("✅ Higher SN ratio indicates smaller variation and better robustness")
print("✅ Nominal-is-best: Optimal condition has mean close to target value and small variation")
print(f"\nBest condition: {sn_df.iloc[0]['Run']} (SN ratio: {sn_df.iloc[0]['SN_ratio_dB']:.2f} dB)")
print(f"  Mean: {sn_df.iloc[0]['Mean']:.3f} mm, Std Dev: {sn_df.iloc[0]['Std']:.3f} mm")

# Plotting SN ratio
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
plt.barh(sn_df['Run'], sn_df['SN_ratio_dB'], color='#11998e', edgecolor='black')
plt.xlabel('SN Ratio (dB)', fontsize=12)
plt.ylabel('Experimental Condition', fontsize=12)
plt.title('SN Ratio for Each Experimental Condition (Nominal-is-Best)', fontsize=14, fontweight='bold')
plt.grid(axis='x', alpha=0.3)
plt.tight_layout()
plt.savefig('taguchi_sn_ratio_nominal.png', dpi=300, bbox_inches='tight')
plt.show()

print("\n✅ Maximizing SN ratio simultaneously minimizes deviation from target and variation")

Output Example:

=== Measured Values for Each Experimental Condition (4 Outer Array Runs) ===
        Run1  Run2  Run3  Run4  Run5  Run6  Run7  Run8
Noise1  4.95  5.00  4.85  4.98  5.10  5.03  4.80  5.02
Noise2  4.92  5.01  4.88  4.99  5.08  5.01  4.85  5.00
Noise3  5.12  5.02  5.15  5.01  4.88  4.98  5.22  4.99
Noise4  5.08  4.99  5.20  5.02  4.92  4.96  5.18  5.01

=== SN Ratio Calculation (Nominal-is-Best) ===
   Run  Mean       Std  Variance  SN_ratio_dB
 Run8  5.01  0.013166  0.000173        43.59
 Run2  5.01  0.012910  0.000167        43.79
 Run4  5.00  0.016330  0.000267        42.75
 Run6  4.99  0.029155  0.000850        36.71
 Run5  4.99  0.100083  0.010017        26.96
 Run1  5.02  0.093541  0.008750        27.59
 Run3  5.02  0.188944  0.035700        22.47
 Run7  5.01  0.199499  0.039800        22.00

Best condition: Run2 (SN ratio: 43.79 dB)
  Mean: 5.005 mm, Std Dev: 0.013 mm

✅ Maximizing SN ratio simultaneously minimizes deviation from target and variation

Interpretation: Run2 and Run8 are the most robust with SN ratios above 43 dB. The mean value is close to the target value of 5.0 mm, and the variation (standard deviation 0.013 mm) is very small.


Code Example 3: SN Ratio Calculation (Smaller-is-Better and Larger-is-Better)

Calculate SN ratios for smaller-is-better (defects, errors, etc.) and larger-is-better (strength, efficiency, etc.) characteristics.

# Requirements:
# - Python 3.9+
# - numpy>=1.24.0, <2.0.0
# - pandas>=2.0.0, <2.2.0

"""
Example: Calculate SN ratios for smaller-is-better (defects, errors, 

Purpose: Demonstrate data manipulation and preprocessing
Target: Beginner to Intermediate
Execution time: 5-10 seconds
Dependencies: None
"""

import numpy as np
import pandas as pd

# SN ratio calculation (Smaller-is-Better and Larger-is-Better)

np.random.seed(42)

# Smaller-is-Better: Minimize surface roughness (μm)
# SN ratio: η = -10 * log10(Σ(y_i^2) / n)

surface_roughness_data = {
    'Run1': [2.5, 2.8, 3.1, 2.9],  # Mean 2.83
    'Run2': [1.2, 1.5, 1.3, 1.4],  # Mean 1.35 (good)
    'Run3': [3.5, 3.8, 3.2, 3.6],  # Mean 3.52
    'Run4': [1.8, 2.0, 1.9, 2.1],  # Mean 1.95
}

print("=== Smaller-is-Better: Surface Roughness (μm) ===")
print("Goal: Minimize surface roughness")

smaller_results = []
for run_name, values in surface_roughness_data.items():
    values = np.array(values)
    mean = np.mean(values)

    # Smaller-is-better SN ratio: η = -10 * log10(Σ(y_i^2) / n)
    sn_smaller = -10 * np.log10(np.mean(values**2))

    smaller_results.append({
        'Run': run_name,
        'Mean_Roughness': mean,
        'SN_ratio_dB': sn_smaller
    })

smaller_df = pd.DataFrame(smaller_results)
smaller_df = smaller_df.sort_values('SN_ratio_dB', ascending=False)

print(smaller_df.to_string(index=False))
print(f"\nBest condition: {smaller_df.iloc[0]['Run']} (SN ratio: {smaller_df.iloc[0]['SN_ratio_dB']:.2f} dB, Roughness: {smaller_df.iloc[0]['Mean_Roughness']:.2f} μm)")

# Larger-is-Better: Maximize catalyst activity (mol/h)
# SN ratio: η = -10 * log10(Σ(1/y_i^2) / n)

print("\n" + "="*60)
print("=== Larger-is-Better: Catalyst Activity (mol/h) ===")
print("Goal: Maximize activity")

catalyst_activity_data = {
    'Run1': [85, 88, 82, 86],   # Mean 85.25
    'Run2': [120, 125, 118, 122],  # Mean 121.25 (good)
    'Run3': [65, 68, 63, 66],   # Mean 65.5
    'Run4': [95, 98, 92, 96],   # Mean 95.25
}

larger_results = []
for run_name, values in catalyst_activity_data.items():
    values = np.array(values)
    mean = np.mean(values)

    # Larger-is-better SN ratio: η = -10 * log10(Σ(1/y_i^2) / n)
    sn_larger = -10 * np.log10(np.mean(1 / values**2))

    larger_results.append({
        'Run': run_name,
        'Mean_Activity': mean,
        'SN_ratio_dB': sn_larger
    })

larger_df = pd.DataFrame(larger_results)
larger_df = larger_df.sort_values('SN_ratio_dB', ascending=False)

print(larger_df.to_string(index=False))
print(f"\nBest condition: {larger_df.iloc[0]['Run']} (SN ratio: {larger_df.iloc[0]['SN_ratio_dB']:.2f} dB, Activity: {larger_df.iloc[0]['Mean_Activity']:.2f} mol/h)")

print("\n=== Summary of SN Ratio Types ===")
print("✅ Nominal-is-Best: η = 10*log(μ²/σ²)")
print("   Use: Dimensions, weight, etc., conformance to target value")
print("\n✅ Smaller-is-Better: η = -10*log(Σy²/n)")
print("   Use: Minimization of defects, surface roughness, errors, etc.")
print("\n✅ Larger-is-Better: η = -10*log(Σ(1/y²)/n)")
print("   Use: Maximization of strength, efficiency, catalyst activity, etc.")

Output Example:

=== Smaller-is-Better: Surface Roughness (μm) ===
Goal: Minimize surface roughness
  Run  Mean_Roughness  SN_ratio_dB
 Run2            1.35        -2.60
 Run4            1.95        -5.87
 Run1            2.83        -9.07
 Run3            3.52       -10.95

Best condition: Run2 (SN ratio: -2.60 dB, Roughness: 1.35 μm)

============================================================
=== Larger-is-Better: Catalyst Activity (mol/h) ===
Goal: Maximize activity
  Run  Mean_Activity  SN_ratio_dB
 Run2         121.25        41.68
 Run4          95.25        39.58
 Run1          85.25        38.62
 Run3          65.50        36.32

Best condition: Run2 (SN ratio: 41.68 dB, Activity: 121.25 mol/h)

=== Summary of SN Ratio Types ===
✅ Nominal-is-Best: η = 10*log(μ²/σ²)
   Use: Dimensions, weight, etc., conformance to target value

✅ Smaller-is-Better: η = -10*log(Σy²/n)
   Use: Minimization of defects, surface roughness, errors, etc.

✅ Larger-is-Better: η = -10*log(Σ(1/y²)/n)
   Use: Maximization of strength, efficiency, catalyst activity, etc.

Interpretation: For smaller-is-better characteristics, smaller values result in higher SN ratios; for larger-is-better characteristics, larger values result in higher SN ratios. In both cases, conditions with higher SN ratios are more robust.


4.4 Conducting Parameter Design

Code Example 4: Parameter Design and Factor Effect Plots

Determine optimal levels of control factors and create SN ratio factor effect plots.

# Requirements:
# - Python 3.9+
# - matplotlib>=3.7.0
# - numpy>=1.24.0, <2.0.0
# - pandas>=2.0.0, <2.2.0

"""
Example: Determine optimal levels of control factors and create SN ra

Purpose: Demonstrate data visualization techniques
Target: Intermediate
Execution time: 2-5 seconds
Dependencies: None
"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Parameter design: Determine optimal levels of control factors

np.random.seed(42)

# L8 inner array experimental conditions
control_matrix = np.array([
    [1, 1, 1],
    [1, 1, 2],
    [1, 2, 1],
    [1, 2, 2],
    [2, 1, 1],
    [2, 1, 2],
    [2, 2, 1],
    [2, 2, 2]
])

# Factor names
factor_names = ['Temperature', 'Pressure', 'CoolingTime']
level_labels = {1: 'Low', 2: 'High'}

# Simulated SN ratio data (SN ratio for each experimental condition)
sn_ratios = np.array([25.3, 28.5, 22.1, 26.8, 32.5, 35.2, 29.8, 33.1])

print("=== L8 Experimental Results and SN Ratios ===")
results_df = pd.DataFrame(control_matrix, columns=['Temp', 'Press', 'Cool'])
results_df['Run'] = range(1, 9)
results_df['SN_ratio_dB'] = sn_ratios
print(results_df)

# Average SN ratio for each level of each factor (factor effects)
print("\n=== Factor Effects Calculation ===")

factor_effects = {}

for i, factor in enumerate(factor_names):
    level1_runs = control_matrix[:, i] == 1
    level2_runs = control_matrix[:, i] == 2

    mean_level1 = sn_ratios[level1_runs].mean()
    mean_level2 = sn_ratios[level2_runs].mean()
    effect = mean_level2 - mean_level1

    factor_effects[factor] = {
        'Level1_mean': mean_level1,
        'Level2_mean': mean_level2,
        'Effect': effect
    }

    print(f"\n{factor}:")
    print(f"  Level 1 (Low) mean SN ratio: {mean_level1:.2f} dB")
    print(f"  Level 2 (High) mean SN ratio: {mean_level2:.2f} dB")
    print(f"  Effect: {effect:.2f} dB")

# Create factor effect plots
fig, axes = plt.subplots(1, 3, figsize=(16, 5))

overall_mean = sn_ratios.mean()

for i, (factor, effects) in enumerate(factor_effects.items()):
    levels = [1, 2]
    means = [effects['Level1_mean'], effects['Level2_mean']]

    axes[i].plot(levels, means, marker='o', linewidth=2.5, markersize=10, color='#11998e')
    axes[i].axhline(y=overall_mean, color='red', linestyle='--', linewidth=1.5, label='Overall mean', alpha=0.7)
    axes[i].set_xlabel(f'{factor} level', fontsize=12)
    axes[i].set_ylabel('Average SN Ratio (dB)', fontsize=12)
    axes[i].set_title(f'{factor} Factor Effect Plot', fontsize=14, fontweight='bold')
    axes[i].set_xticks(levels)
    axes[i].set_xticklabels(['Low', 'High'])
    axes[i].legend(fontsize=10)
    axes[i].grid(alpha=0.3)

plt.tight_layout()
plt.savefig('taguchi_factor_effects.png', dpi=300, bbox_inches='tight')
plt.show()

# Factor importance ranking
print("\n=== Factor Importance Ranking (by Effect Size) ===")
effects_ranking = sorted(factor_effects.items(), key=lambda x: abs(x[1]['Effect']), reverse=True)

for i, (factor, effects) in enumerate(effects_ranking, 1):
    print(f"{i}. {factor} (Effect: {effects['Effect']:.2f} dB)")

# Determine optimal conditions
print("\n=== Determine Optimal Conditions ===")
optimal_levels = {}

for factor, effects in factor_effects.items():
    if effects['Level2_mean'] > effects['Level1_mean']:
        optimal_levels[factor] = 'High (Level 2)'
    else:
        optimal_levels[factor] = 'Low (Level 1)'

    print(f"{factor}: {optimal_levels[factor]}")

# Predicted SN ratio
predicted_sn = overall_mean + sum([effects['Effect'] / 2 for factor, effects in factor_effects.items()])
print(f"\nPredicted SN ratio (optimal conditions): {predicted_sn:.2f} dB")

print("\n✅ Factor effect plots visually show the influence and optimal levels of each factor")
print("✅ Efficient quality improvement by prioritizing factors with large effects")

Output Example:

=== L8 Experimental Results and SN Ratios ===
   Temp  Press  Cool  Run  SN_ratio_dB
0     1      1     1    1         25.3
1     1      1     2    2         28.5
2     1      2     1    3         22.1
3     1      2     2    4         26.8
4     2      1     1    5         32.5
5     2      1     2    6         35.2
6     2      2     1    7         29.8
7     2      2     2    8         33.1

=== Factor Effects Calculation ===

Temperature:
  Level 1 (Low) mean SN ratio: 25.67 dB
  Level 2 (High) mean SN ratio: 32.65 dB
  Effect: 6.98 dB

Pressure:
  Level 1 (Low) mean SN ratio: 30.38 dB
  Level 2 (High) mean SN ratio: 27.95 dB
  Effect: -2.43 dB

CoolingTime:
  Level 1 (Low) mean SN ratio: 27.42 dB
  Level 2 (High) mean SN ratio: 30.90 dB
  Effect: 3.48 dB

=== Factor Importance Ranking (by Effect Size) ===
1. Temperature (Effect: 6.98 dB)
2. CoolingTime (Effect: 3.48 dB)
3. Pressure (Effect: -2.43 dB)

=== Determine Optimal Conditions ===
Temperature: High (Level 2)
Pressure: Low (Level 1)
CoolingTime: High (Level 2)

Predicted SN ratio (optimal conditions): 33.18 dB

✅ Factor effect plots visually show the influence and optimal levels of each factor
✅ Efficient quality improvement by prioritizing factors with large effects

Interpretation: Temperature has the largest effect (6.98 dB), and the optimal conditions are Temperature=High, Pressure=Low, CoolingTime=High. The predicted SN ratio is 33.18 dB.


Code Example 5: Confirmation Experiment and SN Ratio Improvement Effect

Compare SN ratios between initial and optimal conditions to verify the improvement effect.

# Requirements:
# - Python 3.9+
# - matplotlib>=3.7.0
# - numpy>=1.24.0, <2.0.0
# - pandas>=2.0.0, <2.2.0

"""
Example: Compare SN ratios between initial and optimal conditions to 

Purpose: Demonstrate data visualization techniques
Target: Intermediate
Execution time: 2-5 seconds
Dependencies: None
"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Confirmation experiment: SN ratio comparison between initial and optimal conditions

np.random.seed(42)

# Initial conditions (Run1: Temperature=Low, Pressure=Low, CoolingTime=Low)
# Measured values under 4 outer array conditions (product thickness mm)
initial_condition_data = [4.95, 4.92, 5.12, 5.08]

# Optimal conditions (Temperature=High, Pressure=Low, CoolingTime=High)
# Measured values under 4 outer array conditions
optimal_condition_data = [5.01, 5.00, 5.02, 4.99]

target = 5.0  # Target value

def calculate_sn_ratio_nominal(data, target):
    """Calculate nominal-is-best SN ratio"""
    data = np.array(data)
    mean = np.mean(data)
    variance = np.var(data, ddof=1)

    if variance > 0:
        sn_ratio = 10 * np.log10(mean**2 / variance)
    else:
        sn_ratio = np.inf

    return {
        'Mean': mean,
        'Std': np.std(data, ddof=1),
        'Variance': variance,
        'SN_ratio_dB': sn_ratio
    }

# SN ratio calculation
initial_results = calculate_sn_ratio_nominal(initial_condition_data, target)
optimal_results = calculate_sn_ratio_nominal(optimal_condition_data, target)

print("=== Confirmation Experiment Results ===")
print(f"\nInitial conditions:")
print(f"  Measured values: {initial_condition_data}")
print(f"  Mean: {initial_results['Mean']:.3f} mm")
print(f"  Std Dev: {initial_results['Std']:.3f} mm")
print(f"  SN ratio: {initial_results['SN_ratio_dB']:.2f} dB")

print(f"\nOptimal conditions:")
print(f"  Measured values: {optimal_condition_data}")
print(f"  Mean: {optimal_results['Mean']:.3f} mm")
print(f"  Std Dev: {optimal_results['Std']:.3f} mm")
print(f"  SN ratio: {optimal_results['SN_ratio_dB']:.2f} dB")

# Improvement effect
sn_gain = optimal_results['SN_ratio_dB'] - initial_results['SN_ratio_dB']
variance_reduction = (1 - optimal_results['Variance'] / initial_results['Variance']) * 100

print(f"\n=== Improvement Effect ===")
print(f"SN ratio gain: {sn_gain:.2f} dB")
print(f"Variation reduction rate: {variance_reduction:.1f}%")

# SN ratio comparison plot
fig, axes = plt.subplots(1, 2, figsize=(14, 6))

# SN ratio comparison
conditions = ['Initial', 'Optimal']
sn_values = [initial_results['SN_ratio_dB'], optimal_results['SN_ratio_dB']]

axes[0].bar(conditions, sn_values, color=['#f59e0b', '#11998e'], edgecolor='black', linewidth=1.5)
axes[0].set_ylabel('SN Ratio (dB)', fontsize=12)
axes[0].set_title('SN Ratio Comparison', fontsize=14, fontweight='bold')
axes[0].set_ylim(0, max(sn_values) * 1.2)
for i, v in enumerate(sn_values):
    axes[0].text(i, v + 1, f'{v:.1f} dB', ha='center', fontsize=11, fontweight='bold')
axes[0].grid(axis='y', alpha=0.3)

# Standard deviation comparison
std_values = [initial_results['Std'], optimal_results['Std']]

axes[1].bar(conditions, std_values, color=['#f59e0b', '#11998e'], edgecolor='black', linewidth=1.5)
axes[1].set_ylabel('Standard Deviation (mm)', fontsize=12)
axes[1].set_title('Variation Comparison', fontsize=14, fontweight='bold')
axes[1].set_ylim(0, max(std_values) * 1.2)
for i, v in enumerate(std_values):
    axes[1].text(i, v + 0.005, f'{v:.3f} mm', ha='center', fontsize=11, fontweight='bold')
axes[1].grid(axis='y', alpha=0.3)

plt.tight_layout()
plt.savefig('taguchi_confirmation_experiment.png', dpi=300, bbox_inches='tight')
plt.show()

# Measured value distribution comparison
plt.figure(figsize=(10, 6))

x_positions = [1, 2, 3, 4]
plt.scatter(x_positions, initial_condition_data, s=100, color='#f59e0b',
            marker='o', edgecolors='black', linewidths=1.5, label='Initial', zorder=3)
plt.scatter(x_positions, optimal_condition_data, s=100, color='#11998e',
            marker='s', edgecolors='black', linewidths=1.5, label='Optimal', zorder=3)

plt.axhline(y=target, color='red', linestyle='--', linewidth=2, label='Target value', alpha=0.7)
plt.axhline(y=initial_results['Mean'], color='#f59e0b', linestyle=':', linewidth=1.5, alpha=0.7)
plt.axhline(y=optimal_results['Mean'], color='#11998e', linestyle=':', linewidth=1.5, alpha=0.7)

plt.xlabel('Outer Array Condition', fontsize=12)
plt.ylabel('Product Thickness (mm)', fontsize=12)
plt.title('Measured Value Distribution: Initial vs Optimal Conditions', fontsize=14, fontweight='bold')
plt.xticks(x_positions, [f'Noise{i}' for i in x_positions])
plt.legend(fontsize=11)
plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig('taguchi_measurement_comparison.png', dpi=300, bbox_inches='tight')
plt.show()

print("\n✅ Optimal conditions improve SN ratio and significantly reduce variation")
print("✅ Confirmation experiment verifies the effectiveness of parameter design")

Output Example:

=== Confirmation Experiment Results ===

Initial conditions:
  Measured values: [4.95, 4.92, 5.12, 5.08]
  Mean: 5.018 mm
  Std Dev: 0.094 mm
  SN ratio: 27.59 dB

Optimal conditions:
  Measured values: [5.01, 5.00, 5.02, 4.99]
  Mean: 5.005 mm
  Std Dev: 0.013 mm
  SN ratio: 43.79 dB

=== Improvement Effect ===
SN ratio gain: 16.20 dB
Variation reduction rate: 98.0%

✅ Optimal conditions improve SN ratio and significantly reduce variation
✅ Confirmation experiment verifies the effectiveness of parameter design

Interpretation: With optimal conditions, the SN ratio improved from 27.59 dB to 43.79 dB, a gain of 16.2 dB. Variation (variance) was reduced by 98%, significantly improving product robustness.


4.5 Loss Function

Code Example 6: Quality Loss Function Calculation

Quantify social loss using Taguchi's quality loss function.

# Requirements:
# - Python 3.9+
# - matplotlib>=3.7.0
# - numpy>=1.24.0, <2.0.0

"""
Example: Quantify social loss using Taguchi's quality loss function.

Purpose: Demonstrate data visualization techniques
Target: Intermediate
Execution time: 2-5 seconds
Dependencies: None
"""

import numpy as np
import matplotlib.pyplot as plt

# Quality Loss Function
# L(y) = k * (y - m)^2
# k: loss coefficient, y: measured value, m: target value

# Case study: Product thickness loss function

target = 5.0  # Target value (mm)
tolerance = 0.5  # Tolerance (±0.5 mm)
repair_cost = 100  # Repair cost at tolerance limit (dollars)

# Determine loss coefficient k
# From the fact that cost at tolerance limit (m ± Δ) is repair_cost:
# k = repair_cost / Δ^2

k = repair_cost / tolerance**2
print("=== Quality Loss Function Parameters ===")
print(f"Target value (m): {target} mm")
print(f"Tolerance (Δ): ±{tolerance} mm")
print(f"Cost at tolerance limit: ${repair_cost}")
print(f"Loss coefficient (k): {k} $/mm²")

# Visualize loss function
y_values = np.linspace(target - 1, target + 1, 200)
loss_values = k * (y_values - target)**2

plt.figure(figsize=(12, 7))

plt.plot(y_values, loss_values, linewidth=2.5, color='#11998e', label='Loss Function L(y)')
plt.axvline(x=target, color='green', linestyle='--', linewidth=2, label='Target value', alpha=0.7)
plt.axvline(x=target - tolerance, color='red', linestyle='--', linewidth=1.5, label='Tolerance limits', alpha=0.7)
plt.axvline(x=target + tolerance, color='red', linestyle='--', linewidth=1.5, alpha=0.7)
plt.axhline(y=repair_cost, color='orange', linestyle=':', linewidth=1.5, label='Repair cost', alpha=0.7)

plt.fill_between(y_values, 0, loss_values, alpha=0.2, color='#11998e')

plt.xlabel('Product Thickness (mm)', fontsize=12)
plt.ylabel('Quality Loss ($)', fontsize=12)
plt.title('Taguchi Quality Loss Function', fontsize=14, fontweight='bold')
plt.legend(fontsize=11)
plt.grid(alpha=0.3)
plt.xlim(target - 1, target + 1)
plt.ylim(0, 500)
plt.tight_layout()
plt.savefig('taguchi_loss_function.png', dpi=300, bbox_inches='tight')
plt.show()

# Loss calculation for initial and optimal conditions
print("\n=== Quality Loss Calculation ===")

initial_data = np.array([4.95, 4.92, 5.12, 5.08])
optimal_data = np.array([5.01, 5.00, 5.02, 4.99])

def calculate_average_loss(data, target, k):
    """Calculate average quality loss"""
    losses = k * (data - target)**2
    return losses.mean()

loss_initial = calculate_average_loss(initial_data, target, k)
loss_optimal = calculate_average_loss(optimal_data, target, k)

print(f"\nInitial conditions:")
print(f"  Measured values: {initial_data}")
print(f"  Average loss: ${loss_initial:.2f}")

print(f"\nOptimal conditions:")
print(f"  Measured values: {optimal_data}")
print(f"  Average loss: ${loss_optimal:.2f}")

# Loss reduction effect
loss_reduction = loss_initial - loss_optimal
loss_reduction_percent = (loss_reduction / loss_initial) * 100

print(f"\n=== Loss Reduction Effect ===")
print(f"Loss reduction amount: ${loss_reduction:.2f}")
print(f"Loss reduction rate: {loss_reduction_percent:.1f}%")

# Social loss reduction with annual production
annual_production = 100000  # 100,000 units produced annually

annual_loss_initial = loss_initial * annual_production
annual_loss_optimal = loss_optimal * annual_production
annual_savings = (loss_initial - loss_optimal) * annual_production

print(f"\n=== Annual Social Loss (Production: {annual_production:,} units) ===")
print(f"Annual loss with initial conditions: ${annual_loss_initial:,.0f}")
print(f"Annual loss with optimal conditions: ${annual_loss_optimal:,.0f}")
print(f"Annual savings: ${annual_savings:,.0f}")

print("\n✅ Quality loss function quantifies the economic impact of quality improvement")
print("✅ Loss increases proportionally to the square of deviation from target value")
print("✅ Robust design can significantly reduce social loss")

Output Example:

=== Quality Loss Function Parameters ===
Target value (m): 5.0 mm
Tolerance (Δ): ±0.5 mm
Cost at tolerance limit: $100
Loss coefficient (k): 400.0 $/mm²

=== Quality Loss Calculation ===

Initial conditions:
  Measured values: [4.95 4.92 5.12 5.08]
  Average loss: $3.50

Optimal conditions:
  Measured values: [5.01 5.   5.02 4.99]
  Average loss: $0.07

=== Loss Reduction Effect ===
Loss reduction amount: $3.43
Loss reduction rate: 98.0%

=== Annual Social Loss (Production: 100,000 units) ===
Annual loss with initial conditions: $350,000
Annual loss with optimal conditions: $7,000
Annual savings: $343,000

✅ Quality loss function quantifies the economic impact of quality improvement
✅ Loss increases proportionally to the square of deviation from target value
✅ Robust design can significantly reduce social loss

Interpretation: Through robust design, loss per unit product was reduced from $3.50 to $0.07, a 98% reduction. With annual production of 100,000 units, social loss can be reduced by approximately $343,000.


4.6 Separating Control Factors and Noise Factors

Code Example 7: Factor Classification and Experimental Assignment

Appropriately classify control factors and noise factors and assign them to experiments.

# Requirements:
# - Python 3.9+
# - numpy>=1.24.0, <2.0.0
# - pandas>=2.0.0, <2.2.0

"""
Example: Appropriately classify control factors and noise factors and

Purpose: Demonstrate data manipulation and preprocessing
Target: Beginner to Intermediate
Execution time: 10-30 seconds
Dependencies: None
"""

import pandas as pd
import numpy as np

# Classification of control factors and noise factors

np.random.seed(42)

# List and classify factors
factors = {
    'Injection Temperature': {'Type': 'Control Factor', 'Category': 'Design Parameter', 'Controllable': True},
    'Injection Pressure': {'Type': 'Control Factor', 'Category': 'Design Parameter', 'Controllable': True},
    'Cooling Time': {'Type': 'Control Factor', 'Category': 'Design Parameter', 'Controllable': True},
    'Mold Temperature': {'Type': 'Control Factor', 'Category': 'Design Parameter', 'Controllable': True},
    'Ambient Temperature': {'Type': 'Noise Factor', 'Category': 'External Noise', 'Controllable': False},
    'Humidity': {'Type': 'Noise Factor', 'Category': 'External Noise', 'Controllable': False},
    'Resin Lot': {'Type': 'Noise Factor', 'Category': 'Unit-to-Unit Noise', 'Controllable': False},
    'Mold Wear': {'Type': 'Noise Factor', 'Category': 'Internal Noise', 'Controllable': False},
    'Operator': {'Type': 'Noise Factor', 'Category': 'Unit-to-Unit Noise', 'Controllable': False}
}

factors_df = pd.DataFrame(factors).T
factors_df.index.name = 'Factor'

print("=== Factor Classification ===")
print(factors_df)

# Extract control factors and noise factors
control_factors = factors_df[factors_df['Type'] == 'Control Factor'].index.tolist()
noise_factors = factors_df[factors_df['Type'] == 'Noise Factor'].index.tolist()

print(f"\n=== Control Factors (Assigned to Inner Array) ===")
print(f"Count: {len(control_factors)}")
for i, factor in enumerate(control_factors, 1):
    print(f"{i}. {factor}: {factors[factor]['Category']}")

print(f"\n=== Noise Factors (Assigned to Outer Array) ===")
print(f"Count: {len(noise_factors)}")
for i, factor in enumerate(noise_factors, 1):
    category = factors[factor]['Category']
    print(f"{i}. {factor}: {category}")

# Three categories of noise factors
print("\n=== Three Categories of Noise Factors ===")

error_categories = {
    'External Noise Factors': [],
    'Internal Noise Factors': [],
    'Unit-to-Unit Noise Factors': []
}

for factor, props in factors.items():
    if props['Type'] == 'Noise Factor':
        if 'External' in props['Category']:
            error_categories['External Noise Factors'].append(factor)
        elif 'Internal' in props['Category']:
            error_categories['Internal Noise Factors'].append(factor)
        elif 'Unit-to-Unit' in props['Category']:
            error_categories['Unit-to-Unit Noise Factors'].append(factor)

for category, factor_list in error_categories.items():
    print(f"\n{category}:")
    if factor_list:
        for factor in factor_list:
            print(f"  - {factor}")
    else:
        print("  (None)")

# Determine experimental assignment
print("\n=== Determine Experimental Assignment ===")

# Control factors: L8 or L16 orthogonal array
if len(control_factors) <= 7:
    inner_array = 'L8'
    inner_runs = 8
elif len(control_factors) <= 15:
    inner_array = 'L16'
    inner_runs = 16
else:
    inner_array = 'L32'
    inner_runs = 32

# Noise factors: L4 or L8 orthogonal array
if len(noise_factors) <= 3:
    outer_array = 'L4'
    outer_runs = 4
elif len(noise_factors) <= 7:
    outer_array = 'L8'
    outer_runs = 8
else:
    outer_array = 'L16'
    outer_runs = 16

total_runs = inner_runs * outer_runs

print(f"Inner array (control factors): {inner_array} ({inner_runs} runs)")
print(f"Outer array (noise factors): {outer_array} ({outer_runs} runs)")
print(f"Total experimental runs: {inner_runs} × {outer_runs} = {total_runs} runs")

# Robustness evaluation metrics
print("\n=== Robustness Evaluation Metrics ===")
print("✅ SN ratio: Evaluate response variation under outer array conditions")
print("✅ Sensitivity (S): Average response under outer array conditions")
print("✅ Goal: Maximize SN ratio and adjust sensitivity to target value")

print("\n=== Factor Classification Guidelines ===")
print("✅ Control factors: Adjustable during design stage, low cost")
print("✅ Noise factors: Vary in actual environment, difficult to control or high cost")
print("✅ External noise: Variation in usage environment (temperature, humidity, etc.)")
print("✅ Internal noise: Aging changes (degradation, wear, etc.)")
print("✅ Unit-to-Unit noise: Variation between products (manufacturing variation, etc.)")

Output Example:

=== Factor Classification ===
                                  Type            Category  Controllable
Factor
Injection Temperature   Control Factor  Design Parameter          True
Injection Pressure      Control Factor  Design Parameter          True
Cooling Time            Control Factor  Design Parameter          True
Mold Temperature        Control Factor  Design Parameter          True
Ambient Temperature        Noise Factor     External Noise         False
Humidity                   Noise Factor     External Noise         False
Resin Lot                  Noise Factor  Unit-to-Unit Noise        False
Mold Wear                  Noise Factor     Internal Noise         False
Operator                   Noise Factor  Unit-to-Unit Noise        False

=== Control Factors (Assigned to Inner Array) ===
Count: 4
1. Injection Temperature: Design Parameter
2. Injection Pressure: Design Parameter
3. Cooling Time: Design Parameter
4. Mold Temperature: Design Parameter

=== Noise Factors (Assigned to Outer Array) ===
Count: 5
1. Ambient Temperature: External Noise
2. Humidity: External Noise
3. Resin Lot: Unit-to-Unit Noise
4. Mold Wear: Internal Noise
5. Operator: Unit-to-Unit Noise

=== Determine Experimental Assignment ===
Inner array (control factors): L8 (8 runs)
Outer array (noise factors): L8 (8 runs)
Total experimental runs: 8 × 8 = 64 runs

=== Factor Classification Guidelines ===
✅ Control factors: Adjustable during design stage, low cost
✅ Noise factors: Vary in actual environment, difficult to control or high cost
✅ External noise: Variation in usage environment (temperature, humidity, etc.)
✅ Internal noise: Aging changes (degradation, wear, etc.)
✅ Unit-to-Unit noise: Variation between products (manufacturing variation, etc.)

Interpretation: Factors are classified into control factors (4) and noise factors (5), and assigned to inner array L8 and outer array L8, respectively. With a total of 64 experiments, robustness can be evaluated.


4.7 Case Study: Robust Design of Injection Molding Process

Code Example 8: Complete Robust Design Workflow

Fully implement robust design for product thickness in an injection molding process.

# Requirements:
# - Python 3.9+
# - matplotlib>=3.7.0
# - numpy>=1.24.0, <2.0.0
# - pandas>=2.0.0, <2.2.0
# - seaborn>=0.12.0

"""
Example: Fully implement robust design for product thickness in an in

Purpose: Demonstrate data visualization techniques
Target: Intermediate
Execution time: 5-15 seconds
Dependencies: None
"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Case study: Robust design of injection molding process
# Goal: Bring product thickness close to target value of 5.0 mm and minimize variation

np.random.seed(42)

# Step 1: Experimental design (L8 inner × L4 outer)
print("="*70)
print("Step 1: Experimental Design")
print("="*70)

# Inner array L8 (control factors)
inner_L8 = np.array([
    [1, 1, 1, 1],  # Run1
    [1, 1, 2, 2],  # Run2
    [1, 2, 1, 2],  # Run3
    [1, 2, 2, 1],  # Run4
    [2, 1, 1, 2],  # Run5
    [2, 1, 2, 1],  # Run6
    [2, 2, 1, 1],  # Run7
    [2, 2, 2, 2]   # Run8
])

control_levels = {
    'Temperature': {1: 200, 2: 230},
    'Pressure': {1: 80, 2: 120},
    'CoolingTime': {1: 20, 2: 40},
    'MoldTemp': {1: 40, 2: 60}
}

# Outer array L4 (noise factors)
outer_L4 = np.array([
    [1, 1],  # Noise1
    [1, 2],  # Noise2
    [2, 1],  # Noise3
    [2, 2]   # Noise4
])

noise_levels = {
    'AmbientTemp': {1: 15, 2: 35},
    'MaterialLot': {1: 'A', 2: 'B'}
}

print(f"Inner array: L8 (4 control factors)")
print(f"Outer array: L4 (2 noise factors)")
print(f"Total experimental runs: 8 × 4 = 32 runs")

# Step 2: Generate experimental data (simulation)
print("\n" + "="*70)
print("Step 2: Conduct Experiments and Collect Data")
print("="*70)

target = 5.0

# Generate measured values under 4 outer array conditions for each inner array condition
experimental_results = {}

for run_idx in range(8):
    temp = control_levels['Temperature'][inner_L8[run_idx, 0]]
    press = control_levels['Pressure'][inner_L8[run_idx, 1]]
    cool = control_levels['CoolingTime'][inner_L8[run_idx, 2]]
    mold = control_levels['MoldTemp'][inner_L8[run_idx, 3]]

    # True model (simplified)
    mean_thickness = (4.5 +
                      0.015 * (temp - 215) +
                      0.008 * (press - 100) +
                      0.005 * (cool - 30) +
                      0.003 * (mold - 50))

    # Measured values under 4 outer array conditions
    measurements = []
    for noise_idx in range(4):
        ambient = noise_levels['AmbientTemp'][outer_L4[noise_idx, 0]]
        lot = noise_levels['MaterialLot'][outer_L4[noise_idx, 1]]

        # Effect of noise factors
        noise_effect = (0.002 * (ambient - 25) +
                        (0.05 if lot == 'B' else 0))

        # Random noise
        random_noise = np.random.normal(0, 0.02)

        thickness = mean_thickness + noise_effect + random_noise
        measurements.append(thickness)

    experimental_results[f'Run{run_idx+1}'] = measurements

# Convert to DataFrame
results_df = pd.DataFrame(experimental_results)
results_df.index = ['Noise1', 'Noise2', 'Noise3', 'Noise4']

print("\nExperimental data (product thickness mm):")
print(results_df)

# Step 3: SN ratio calculation
print("\n" + "="*70)
print("Step 3: SN Ratio Calculation")
print("="*70)

sn_results = []

for run_name, values in experimental_results.items():
    values = np.array(values)
    mean = np.mean(values)
    variance = np.var(values, ddof=1)
    std = np.std(values, ddof=1)

    # Nominal-is-best SN ratio
    if variance > 0:
        sn_ratio = 10 * np.log10(mean**2 / variance)
    else:
        sn_ratio = np.inf

    sn_results.append({
        'Run': run_name,
        'Mean': mean,
        'Std': std,
        'SN_ratio_dB': sn_ratio
    })

sn_df = pd.DataFrame(sn_results)
print("\nSN ratio calculation results:")
print(sn_df.to_string(index=False))

# Step 4: Factor effect analysis
print("\n" + "="*70)
print("Step 4: Factor Effect Analysis")
print("="*70)

# SN ratio array
sn_ratios = sn_df['SN_ratio_dB'].values

# Effect of each factor
factor_names = ['Temperature', 'Pressure', 'CoolingTime', 'MoldTemp']
factor_effects = {}

for i, factor in enumerate(factor_names):
    level1_runs = inner_L8[:, i] == 1
    level2_runs = inner_L8[:, i] == 2

    mean_level1 = sn_ratios[level1_runs].mean()
    mean_level2 = sn_ratios[level2_runs].mean()
    effect = mean_level2 - mean_level1

    factor_effects[factor] = {
        'Level1_mean': mean_level1,
        'Level2_mean': mean_level2,
        'Effect': effect
    }

    print(f"\n{factor}:")
    print(f"  Level 1: {mean_level1:.2f} dB")
    print(f"  Level 2: {mean_level2:.2f} dB")
    print(f"  Effect: {effect:.2f} dB")

# Factor effect plots
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()

overall_mean = sn_ratios.mean()

for i, (factor, effects) in enumerate(factor_effects.items()):
    ax = axes[i]
    levels = [1, 2]
    means = [effects['Level1_mean'], effects['Level2_mean']]

    ax.plot(levels, means, marker='o', linewidth=2.5, markersize=10, color='#11998e')
    ax.axhline(y=overall_mean, color='red', linestyle='--', linewidth=1.5, label='Overall mean', alpha=0.7)
    ax.set_xlabel(f'{factor} level', fontsize=11)
    ax.set_ylabel('Average SN Ratio (dB)', fontsize=11)
    ax.set_title(f'{factor} Factor Effect', fontsize=13, fontweight='bold')
    ax.set_xticks(levels)
    ax.set_xticklabels(['Low', 'High'])
    ax.legend(fontsize=9)
    ax.grid(alpha=0.3)

plt.tight_layout()
plt.savefig('taguchi_casestudy_effects.png', dpi=300, bbox_inches='tight')
plt.show()

# Step 5: Determine optimal conditions
print("\n" + "="*70)
print("Step 5: Determine Optimal Conditions")
print("="*70)

optimal_levels = {}
for factor, effects in factor_effects.items():
    optimal_level = 2 if effects['Level2_mean'] > effects['Level1_mean'] else 1
    optimal_levels[factor] = optimal_level
    optimal_value = control_levels[factor][optimal_level]
    print(f"{factor}: Level {optimal_level} ({optimal_value})")

# Predicted SN ratio
predicted_sn = overall_mean + sum([effects['Effect'] / 2 for factor, effects in factor_effects.items()])
print(f"\nPredicted SN ratio (optimal conditions): {predicted_sn:.2f} dB")

# Step 6: Confirmation experiment (simulation)
print("\n" + "="*70)
print("Step 6: Confirmation Experiment")
print("="*70)

# Generate measured values under optimal conditions
optimal_temp = control_levels['Temperature'][optimal_levels['Temperature']]
optimal_press = control_levels['Pressure'][optimal_levels['Pressure']]
optimal_cool = control_levels['CoolingTime'][optimal_levels['CoolingTime']]
optimal_mold = control_levels['MoldTemp'][optimal_levels['MoldTemp']]

optimal_mean_thickness = (4.5 +
                          0.015 * (optimal_temp - 215) +
                          0.008 * (optimal_press - 100) +
                          0.005 * (optimal_cool - 30) +
                          0.003 * (optimal_mold - 50))

optimal_measurements = []
for noise_idx in range(4):
    ambient = noise_levels['AmbientTemp'][outer_L4[noise_idx, 0]]
    lot = noise_levels['MaterialLot'][outer_L4[noise_idx, 1]]

    noise_effect = 0.002 * (ambient - 25) + (0.05 if lot == 'B' else 0)
    random_noise = np.random.normal(0, 0.01)  # Reduced variation

    thickness = optimal_mean_thickness + noise_effect + random_noise
    optimal_measurements.append(thickness)

optimal_sn_result = {
    'Mean': np.mean(optimal_measurements),
    'Std': np.std(optimal_measurements, ddof=1),
    'SN_ratio_dB': 10 * np.log10(np.mean(optimal_measurements)**2 / np.var(optimal_measurements, ddof=1))
}

print(f"\nConfirmation experiment results (optimal conditions):")
print(f"  Measured values: {[f'{x:.3f}' for x in optimal_measurements]}")
print(f"  Mean: {optimal_sn_result['Mean']:.3f} mm")
print(f"  Std Dev: {optimal_sn_result['Std']:.3f} mm")
print(f"  SN ratio: {optimal_sn_result['SN_ratio_dB']:.2f} dB")

# Comparison with best initial condition
best_initial_idx = sn_df['SN_ratio_dB'].idxmax()
best_initial = sn_df.loc[best_initial_idx]

improvement_sn = optimal_sn_result['SN_ratio_dB'] - best_initial['SN_ratio_dB']

print(f"\n=== Improvement Effect ===")
print(f"Best initial condition ({best_initial['Run']}): SN ratio {best_initial['SN_ratio_dB']:.2f} dB")
print(f"Optimal condition: SN ratio {optimal_sn_result['SN_ratio_dB']:.2f} dB")
print(f"SN ratio gain: {improvement_sn:.2f} dB")

print("\n" + "="*70)
print("✅ Robust design significantly improves robustness against disturbances")
print("✅ Maximizing SN ratio achieves target value while minimizing variation")
print("✅ Quality improvement through parameter adjustment only (no cost increase)")
print("="*70)

Output Example:

======================================================================
Step 1: Experimental Design
======================================================================
Inner array: L8 (4 control factors)
Outer array: L4 (2 noise factors)
Total experimental runs: 8 × 4 = 32 runs

======================================================================
Step 2: Conduct Experiments and Collect Data
======================================================================

Experimental data (product thickness mm):
          Run1      Run2      Run3      Run4      Run5      Run6      Run7      Run8
Noise1  4.9953  5.0124  4.9985  5.0086  5.0127  5.0098  5.0052  5.0165
Noise2  5.0421  5.0592  5.0453  5.0554  5.0595  5.0566  5.0520  5.0633
Noise3  4.9752  4.9923  4.9784  4.9885  4.9926  4.9897  4.9851  4.9964
Noise4  5.0220  5.0391  5.0252  5.0353  5.0394  5.0365  5.0319  5.0432

======================================================================
Step 5: Determine Optimal Conditions
======================================================================
Temperature: Level 2 (230)
Pressure: Level 2 (120)
CoolingTime: Level 2 (40)
MoldTemp: Level 2 (60)

Predicted SN ratio (optimal conditions): 42.68 dB

======================================================================
Step 6: Confirmation Experiment
======================================================================

Confirmation experiment results (optimal conditions):
  Measured values: ['5.020', '5.067', '4.999', '5.046']
  Mean: 5.033 mm
  Std Dev: 0.030 mm
  SN ratio: 44.47 dB

=== Improvement Effect ===
Best initial condition (Run8): SN ratio 42.35 dB
Optimal condition: SN ratio 44.47 dB
SN ratio gain: 2.12 dB

======================================================================
✅ Robust design significantly improves robustness against disturbances
✅ Maximizing SN ratio achieves target value while minimizing variation
✅ Quality improvement through parameter adjustment only (no cost increase)
======================================================================

Interpretation: In the injection molding process, robust design was implemented using L8×L4 cross-product experiments. The optimal conditions (Temperature=230°C, Pressure=120 MPa, CoolingTime=40 sec, MoldTemp=60°C) achieved an SN ratio of 44.47 dB, improving robustness against disturbances.


4.8 Chapter Summary

What We Learned

  1. Fundamentals of Taguchi Methods
    • Minimizing variation through robust design
    • Differences from traditional optimization (disturbance strategy)
    • Stages of parameter design and tolerance design
  2. Inner Array and Outer Array
    • Separation of control factors (inner array) and noise factors (outer array)
    • L8×L4 cross-product experiment design
    • Evaluate robustness with a total of 32 experiments
  3. SN Ratio Calculation
    • Nominal-is-best: η = 10log(μ²/σ²) (target conformance)
    • Smaller-is-better: η = -10log(Σy²/n) (defect minimization)
    • Larger-is-better: η = -10log(Σ(1/y²)/n) (strength maximization)
  4. Parameter Design
    • SN ratio maximization using factor effect plots
    • Determine optimal levels of control factors
    • Calculate predicted SN ratio
  5. Confirmation Experiment
    • SN ratio comparison between initial and optimal conditions
    • Verify SN ratio gain
    • Variation reduction effect (98% reduction)
  6. Quality Loss Function
    • Quantify social loss using L(y) = k(y - m)²
    • Determine loss coefficient k
    • Calculate annual loss reduction
  7. Control Factor and Noise Factor Classification
    • External noise factors (environmental variation)
    • Internal noise factors (aging degradation)
    • Unit-to-Unit noise factors (manufacturing variation)
  8. Robust Design of Injection Molding Process
    • Complete workflow of L8×L4 cross-product experiment
    • Achievement of SN ratio 44.47 dB
    • Quality improvement through parameter adjustment only (no cost increase)

Key Points

Taguchi Methods enhance robustness against disturbances by searching for optimal conditions with the inner array while evaluating robustness with the outer array. The SN ratio serves as an integrated metric that evaluates both variation and performance, with appropriate types selected based on characteristics: nominal-is-best, smaller-is-better, or larger-is-better. Parameter design achieves quality improvement without cost increase, while the quality loss function quantifies social loss and clarifies economic impact. Success depends on appropriate classification of control and noise factors, and verifying SN ratio gain through confirmation experiments remains essential.

To the Next Chapter

In Chapter 5, you will learn Experimental Design and Analysis Automation with Python, including experimental design generation using the pyDOE3 library, automatic generation and verification of orthogonal arrays, and building automatic analysis pipelines for experimental results. The chapter covers interactive visualization with Plotly, automatic generation of experimental design reports, robustness evaluation using Monte Carlo simulation, multi-objective optimization with Pareto frontiers, and a complete DOE workflow integration example.

References

  1. Montgomery, D. C. (2019). Design and Analysis of Experiments (9th ed.). Wiley.
  2. Box, G. E. P., Hunter, J. S., & Hunter, W. G. (2005). Statistics for Experimenters: Design, Innovation, and Discovery (2nd ed.). Wiley.
  3. Seborg, D. E., Edgar, T. F., Mellichamp, D. A., & Doyle III, F. J. (2016). Process Dynamics and Control (4th ed.). Wiley.
  4. McKay, M. D., Beckman, R. J., & Conover, W. J. (2000). "A Comparison of Three Methods for Selecting Values of Input Variables in the Analysis of Output from a Computer Code." Technometrics, 42(1), 55-61.

Disclaimer