Esempio n. 1
0
def Divider(d, ratio):
    d["divider"] = set()
    # First check using equal resistors
    for R in d["R"]:
        Div(d, float(ratio), R, R)
    for R1, R2 in combinations(d["R"], 2):
        Div(d, float(ratio), R1, R2)
    # Print report
    div = list(d["divider"])
    if not div:
        out("No divider can be made")
        return
    div.sort()
    out("Voltage divider with ratio = ", ratio, ", tolerance = ", 
        sig(d["-t"]*100, 2), "%", sep="")
    out()
    out("% dev from")
    out("desired ratio       R1           R2      Total Res.")
    out("-------------   ----------   ----------  ----------")
    for rat, r1, r2 in div:
        dev = 100*((rat - float(ratio))/float(ratio))
        pct = sig(dev)
        if dev >= 0:
            pct = " " + pct
        R1, R2, R = fp.engsi(r1), fp.engsi(r2), fp.engsi(r1 + r2)
        if not dev:
            fg(highlight)
        out("   {0:10}   {1:^10}   {2:^10}   {3:^10}".format(pct, R1, R2, R))
        normal()
Esempio n. 2
0
def Quotient(d, ratio):
    # Ignore a requested ratio of 1, as any pair of resistors will work
    if ratio == 1:
        out("Quotient cannot be 1")
        exit(1)
    d["resistances"], t, Ratio = set(), d["-t"], float(ratio)
    for R1, R2 in combinations(d["R"], 2):
        q1 = R1/R2
        q2 = 1/q1
        if (1 - t)*Ratio <= q1 <= (1 + t)*Ratio:
            d["resistances"].add((q1, R1, R2))
        elif (1 - t)*Ratio <= q2 <= (1 + t)*Ratio:
            d["resistances"].add((q2, R2, R1))
    # Print report
    res = list(d["resistances"])
    if not res:
        out("No resistor combinations that meet tolerance")
        return
    res.sort()
    out("Desired ratio = ", ratio, ", tolerance = ",
        sig(d["-t"]*100, 2), "%", sep="")
    out()
    out("% dev from")
    out("desired ratio       R1           R2")
    out("-------------   ----------   ----------")
    for val, r1, r2 in res:
        dev = 100*((val - Ratio)/Ratio)
        pct = sig(dev, 2)
        if dev >= 0:
            pct = " " + pct
        R1, R2 = fp.engsi(r1), fp.engsi(r2)
        if not dev:
            fg(highlight)
        out("   {0:10}   {1:^10}   {2:^10}".format(pct, R1, R2))
        normal()
Esempio n. 3
0
    def Report():
        S = {
            "Files"                     : [],
            "ProcessDistribution"       : normal,
            "ProcessMu"                 : 10,
            "ProcessSigma"              : 1,
            "MeasurementDistribution"   : normal,
            "MeasurementMu"             : 0,
            "MeasurementSigma"          : 1,
            "NumberOfLots"              : 2,
            "PartsPerLot"               : 10,
            "Specification"             : (9.5, 10.5),
        }
        seed(8353475)  # Make the random number stream repeatable
        results = Manufacture(S)
        p = sig((S["ProcessMu"], S["ProcessSigma"]))
        m = sig((S["MeasurementMu"], S["MeasurementSigma"]))
        s = sig(S["Specification"])
        nl = str(S["NumberOfLots"])
        ppl = str(S["PartsPerLot"])
        out('''
Small manufacturing example:
  Process      (mu, sigma) = {p}
  Measureement (mu, sigma) = {m}
  Spec                     = {s}
  Number of lots           = {nl}
  Parts per lot            = {ppl}
'''[1:].format(**locals()))
        out("Good parts made =\n",        sig(results["parts"][0]))
        out("Bad parts made  =\n",        sig(results["parts"][1]))
        out("Good parts tested good =\n", sig(results["parts"][2]))
        out("Good parts tested bad  =\n", sig(results["parts"][3]))
        out("Bad parts tested good  =\n", sig(results["parts"][4]))
        out("Bad parts tested bad   =\n", sig(results["parts"][5]))
