# Monte Carlo Tolerance Stack-Up Python Script Generator

> Source: https://netray.co/tools/monte-carlo-tolerance-stack-up-python-script-generator
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: Free Tools

## Short answer

Fill in up to four stack dimensions and a gap limit, and get a Python script that simulates the assembly and reports worst case, RSS and out-of-limit rate.

## Category

engineering-plm

## Industry

Discrete Manufacturing

## Audience

- Design engineer
- Mechanical engineer
- Quality engineer

## Tool

**Kind:** template

**Output:** code

**Language:** python

**Fields:**

#### Dimension 1 name

**Key:** d1_name

**Type:** text

**Default:** housing_depth

#### Dimension 1 nominal (mm)

**Key:** d1_nom

**Type:** number

**Default:** 42.00

#### Dimension 1 tolerance +/- (mm)

**Key:** d1_tol

**Type:** number

**Default:** 0.10

#### Dimension 1 direction

**Key:** d1_dir

**Type:** select

**Options:**

- 1
- -1

**Default:** 1

#### Dimension 2 name

**Key:** d2_name

**Type:** text

**Default:** bearing_width

#### Dimension 2 nominal (mm)

**Key:** d2_nom

**Type:** number

**Default:** 12.00

#### Dimension 2 tolerance +/- (mm)

**Key:** d2_tol

**Type:** number

**Default:** 0.05

#### Dimension 2 direction

**Key:** d2_dir

**Type:** select

**Options:**

- 1
- -1

**Default:** -1

#### Dimension 3 name

**Key:** d3_name

**Type:** text

**Default:** shaft_shoulder

#### Dimension 3 nominal (mm)

**Key:** d3_nom

**Type:** number

**Default:** 28.00

#### Dimension 3 tolerance +/- (mm)

**Key:** d3_tol

**Type:** number

**Default:** 0.08

#### Dimension 3 direction

**Key:** d3_dir

**Type:** select

**Options:**

- 1
- -1

**Default:** -1

#### Dimension 4 name

**Key:** d4_name

**Type:** text

**Default:** spacer

#### Dimension 4 nominal (mm)

**Key:** d4_nom

**Type:** number

**Default:** 1.50

#### Dimension 4 tolerance +/- (mm)

**Key:** d4_tol

**Type:** number

**Default:** 0.02

#### Dimension 4 direction

**Key:** d4_dir

**Type:** select

**Options:**

- 1
- -1

**Default:** -1

#### Minimum acceptable gap (mm)

**Key:** gap_min

**Type:** number

**Default:** 0.10

#### Maximum acceptable gap (mm)

**Key:** gap_max

**Type:** number

**Default:** 0.80

#### Tolerance divided by (sigma)

**Key:** sigma_div

**Type:** number

**Default:** 3

**Help:** 3 means the tolerance equals 3 sigma (Cp of 1.0). Use 4 for Cp of 1.33.

#### Number of samples

**Key:** samples

**Type:** number

**Default:** 200000

#### Random seed

**Key:** seed

**Type:** number

**Default:** 42

**Blocks:**

#### Python script

**Body:** import math
import random
import statistics

random.seed({{seed}})
N = {{samples}}
SIGMA_DIV = {{sigma_div}}
GAP_MIN = {{gap_min}}
GAP_MAX = {{gap_max}}

# (name, nominal, +/- tolerance, direction) ; direction +1 adds to the gap, -1 subtracts
DIMS = [
    ('{{d1_name}}', {{d1_nom}}, {{d1_tol}}, {{d1_dir}}),
    ('{{d2_name}}', {{d2_nom}}, {{d2_tol}}, {{d2_dir}}),
    ('{{d3_name}}', {{d3_nom}}, {{d3_tol}}, {{d3_dir}}),
    ('{{d4_name}}', {{d4_nom}}, {{d4_tol}}, {{d4_dir}}),
]

nominal_gap = sum(d * nom for _, nom, _, d in DIMS)
worst_range = sum(tol for _, _, tol, _ in DIMS)
rss_range = math.sqrt(sum(tol ** 2 for _, _, tol, _ in DIMS))

gaps = []
for _ in range(N):
    gap = 0.0
    for _, nom, tol, d in DIMS:
        gap += d * random.gauss(nom, tol / SIGMA_DIV)
    gaps.append(gap)

out_low = sum(1 for g in gaps if g < GAP_MIN)
out_high = sum(1 for g in gaps if g > GAP_MAX)
ppm = (out_low + out_high) / N * 1e6

