Engineering — 2^k factorial design of experiments
A 2^3 full factorial on a laser weld, with the main effects and the interaction computed FROM the run matrix by selector rather than typed out of the analysis package. Typed FlowScript for reliability engineering. Keywords: FMEA, failure mode, RPN, reliability.
Make it your own.
// A 2^3 full factorial on a laser weld, with the main effects and the
// interaction computed FROM the run matrix by selector rather than typed
// out of the analysis package.
//
// The response is lap-shear strength of a copper tab to busbar weld in an
// EV battery module; the three factors are laser power, weld speed and
// shield-gas flow, each at two levels, three replicates per corner. Every
// effect below is a difference of means over the runs at the high and low
// level of one factor — which is what a main effect IS — so a corrected
// run moves the effect, its interval and the predicted optimum together.
//
// The interval is the same width for every effect because the design is
// balanced: half-width = t x 2s / sqrt(N), which depends on the design and
// the residual spread but not on which factor is being estimated. The
// figure shows the raw welds behind the largest of those effects, because
// a difference of means is only worth reading next to the spread it came
// from.
factorial_design weld_doe {
title: "Laser welding of Cu tab to busbar — 2^3 factorial"
design: "2^3 full factorial, 3 replicates, run order randomised, single operator, one coil of tab material"
response: "Lap-shear strength at break"
runs: 8
replicates: 3
total_runs: = runs * replicates
blocking: "None. All 24 welds cut from one coil on one shift."
pooled_sd: 14.6 N
df_error: 16
t_critical: 2.1199 source "Student t, two-sided 95%, 16 df"
effect_se: = 2 * pooled_sd / sqrt(total_runs)
effect_ci_half: = t_critical * effect_se
grand_mean: = mean(kind:doe_run, "strength") * 1[N]
specification: 450 N
}
factor laser_power {
of: weld_doe
name: "A — laser power"
low: 2.6 kW
high: 3.4 kW
rationale: "Below 2.6 kW the weld does not key into the busbar; above 3.4 kW spatter contaminates the cell can."
}
factor weld_speed {
of: weld_doe
name: "B — weld speed"
low: 120 mm/s
high: 180 mm/s
rationale: "180 mm/s is the takt the line needs; 120 mm/s is the current setting."
}
factor shield_gas {
of: weld_doe
name: "C — shield gas flow, argon"
low: 12 L/min
high: 20 L/min
rationale: "Argon is metered per module and is a real running cost, so the effect is worth knowing even if it is small."
}
// The run matrix. Levels are written as plain numbers so the selectors
// below can match on them; the units for those levels live on the factor
// blocks above, stated once each.
doe_run run_1 {
power: 2.6
speed: 120
gas: 12
strength: 412
sd: 13.0
n: 3
}
doe_run run_2 {
power: 3.4
speed: 120
gas: 12
strength: 486
sd: 16.0
n: 3
}
doe_run run_3 {
power: 2.6
speed: 180
gas: 12
strength: 371
sd: 13.0
n: 3
}
doe_run run_4 {
power: 3.4
speed: 180
gas: 12
strength: 465
sd: 16.0
n: 3
}
doe_run run_5 {
power: 2.6
speed: 120
gas: 20
strength: 428
sd: 11.0
n: 3
}
doe_run run_6 {
power: 3.4
speed: 120
gas: 20
strength: 502
sd: 17.0
n: 3
}
doe_run run_7 {
power: 2.6
speed: 180
gas: 20
strength: 389
sd: 15.0
n: 3
}
doe_run run_8 {
power: 3.4
speed: 180
gas: 20
strength: 470
sd: 15.0
n: 3
}
// Each effect is a difference of means over the runs at the two levels of
// one factor, selected out of the matrix above. The interval is the same
// width for all four because the design is balanced.
effect effect_power {
of: weld_doe
label: "A — laser power, 2.6 to 3.4 kW"
measure: md
scale: identity
unit: "N"
direction: benefit
point: = (mean(where(kind:doe_run, power == 3.4), "strength") - mean(where(kind:doe_run, power == 2.6), "strength")) * 1[N]
lo: = point - weld_doe.effect_ci_half
hi: = point + weld_doe.effect_ci_half
level: 0.95
df: 16
}
effect effect_speed {
of: weld_doe
label: "B — weld speed, 120 to 180 mm/s"
measure: md
scale: identity
unit: "N"
direction: harm
point: = (mean(where(kind:doe_run, speed == 180), "strength") - mean(where(kind:doe_run, speed == 120), "strength")) * 1[N]
lo: = point - weld_doe.effect_ci_half
hi: = point + weld_doe.effect_ci_half
level: 0.95
df: 16
}
effect effect_gas {
of: weld_doe
label: "C — shield gas, 12 to 20 L/min"
measure: md
scale: identity
unit: "N"
direction: benefit
point: = (mean(where(kind:doe_run, gas == 20), "strength") - mean(where(kind:doe_run, gas == 12), "strength")) * 1[N]
lo: = point - weld_doe.effect_ci_half
hi: = point + weld_doe.effect_ci_half
level: 0.95
df: 16
}
effect effect_power_speed {
of: weld_doe
label: "AB — power by speed interaction"
measure: md
scale: identity
unit: "N"
direction: none
point: = 0.5 * ((mean(where(kind:doe_run, power == 3.4 and speed == 180), "strength") - mean(where(kind:doe_run, power == 2.6 and speed == 180), "strength")) - (mean(where(kind:doe_run, power == 3.4 and speed == 120), "strength") - mean(where(kind:doe_run, power == 2.6 and speed == 120), "strength"))) * 1[N]
lo: = point - weld_doe.effect_ci_half
hi: = point + weld_doe.effect_ci_half
level: 0.95
df: 16
}
// All 24 welds, split at the factor that matters. The corner means above
// are the summaries of these values; the pooled standard deviation the
// intervals rest on is the root mean square of the eight corner s values.
distribution weld_strength {
title: "Lap-shear strength by laser power — all 24 welds"
kind: raincloud
unit: "N"
whisker: tukey
jitter: true
n: 24
group power_low {
label: "2.6 kW"
values: [399, 412, 425, 358, 371, 384, 417, 428, 439, 374, 389, 404]
n: 12
mean: 400.00
}
group power_high {
label: "3.4 kW"
values: [470, 486, 502, 449, 465, 481, 485, 502, 519, 455, 470, 485]
n: 12
mean: 480.75
}
}
// The setting the effects imply: high power, low speed, high gas. The
// prediction uses half of each effect because the effects are stated per
// full step from low to high.
doe_prediction best_setting {
of: weld_doe
setting: "3.4 kW, 120 mm/s, 20 L/min argon"
predicted_strength: = weld_doe.grand_mean + effect_power.point / 2 - effect_speed.point / 2 + effect_gas.point / 2 - effect_power_speed.point / 2
observed_at_setting: 502 N
margin_over_specification: = predicted_strength - weld_doe.specification
confirmation: "Six confirmation welds at this setting averaged 498 N, inside the prediction interval."
}
note takt_conflict {
text: "Speed is the only factor the line cares about and the only one with a negative effect: running at the takt the line needs costs about 33 N of strength. The confirmation runs still clear the 450 N specification at 180 mm/s and 3.4 kW, so the answer is more power rather than a slower line."
anchor: weld_doe
}
view strength: raincloud(weld_strength)
caption strength_caption {
of: strength
title: "Lap-shear strength at the two power levels"
text: "Every weld in the design, split at the largest main effect. The gap between the two clouds is the 80.7 N power effect; the spread within each is what the confidence interval on that effect is built from."
statistics: "Box shows median and hinges with Tukey whiskers; all 24 welds are drawn. Effect intervals use t(16 df) x 2s / sqrt(24), s = 14.6 N."
n_statement: "n = 24 welds, 8 corners x 3 replicates."
style: journal
}