Esempio n. 4
0
def Pairs(args, d):
    if len(args) != 4:
        Usage(d)
    parallel = True if args[3] == "p" else False
    target_value = float(args[2])
    if target_value <= 0:
        Error("Target value must be > 0")
    # Read file data
    lines = [i.strip() for i in open(args[1]).readlines()]
    # Check that we have only one blank line and an equal number of
    # resistance values on either side of it.
    r1, r2, first = [], [], True
    for line in lines:
        if not line:
            first = False
            continue
        if first:
            r1.append(float(line))
        else:
            r2.append(float(line))
    if not r1 or not r2:
        Error("Missing blank line in resistor file '%s'" % args[1])
    if len(r1) != len(r2):
        Error("Two resistor sets don't have equal number in resistor file '%s'" 
            % args[1])
    # Calculate the set of resultant resistances
    results = []
    for i in r1:
        for j in r2:
            if parallel:
                r = 1/(1/i + 1/j)
            else:
                r = i + j
            pct_dev = 100*(r - target_value)/target_value
            pct_dev = 0 if abs(pct_dev) < 1e-10 else pct_dev
            results.append([pct_dev, r, i, j])
    results.sort()
    model, file = "parallel" if parallel else "series", args[1]
    out('''
Model = {model}
File  = {file}

% dev from
mean value      Resistance          R1               R2
----------      ----------      -------------   -------------
'''[1:-1].format(**locals()))
    sig.digits = d["-d"]
    for i in results:
        r, r1, r2 = i[1:]
        out("%9s%%      " % sig(i[0], 2), nl=False)
        out("%-10s      " % sig(r), nl=False)
        out("%-10s      " % sig(r1), nl=False)
        out("%-10s" % sig(r2))
Esempio n. 5
0
def Resistance(d, resistance):
    d["resistances"] = set()
    # First see if we have an exact match
    if resistance in d["R"]:
        d["resistances"].add((resistance, "e", resistance, 0))
    else:
        # First check using equal resistors
        for R in d["R"]:
            Res(d, resistance, R, R)
        for R1, R2 in combinations(d["R"], 2):
            Res(d, resistance, R1, R2)
    res = list(d["resistances"])
    if not res:
        out("No resistor combinations that meet tolerance")
        return
    # Check if we have too many entries; if so, whittle down the list to
    # the closest N.
    clipped = False
    if len(res) > d["-n"]:
        # Sort by absolute value of tolerance
        tol = lambda tgt, val: abs(val - tgt)/val
        r = [(tol(resistance, i[0]), i) for i in res]   # Decorate with abs val
        r.sort()
        res = [i[1] for i in r[:d["-n"]]]
        clipped = True
    # Print report
    res.sort()
    out("Desired resistance = ", d["desired"], " = ", sig(d["res"]) + 
        ", tolerance = ", sig(d["-t"]*100, 2), "%", sep="")
    if clipped:
        out("Closest %d matches shown" % d["-n"])
    out()
    out("% dev from")
    out("desired res.        R1           R2      Connection")
    out("-------------   ----------   ----------  ----------")
    for val, c, r1, r2 in res:
        dev = 100*((val - resistance)/resistance)
        pct = sig(dev, 2)
        if dev >= 0:
            pct = " " + pct
        R1, R2 = fp.engsi(r1), fp.engsi(r2)
        conn = {"s":"series", "p":"parallel", "e":"exact"}[c]
        if (d["-p"] and c == "s") or (d["-s"] and c == "p"):
            continue
        if not dev:
            fg(highlight)
        if c == "e":
            out("   {0:10}   {1:^10}                {2}".format(pct, R1, conn))
        else:
            out("   {0:10}   {1:^10}   {2:^10}   {3}".format(pct, R1, R2, conn))
        normal()
Esempio n. 6
0
def FloatingPoint(n, m, inc, d):
    fmt = "%%.%dg" % d["-d"]
    for i in frange(n, m, inc, include_end=d["-e"]):
        if i <= float(m):
            if d["-s"]:
                out(sig(i), "", nl=d["-n"])
            else:
                out(fmt % i, "", nl=d["-n"])
    if not d["-n"]:
        out()