print('Nominal gap        : %.4f mm' % nominal_gap)
print('Worst case range   : %.4f to %.4f mm' % (nominal_gap - worst_range, nominal_gap + worst_range))
print('RSS range (+/-)    : %.4f to %.4f mm' % (nominal_gap - rss_range, nominal_gap + rss_range))
print('Simulated mean     : %.4f mm' % statistics.mean(gaps))
print('Simulated std dev  : %.4f mm' % statistics.pstdev(gaps))
print('Simulated min/max  : %.4f / %.4f mm' % (min(gaps), max(gaps)))
print('Below %.2f mm      : %d of %d' % (GAP_MIN, out_low, N))
print('Above %.2f mm      : %d of %d' % (GAP_MAX, out_high, N))
print('Out of limits      : %.0f PPM' % ppm)
print('Worst case fits?   :', nominal_gap - worst_range >= GAP_MIN and nominal_gap + worst_range <= GAP_MAX)

**Notes:** Each dimension is modeled as a normal distribution centered on nominal with a standard deviation of tolerance divided by the sigma value. This ignores mean shift, non-normal distributions and geometric variation (position, form, tilt), so treat the output as a design aid and validate with measured data. Needs Python 3 and no extra packages.

## Content

**Intro:** Spreadsheets handle worst case and RSS well, but a simulation is better when the stack has many terms or when you want an out-of-limit rate in parts per million. This generator writes a short, dependency-free Python script you can run and modify.

**Sections:**

#### How to use the generator

**Body:** Enter each dimension in the stack with its nominal and plus-minus tolerance. Set the direction to 1 if the dimension increases the gap, and -1 if it decreases it. Then enter the minimum and maximum acceptable gap. The sigma setting decides how wide the simulated distribution is compared with the tolerance. Copy the script, save it as a .py file and run it with Python 3. It prints the worst case range, the RSS range, the simulated statistics and the estimated number of assemblies outside the gap limits.

**Bullets:**

- Add more dimensions by copying one tuple in the DIMS list
- Raise samples to 1,000,000 for a finer tail estimate
- Change the random seed to check that the answer is stable

#### Worst case, RSS and Monte Carlo

**Body:** Worst case adds every tolerance, so it guarantees fit for every assembly if all parts are within limits. RSS takes the square root of the sum of squares, which assumes independent, centered, normal variation and gives a narrower range. Monte Carlo draws random values for each dimension and builds thousands of virtual assemblies. It matches RSS for simple linear stacks, but it also lets you change the distribution, add a mean shift or use non-linear relationships.

#### How to read the result

**Body:** If the worst case range sits inside the gap limits, the design always assembles with in-tolerance parts. If only the RSS range fits, you are accepting a small, predictable rejection rate, and the PPM line tells you how small. With the default inputs, the nominal gap is 0.50 mm, the worst case range is 0.25 to 0.75 mm, and the simulation shows no failures against 0.10 to 0.80 mm. A non-zero PPM means a tolerance review or a process capability check.

#### Limits of the model

**Body:** The script assumes a one-dimensional linear stack, and every part is centered on nominal. Real processes drift, so a Cpk below the Cp used here will give a higher failure rate than reported. Geometric tolerances, thermal expansion and assembly shifts are not modeled. Use the output as a design aid, and confirm against measured data once production parts exist.

**Cta:** Netray can pull measured dimensions from your ERP or quality system into a script like this, so tolerance analysis uses real process data instead of assumed sigma values.

**Faq:**

#### Why divide the tolerance by 3 for sigma?

**Answer:** Dividing by 3 assumes the process is centered and its natural spread, plus or minus 3 sigma, just fills the tolerance, which is a Cp of 1.0. A capable process with Cp of 1.33 would use 4. Use measured standard deviations when you have them.

#### How many samples are enough?

**Answer:** For a stable mean and standard deviation, 10,000 is usually enough. To see rare failures in the parts per million range you need hundreds of thousands or more. Run with two different seeds and check that the PPM figure is roughly stable.

#### When should I use worst case instead?

**Answer:** Use worst case for safety-critical fits, small production volumes, or where any single failure is unacceptable. Statistical methods are reasonable for high volume work with demonstrated process capability, and where the customer or standard allows them.

#### Can I model a non-normal distribution?

**Answer:** Yes. Replace random.gauss with random.uniform for a uniform spread or random.triangular for a skewed one. The structure of the script stays the same, which is the main advantage of simulation over a closed-form RSS formula.

## Search terms

monte carlo tolerance analysis python, tolerance stack up python script, statistical tolerance simulation, tolerance stackup monte carlo excel alternative, rss vs monte carlo tolerance, python tolerance analysis, stack up simulation normal distribution, tolerance analysis code

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
