Monday, February 19, 2024

Statistics of Parts Sorting

 [Today I was listening to SolderSmoke podcast #250 and was shocked to find my name mentioned for the 10m AM conversion I have been doing, as documented here.  I'm famous now!]

During the podcast, the trio mentioned the need to pay attention to the quality of the parts one orders from various sources, some with better results than others.  This reminded me that some people haven't really thought that much either about what it means when you buy a part at a given tolerance - e.g 1%, 5%, etc.

What you get actually depends critically on how the parts sorting is done.  Let's demonstrate.  This is a plot of 10,000 resistor values, with 100 ohm target and assuming a 10% Gaussian distribution:


Now the factory selects their 1% grade parts and puts them aside in a bin.  What's the distribution now look like?


Not bad; the 1% didn't take many out so that on average, you're still looking at Gaussian approximate distribution of the parts.  So a selection taken at random here from the parts left still has about 100 ohm mean with 10% variation.

However, now let's do a second bin sorting and take out all the 5% parts.  What's left for the hapless 10% "floor sweepings" tolerance buyer?

Decidedly NOT a Gaussian distribution any longer.  It's bimodal.  In fact, as you can see, you get parts with two means: 111.63 ohms, and 88.60 ohms!  The distribution around those values also looks really Poisson to me, no longer a bell curve.

So depending on how the sorting is done at the factory, you can end up with large gaps in the values of the parts you might naively think are 10% distributed - which in this case is definitely NOT (100 +/- 10 ohms).  The good stuff disappeared.  It might also make a difference to you if you are expecting to sort parts looking for matches for e.g. building filters, etc. - you'd probably have to buy more parts (twice as many?) to get a good number within some distance of one another.  Think about the distance between those two distributions (vs. the distance within one).

Yet another reason to make sure your designs don't depend critically on absolute part values.

==================================

PS: Here's the Python code that generated the plots, for any who are interested.

#!/usr/bin/env python
#
# Demonstrate effects of parts sorting on statistics of remaining population
# 2024-02-19 PJE
#
import numpy
import scipy.stats
import numpy.random
import pylab
# 10,000 parts with 10% tolerance: 100 ohm resistor
rcenter = 100
tol = 0.1
N = 10000
rp = numpy.random.normal(loc=rcenter, scale=rcenter*tol, size=N)

# plot with overlaid bell curve
def plotdist(rp, rcenter, tol, tstr, fname, pval=None):
    pylab.figure()
    x = numpy.linspace(rcenter*(1-5*tol),rcenter*(1+5*tol),1000)
    n,bins,patch = pylab.hist(rp, bins=500,density=True,label='Parts dist')
    pylab.plot(x, scipy.stats.norm.pdf(x, rcenter, tol*rcenter),'m-',linewidth=4,label='Gaussian distribution')
    if pval:
        # mark means as vertical lines
        for k in range(len(pval)):
            rpsel = rp[pval[k]]
            rpmean = numpy.mean(rpsel)
            pylab.axvline(rpmean, color='r', label='Mean: %.2f' % (rpmean))
    pylab.legend(fontsize=10)
    pylab.grid()
    pylab.xlabel('Resistor value (ohms)')
    pylab.ylabel('Relative number of parts')
    pylab.title(tstr)
    pylab.savefig(fname, dpi=300)

# define a part sorting function.  tol = absolute fraction of parts to take out.
def binsort(x, tol):
    xm = numpy.mean(x)
    indx = numpy.where(numpy.abs((x-xm)/xm) > tol)[0]
    return x[indx]

#######

# plot unaltered bins
plotdist(rp, rcenter, tol, '%i original parts' % (N), 'original.png')

# sort the 1% parts
rpfirst = binsort(rp, tol=0.01)

# plot first sort
plotdist(rpfirst, rcenter, tol, '1% Parts Sort', 'no_1_pct.png')

# sort the 5% parts next
# yes, a bit silly since 1% parts are already gone, but it makes a point
rpsecond = binsort(rpfirst, tol=0.05)

# This is very bifurcated: separate positive and negative populations
posindx = numpy.where(rpsecond > rcenter)[0]
negindx = numpy.where(rpsecond < rcenter)[0]

# plot second sort
plotdist(rpsecond, rcenter, tol, '5% Parts Sort', 'no_5_pct.png', pval = [posindx,negindx])

No comments:

Post a Comment

Statistics of Parts Sorting

 [Today I was listening to SolderSmoke podcast #250 and was shocked to find my name mentioned for the 10m AM conversion I have been doing, a...