Esempio n. 7
0
def yt_download(video_id):
    """Request download link from youtube-mp3.com."""
    timestamp = str(int(time.time()))
    tail = random.sample(range(100, 999), 2)
    # Generate timestamp that complies with site's version
    ts = [timestamp + str(min(tail)), timestamp + str(max(tail))]
    push = 'http://www.youtube-mp3.org/a/pushItem/?item=https%3A//www.youtube.com/watch%\3Fv%3D{}&el=ma&bf=false&r={}&s={}'.format(
        video_id, ts[0], sig(ts[0]))
    info = 'http://www.youtube-mp3.org/a/itemInfo/?video_id={}&ac=www&t=grp&r={}&s={}'.format(
        video_id, ts[1], sig(ts[1]))

    requests.get(push)  # Make sure video is converted
    r = requests.get(info)
    txt = r.text.split('info = ')[1][:-1]  # JSON-friendly part of response
    js = json.loads(txt)
    dl_link = (
        'http://www.youtube-mp3.org/get?video_id={}&ts_create={}&r=MTg4LjIzMS4xMzEuNzQ%3D&h2={}&s={}'
        .format(video_id, js["ts_create"], js["h2"], sig(js["h2"])))
    return dl_link
Esempio n. 8
0
def DividerRatios(d, res):
    r = [Interpret(i) for i in res]
    R = sum(r)
    out("String of voltage dividers:")
    out("  Resistors given:")
    for i in res:
        out("    ", i)
    out("  Total resistance =", fp.engsi(R))
    out("  Divider ratios:")
    for i in range(1, len(r)):
        D = sum(r[i:])/R
        out("  %2d  " % i, sig(D, 4))
Esempio n. 9
0
def List(d):
    out("On-hand resistors:\n")
    out(on_hand[1:-1])
    out("-"*70)
    out("EIA resistance series:")
    for n in (6, 12, 24, 48, 96):
        out("E%d:" % n)
        digits = 2 if n < 48 else 3
        s = []
        for num in EIA[n]:
            s.append(sig(num, digits))
        for i in Columnize(s):
            out(" ", i)
Esempio n. 10
0
def Series(d, res):
    '''Find a set of resistors that sum to the desired value but remain
    less than or equal to it.
    '''
    resistors = d["R"]
    resistors.sort()
    resistors = list(reversed(resistors))
    used = []
    while resistors and sum(used) <= res:
        if resistors[0] + sum(used) <= res:
            used.append(resistors[0])
        else:
            del resistors[0]
    out("Sum =", fp.engsi(sum(used)))
    out("  Resistor     % of total")
    r = 0
    for i in used:
        r += i
        out("  %-10s" % fp.engsi(i), " ", sig(100*r/res, 6))
Esempio n. 11
0
def Report(d):
    angle = sig(d["angle"])
    arc = sig(d["arc"])
    chord = sig(d["chord"])
    diameter = sig(d["diameter"])
    height = sig(d["height"])
    radius = sig(d["radius"])
    print('''Results:
  Angle     {angle} deg
  Arc       {arc}
  Chord     {chord}
  Diameter  {diameter}
  Height    {height}
  Radius    {radius}'''.format(**locals()))
Esempio n. 12
0
def Calculate(__vars, __d):
    # Get vars into our local namespace
    if __vars is not None:
        for __k in __vars:
            if len(__k) > 2 and __k[:2] == "__":
                continue
            exec("%s = __vars['%s']" % (__k, __k))
    try:
        if radius and angle:
            if dbg:
                print("radius, angle", sig(radius), sig(angle))
            z = radius*COSD(0.5*angle)
            height = radius - z
            chord = 2.*radius*SIND(0.5*angle)
            arc = radius*angle*RPD
        elif radius and chord:
            if dbg:
                print("radius, chord", sig(radius), sig(chord))
            angle = 2.*ASND(0.5*chord/radius)
            z = radius*COSD(0.5*angle)
            height = radius - z
            arc = radius*angle*RPD
        elif radius and height:
            if dbg:
                print("radius, height", sig(radius), sig(height))
            z = radius - height
            angle = 2.*ACSD(z/radius)
            chord = 2.*radius*SIND(0.5*angle)
            arc = radius*angle*RPD
        elif radius and arc:
            if dbg:
                print("radius, arc", sig(radius), sig(arc))
            angle = DPR*arc/radius
            z = radius*COSD(0.5*angle)
            height = radius - z
            chord = 2.*radius*SIND(0.5*angle)
        elif angle and chord:
            if dbg:
                print("angle, chord", sig(angle), sig(chord))
            radius = 0.5*chord/SIND(0.5*angle)
            z = radius*COSD(0.5*angle)
            height = radius - z
            arc = radius*angle*RPD
        elif angle and height:
            if dbg:
                print("angle, height", sig(angle), sig(height))
            radius = height/(1. - COSD(0.5*angle))
            z = radius - height
            chord = 2.*radius*SIND(0.5*angle)
            arc = radius*angle*RPD
        elif angle and arc:
            if dbg:
                print("angle, arc", sig(angle), sig(arc))
            radius = DPR*arc/angle
            z = radius*COSD(0.5*angle)
            height = radius - z
            chord = 2.*radius*SIND(0.5*angle)
        elif chord and height:
            if dbg:
                print("chord, height", sig(chord), sig(height))
            radius = (4.*height*height + chord*chord)/(8.*height)
            z = radius - height
            angle = 2.*ACSD(z/radius)
            arc = radius*angle*RPD
        elif chord and arc:
            if dbg:
                print("chord, arc", sig(chord), sig(arc))
            h, t1, t2, dt, hbest, k = 0, 1, 180, 1, 1e6, 0
            while ABS(h - chord) > 1e-6 and k < 6:
                angle = t1
                while angle <= t2:
                    radius = DPR*arc/angle
                    h = 2.*radius*SIND(0.5*angle)
                    if ABS(h - chord) < hbest:
                        hbest = ABS(h - chord)
                        tbest = angle
                    angle += dt
                t1 = tbest - dt
                t2 = tbest + dt
                dt *= 0.1
                k += 1
            # Note that angle will not have an uncertainty associated
            # with it because it was derived through iteration in the
            # loop.
            angle = tbest
            radius = DPR*arc/angle
            height = radius*(1 - COSD(0.5*angle))
        elif height and arc:
            if dbg:
                print("height, arc", sig(height), sig(arc))
            h, t1, t2, dt, hbest, k = 0, 1, 180, 1, 1e6, 0
            while ABS(h - height) > 1e-6 and k < 6:
                angle = t1
                while angle <= t2:
                    radius = DPR*arc/angle
                    h = radius*(1 - COSD(0.5*angle))
                    if ABS(h - height) < hbest:
                        hbest = ABS(h - height)
                        tbest = angle
                    angle += dt
                t1 = tbest - dt
                t2 = tbest + dt
                dt *= 0.1
                k += 1
            # Note that angle will not have an uncertainty associated
            # with it because it was derived through iteration in the
            # loop.
            angle = tbest
            radius = DPR*arc/angle
            chord = 2.*radius*SIND(0.5*angle)
    except Exception as e:
        if dbg:
            print("Exception in Calculate(): ", str(e))
        return False
    # Put answers into dictionary
    __d["diameter"] = 2*radius
    __d["radius"] = radius
    __d["angle"] = angle
    __d["chord"] = chord
    __d["height"] = height
    __d["arc"] = arc
    return True
Esempio n. 13
0
     X = Z * sin(theta)
     print("  Rs = ", E(Rs), "ohm = ESR", sep="")
     print("  Rp = ", E(Rp), "ohm", sep="")
     print("  X  = ", E(X), "ohm", sep="")
     if isinf(Cs):
         print("  Cs = inf")
     else:
         print("  Cs = ", E(Cs), "F", sep="")
     print("  Cp = ", E(Cp), "F", sep="")
     print("  Ls = ", E(Ls), "H", sep="")
     if isinf(Lp):
         print("  Lp = inf")
     else:
         print("  Lp = ", E(Lp), "H", sep="")
     if isinstance(Q, float):
         print("  Q  =", sig(Q))
         print("  D  =", sig(D))
     else:
         print("  Q  =", Q)
         print("  D  =", D)
 else:
     # Use f-strings
     o = "Ω"
     Rs = f"{E(Rs)}{o}"
     Rp = f"{E(Rp)}{o}"
     X = E(Z * sin(theta)) + o
     if isinf(Cs):
         Cs = f"∞ F"
     else:
         Cs = f"{E(Cs)}F"
     Cp = f"{E(Cp)}F"
Esempio n. 14
0
def Report(d):
    S, w = d["solution"], 15
    angle_measure = 1/d["angle_measure"]
    if angle_measure == 1:
        dm = "rad"
    else:
        dm = "deg"
    ds = " "*5
    S1, S2, S3, A1, A2, A3 = [S[i] for i in  "S1 S2 S3 A1 A2 A3".split()]
    s1, s2, s3 = [sig(i) for i in (S1, S2, S3)]
    a1, a2, a3 = [sig(i*angle_measure) for i in (A1, A2, A3)]
    GetOtherFacts(S1, S2, S3, A1, A2, A3, d)
    area = sig(d["area"])
    r = sig(d["r_inscribed"])
    R = sig(d["R_circumscribed"])
    di = sig(d["r_inscribed"]*2)
    D = sig(d["R_circumscribed"]*2)
    p = sig(d["perimeter"])
    title = "Triangle solution"
    fmt = '''{title}:
  Sides  {ds}          {s1:{w}} {s2:{w}} {s3:{w}}
  Angles ({dm})          {a1:{w}} {a2:{w}} {a3:{w}}
  Area                  {area}
  Perimeter             {p}
  Inscribed circle      radius = {r}, diameter = {di}   [Note 1]
  Circumscribed circle  radius = {R}, diameter = {D}   [Note 2]'''
    out(fmt.format(**locals()))
    # Check for 2nd solution
    if "S1_2" in S:
        S1, S2, S3, A1, A2, A3 = [S[i] for i in  
            "S1_2 S2_2 S3_2 A1_2 A2_2 A3_2".split()]
        GetOtherFacts(S1, S2, S3, A1, A2, A3, d)
        s1, s2, s3 = [sig(i) for i in (S1, S2, S3)]
        a1, a2, a3 = [sig(i*angle_measure) for i in (A1, A2, A3)]
        title = "Second solution"
        area = sig(d["area"])
        r = sig(d["r_inscribed"])
        R = sig(d["R_circumscribed"])
        di = sig(d["r_inscribed"]*2)
        D = sig(d["R_circumscribed"]*2)
        p = sig(d["perimeter"])
        out(fmt.format(**locals()))
    out('''  
  [1] Center located by angle bisectors.  
  [2] Center located by perpendicular bisectors of the sides.''')
Esempio n. 15
0
if __name__ == "__main__":
    d = {}  # Options dictionary
    args = ParseCommandLine(d)
    price = None
    CorrectArgs(args)
    if len(args) == 2:
        year1, year2 = [int(i) for i in args]
    elif len(args) == 3:
        price = float(args[0])
        p = args[0]  # User's string for price
        year1, year2 = [int(i) for i in args[1:]]
    else:
        raise Exception("Logic bug")
    c = d["cpi"]
    if year1 not in c:
        print("Year", year1, "not in data")
        exit(1)
    if year2 not in c:
        print("Year", year2, "not in data")
        exit(1)
    ratio = c[year2] / c[year1]
    if price is not None:
        print("${} in {} = ${} in {}".format(p, year1, sig(price * ratio),
                                             year2))
        print("${} in {} = ${} in {}".format(p, year2, sig(price / ratio),
                                             year1))
    else:
        print("$1 in {} = ${} in {}".format(year1, sig(ratio), year2))
        print("$1 in {} = ${} in {}".format(year2, sig(1 / ratio), year1))
Esempio n. 16
0
    def do_sig(self, line):
        _sig = sig(self.line_bot_api, self.event)

        return _sig.calculate(line)
Esempio n. 17
0
def PrintReport(d):
    S, R, w = d["settings"], d["results"]["parts"], 79
    if S["Title"].strip():
        for line in S["Title"].split("\n"):
            out("{0:^{1}s}".format(line, w))
    tm = time.asctime(time.localtime(time.time()))
    out("{0:^{1}s}".format(tm, w))
    if d["seed"] is not None:
        s = "Seed = " + d["seed"]
        out("{0:^{1}s}".format(s, w))
    out()
    s = "Source files and their hashes"
    out(s)
    out("-"*len(s))
    d["settings"]["Files"].sort()
    for file in d["settings"]["Files"]:
        out(" ", Hash(open(file).read())[0], file)
    out()
    # Process details
    sig.digits = sd = S["SignificantDigits"]
    proc_mean, proc_s = sig(S["ProcessMu"]), sig(S["ProcessSigma"])
    meas_mean, meas_s = sig(S["MeasurementMu"]), sig(S["MeasurementSigma"])
    pdist, mdist = S["ProcessDistributionName"], S["MeasurementDistributionName"]
    N = S["NumberOfLots"]*S["PartsPerLot"]
    nparts = FmtI(N)
    nl, ppl = FmtI(S["NumberOfLots"]), FmtI(S["PartsPerLot"])
    spec = sig(list(S["Specification"]))
    na, nw, nd, sp = ">", 15, 30, " "*10
    out('''
Process characteristics                    ({sd} significant figures)
-----------------------
  Distributions
    Process     = {pdist}
    Measurement = {mdist}
  Process mean                    {sp}{proc_mean:{na}{nw}}
  Process standard deviation      {sp}{proc_s:{na}{nw}} 
  Measurement bias                {sp}{meas_mean:{na}{nw}} 
  Measurement standard deviation  {sp}{meas_s:{na}{nw}}
  Part acceptance interval        {sp}{spec:{na}{nw}}
  Number of lots made             {sp}{nl:{na}{nw}}
  Parts per lot                   {sp}{ppl:{na}{nw}}
'''[1:].format(**locals()))
    # What was actually produced
    good, bad = len(R[0]), len(R[1])
    goodi, badi = FmtI(good), FmtI(bad)
    goodp, badp = sig(100*good/float(N)), sig(100*bad/float(N))
    out('''
True (unknowable) process output
--------------------------------
  Total parts made  {nparts:{na}{nw}}
  Actual good       {goodi:{na}{nw}}    ({goodp}% of total)
  Actual bad        {badi:{na}{nw}}    ({badp}% of total)
'''[1:].format(**locals()))
    # What the measurements said was produced
    gtg, gtb = len(R[2]), len(R[3])
    btg, btb = len(R[4]), len(R[5])
    gtgi, gtbi = FmtI(gtg), FmtI(gtb)
    btgi, btbi = FmtI(btg), FmtI(btb)
    gtgp = sig(100*gtg/float(N))
    gtbp = sig(100*gtb/float(N))
    btgp = sig(100*btg/float(N))
    btbp = sig(100*btb/float(N))
    all = np.concatenate((R[2], R[3], R[4], R[5]))
    mean = sig(np.average(all))
    sdev = sig(np.sqrt(np.cov(all)))
    low, high = sig(np.min(all)), sig(np.max(all))
    out('''
What 100% inspection determined
-------------------------------
  Good tested good  {gtgi:{na}{nw}}  {gtgp:{na}}%
  Good tested bad   {gtbi:{na}{nw}}  {gtbp:{na}}%  <-- Producer's risk
  Bad  tested good  {btgi:{na}{nw}}  {btgp:{na}}%  <-- Consumer's risk
  Bad  tested bad   {btbi:{na}{nw}}  {btbp:{na}}%
  Process mean      {mean:{na}{nw}}
  Process std dev   {sdev:{na}{nw}}
  Min, max measured    [{low}, {high}]
'''[1:].format(**locals()))

    # Production results
    ship  = FmtI(gtg + btg)
    scrap = FmtI(gtb + btb)
    try:
        ship_badp = sig(100*gtb/float(gtg + gtb))
    except ZeroDivisionError:
        ship_badp = sig(0)
    try:
        scrap_goodp = sig(100*btg/float(btg + btb))
    except ZeroDivisionError:
        scrap_goodp = sig(0)
    yieldr = "actual = " + sig(100*good/float(N)) + "%,"
    yieldm = "measured = " + sig(100*(gtg + btg)/float(N)) + "%"
    scrapr = "actual = " + sig(100*bad/float(N)) + "%,"
    scrapm = "measured = " + sig(100*(gtb + btb)/float(N)) + "%"
    ya, ysw = ">", 15
    out('''
Production results
------------------
  Parts shipped     {ship:{na}{nw}}  {ship_badp}% of these are bad parts
  Parts scrapped    {scrap:{na}{nw}}  {scrap_goodp}% of these are good parts
  Yield              {yieldr:{ya}{ysw}} {yieldm}
  Scrapped           {scrapr:{ya}{ysw}} {scrapm}
'''[1:].format(**locals()))
    # Financial results
    # Per part:
    nship, nscrap, n = gtg + btg, gtb + btb, float(N)
    cprodpp    = S["CostToProducePart"]
    ctestpp    = S["CostToTestPart"]
    cshippp    = S["CostToShipPart"]
    cscrappp   = S["CostToScrapPart"]
    cvohpp     = S["CostVariableOverhead"]
    cfohpp     = S["CostFixedOverhead"]/float(N)
    ccustbadpp = S["CustomerCostPerBadPart"]
    # Formatted as integers
    cprod       = FmtI(int(cprodpp*n))
    ctest       = FmtI(int(ctestpp*n))
    cship       = FmtI(int(ctestpp*float(nship)))
    cscrap      = FmtI(int(cscrappp*float(nscrap)))
    cvoh        = FmtI(int(cvohpp*n))
    cfoh        = FmtI(int(float(S["CostFixedOverhead"])))
    ctprod      = (n*(cprodpp + ctestpp + cvohpp + cfohpp)
                  + ctestpp*float(nship) + cscrappp*float(nscrap))
    ctprodi     = FmtI(int(ctprod))
    ctprodpp    = (ctprod/n)
    ppstart     = ctprod/n
    try:
        ppship  = ctprod/float(nship)
    except ZeroDivisionError:
        ppship  = 0
    # Percentages of total production cost
    ppc = 100*cprodpp*n/ctprod
    ptc = 100*ctestpp*n/ctprod
    psc = 100*ctestpp*float(nship)/ctprod
    pcs = 100*cscrappp*float(nscrap)/ctprod
    pvo = 100*cvohpp*n/ctprod
    pfo = 100*float(S["CostFixedOverhead"])/ctprod
    tpc = 100
    # Revenue & customer
    sppp = S["SellingPricePerPart"]
    trev = sppp*float(gtg + btg)
    trevi = FmtI(int(trev))
    gp = FmtI(int(trev - ctprod))
    try:
        gpp = 100*(trev - ctprod)/trev
    except Exception:
        gpp = "--"
    custloss = ccustbadpp*float(btg)
    custlossi = FmtI(int(custloss))
    try:
        custlosspp = custloss/float(nship)
    except ZeroDivisionError:
        custlosspp = 0
    mo = ">15s"
    kd, pp, pt = ">10.1f", ">8.3f", ">5.1f"
    pps  = "per part started"
    ppsh = "per part shipped"
    prp  = "per received part"
    out('''
Money                              Amount   %   Cost per part
-----                           --------- ----- -------------
  Production cost         {cprod:{mo}} {ppc:{pt}} {cprodpp:{pp}}   
  Testing cost            {ctest:{mo}} {ptc:{pt}} {ctestpp:{pp}}   
  Shipment cost           {cship:{mo}} {psc:{pt}} {cshippp:{pp}}   
  Cost to scrap           {cscrap:{mo}} {pcs:{pt}} {cscrappp:{pp}}   
  Variable overhead cost  {cvoh:{mo}} {pvo:{pt}} {cvohpp:{pp}}   
  Fixed overhead cost     {cfoh:{mo}} {pfo:{pt}} {cfohpp:{pp}}   
                                --------- ----- --------
  Total production cost   {ctprodi:{mo}} {tpc:{pt}} {ppstart:{pp}} {pps}
                                                {ppship:{pp}} {ppsh}
  Revenue                 {trevi:{mo}}       {sppp:{pp}} selling price
  Gross profit            {gp:{mo}}       
'''[1:-1].format(**locals()))
    if gpp == "--":
        out('''
  % gross profit                      --%            
  Customer's loss              {custlossi:{mo}}       {custlosspp:{pp}} {prp}
'''[1:-1].format(**locals()))
    else:
        out('''
  % gross profit               {gpp:{kd}}%    
  Customer's loss         {custlossi:{mo}}       {custlosspp:{pp}} {prp}
'''[1:-1].format(**locals()))