Last active
February 14, 2016 17:44
-
-
Save notwa/30630649526fd3e354fa to your computer and use it in GitHub Desktop.
guitar tension ideal string finder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# (product name, unit weight) | |
# D'Addario stock via http://www.daddario.com/upload/tension_chart_13934.pdf | |
# Circle K String stock http://circlekstrings.com/CKSIMAGES/UnitWeightChart130105.pdf | |
# string names don't necessarily match up with their actual product names | |
daddario_plain_steel = ( | |
('DAPL007' , .00001085), | |
('DAPL008' , .00001418), | |
('DAPL0085', .00001601), | |
('DAPL009' , .00001794), | |
('DAPL0095', .00001999), | |
('DAPL010' , .00002215), | |
('DAPL0105', .00002442), | |
('DAPL011' , .00002680), | |
('DAPL0115', .00002930), | |
('DAPL012' , .00003190), | |
('DAPL013' , .00003744), | |
('DAPL0135', .00004037), | |
('DAPL014' , .00004342), | |
('DAPL015' , .00004984), | |
('DAPL016' , .00005671), | |
('DAPL017' , .00006402), | |
('DAPL018' , .00007177), | |
('DAPL019' , .00007997), | |
('DAPL020' , .00008861), | |
('DAPL022' , .00010722), | |
('DAPL024' , .00012760), | |
('DAPL027' , .00014975), | |
) | |
daddario_nickle_wound = ( # XL | |
('DANW017' , .00005524), | |
('DANW018' , .00006215), | |
('DANW019' , .00006947), | |
('DANW020' , .00007495), | |
('DANW021' , .00008293), | |
('DANW022' , .00009184), | |
('DANW024' , .00010857), | |
('DANW025*', .00011875), # from the EXL110BT, an approximation | |
('DANW026' , .00012671), | |
('DANW028' , .00014666), | |
('DANW030' , .00017236), | |
('DANW032' , .00019347), | |
('DANW034' , .00021590), | |
('DANW036' , .00023964), | |
('DANW037*', .00024872), # from the EXL115BT, an approximation | |
('DANW038' , .00026471), | |
('DANW039' , .00027932), | |
('DANW040*', .00029570), # from the EXL120BT, an approximation | |
('DANW042' , .00032279), | |
('DANW044' , .00035182), | |
('DANW046' , .00038216), | |
('DANW048' , .00041382), | |
('DANW049' , .00043014), | |
('DANW050*', .00044720), # from the EXL115BT, an approximation | |
('DANW052' , .00048109), | |
('DANW054' , .00053838), | |
('DANW056' , .00057598), | |
('DANW059' , .00064191), | |
('DANW060' , .00066542), | |
('DANW062' , .00070697), | |
('DANW064' , .00074984), | |
('DANW066' , .00079889), | |
('DANW068' , .00084614), | |
('DANW070' , .00089304), | |
('DANW072' , .00094124), | |
('DANW074' , .00098869), | |
('DANW080' , .00115011), | |
) | |
kalium_plain = ( | |
('CKPL008 ',.0000142401458191), | |
('CKPL0085',.00001607510288), | |
('CKPL009', .0000180219146483), | |
('CKPL0095',.00002008032129), | |
('CKPL010', .0000222518914107), | |
('CKPL0105',.00002453144932), | |
('CKPL011', .0000269251480883), | |
('CKPL0115',.00002942561205), | |
('CKPL012', .0000320389593746), | |
('CKPL0125',.00003476567932), | |
('CKPL013', .0000376052948255), | |
('CKPL0135',.00004055150041), | |
('CKPL014', .000043607), | |
('CKPL015', .000050050), | |
('CKPL016', .000056961), | |
('CKPL017', .000064300), | |
('CKPL018', .000072088), | |
('CKPL019', .000080360), | |
('CKPL020', .000089031), | |
('CKPL021', .000098155), | |
('CKPL022', .000107666), | |
('CKPL023', .000117702), | |
) | |
kalium_hybrid_wound = ( | |
('CKHW021', .000093873), | |
('CKHW022', .000103500), | |
('CKHW023', .000113985), | |
('CKHW024', .000124963), | |
('CKHW025', .000136054), | |
('CKHW026', .000144691), | |
('CKHW027', .000153146), | |
('CKHW028', .000161203), | |
('CKHW029', .000178551), | |
('CKHW031', .000198902), | |
('CKHW033', .000223217), | |
('CKHW035', .000249034), | |
('CKHW037', .000276237), | |
('CKHW039', .000304788), | |
('CKHW041', .000334965), | |
('CKHW043', .000366357), | |
('CKHW045', .000404956), | |
('CKHW047', .000447408), | |
('CKHW049', .000475438), | |
('CKHW051', .000512645), | |
('CKHW053', .000551898), | |
('CKHW055', .000584407), | |
('CKHW057', .000625704), | |
('CKHW059', .000679149), | |
('CKHW061', .000720293), | |
('CKHW063', .000765973), | |
('CKHW065', .000821116), | |
('CKHW067', .000870707), | |
('CKHW070', .000939851), | |
('CKHW073', .001021518), | |
('CKHW076', .001110192), | |
('CKHW079', .001188974), | |
('CKHW082', .001293598), | |
('CKHW086', .001416131), | |
('CKHW090', .001544107), | |
('CKHW094', .001677765), | |
('CKHW098', .001831487), | |
('CKHW102', .001986524), | |
('CKHW106', .002127413), | |
('CKHW112', .002367064), | |
('CKHW118', .002616406), | |
('CKHW124', .002880915), | |
('CKHW130', .003154996), | |
('CKHW136', .003441822), | |
('CKHW142', .003741715), | |
('CKHW150', .004051506), | |
('CKHW158', .004375389), | |
('CKHW166', .005078724), | |
('CKHW174', .005469937), | |
('CKHW182', .006071822), | |
('CKHW190', .006605072), | |
('CKHW200', .007311717), | |
('CKHW210', .008037439), | |
('CKHW222', .009091287), | |
('CKHW232', .009888443), | |
('CKHW244', .010907182), | |
('CKHW254', .011787319), | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
A = 440 | |
notes = { | |
'C' : 0, | |
'D' : 2, | |
'E' : 4, | |
'F' : 5, | |
'G' : 7, | |
'A' : 9, | |
'B' : 11, | |
} | |
rel = (2**(1/12.)) | |
def note2freq(name): | |
sharp = name[1] == '#' | |
flat = name[1] == 'b' | |
if sharp or flat: | |
note = name[0:1] | |
octave = int(name[2]) | |
else: | |
note = name[0] | |
octave = int(name[1]) | |
num = notes[note] | |
if sharp: | |
num += 1 | |
if flat: | |
num -= 1 | |
fullnum = num + 12*(octave - 5) | |
return A*rel**(fullnum + 3) | |
if __name__ == '__main__': | |
test_fmt = '{:3} gave {: 9.2f} Hz\nexpected {: 9.2f} Hz' | |
def test(name, expected): | |
print(test_fmt.format(name, note2freq(name), expected)) | |
test('C2' , 65.41) | |
test('Ab4', 415.30) | |
test('A4' , 440.00) | |
test('B4' , 493.88) | |
test('B#4', 523.25) | |
test('Cb5', 493.88) | |
test('C5' , 523.25) | |
print() | |
test('E4' , 329.63) | |
test('B3' , 246.94) | |
test('G3' , 196.00) | |
test('D3' , 146.83) | |
test('A2' , 110.00) | |
test('E2' , 82.41) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
from strings import print_ideal_stock | |
in_mm = 25.4 | |
default_scale_length = 648/in_mm | |
sets = """ | |
regular light | |
E4 16 PD | |
B3 16 PD | |
G3 16 PD | |
D3 16 WD | |
A2 16 WD | |
E2 16 WD | |
jazz medium | |
E4 24 PD | |
B3 24 PD | |
G3 24 WD | |
D3 24 WD | |
A2 24 WD | |
E2 24 WD | |
regular light (DADGAD) | |
D4 16 PD | |
A3 16 PD | |
G3 16 PD | |
D3 16 WD | |
A2 16 WD | |
D2 16 WD | |
fanned-fret bass | |
G2 35 WC 34.00 | |
D2 35 WC 34.75 | |
A1 35 WC 35.50 | |
E1 35 WC 36.25 | |
B0 35 WC 37.00 | |
regular light (Open G 7-string) | |
D4 16 PD | |
B3 16 PD | |
G3 16 PD | |
D3 16 WD | |
B2 16 WD | |
G2 16 WD | |
D2 16 WD | |
""" | |
string_sets = {} | |
sets = sets+'\n\n' | |
title = None | |
for line in sets.splitlines(): | |
if not line: | |
title = None | |
continue | |
if not title: | |
title = line | |
string_sets[title] = [] | |
else: | |
fields = line.split() | |
note, tension = fields[0:2] | |
tension = int(tension) | |
req = '' | |
if len(fields) > 2: | |
req = fields[2] | |
length = None | |
if len(fields) > 3: | |
length = float(fields[3]) | |
string = (note, tension, req, length) | |
string_sets[title].append(string) | |
print('for a scale length of {:>5.2f} inches'.format(default_scale_length)) | |
for name, strings in sorted(string_sets.items()): | |
print() | |
print('"{}"'.format(name)) | |
print_ideal_stock(strings, default_scale_length) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
from strings import print_tensions | |
in_mm = 25.4 | |
default_scale_length = 648/in_mm | |
sets = """ | |
E standard (super light balanced) | |
E4 DAPL009 | |
B3 DAPL012 | |
G3 DAPL015 | |
D3 DANW022 | |
A2 DANW030 | |
E2 DANW040 | |
E standard (medium balanced) | |
E4 DAPL011 | |
B3 DAPL015 | |
G3 DAPL019 | |
D3 DANW028 | |
A2 DANW037 | |
E2 DANW050 | |
C standard (medium balanced) | |
C4 DAPL011 | |
G3 DAPL015 | |
D#3 DAPL019 | |
A#2 DANW028 | |
F2 DANW037 | |
C2 DANW050 | |
C standard (jazz medium) | |
C4 DAPL013 | |
G3 DAPL017 | |
D#3 DANW026 | |
A#2 DANW036 | |
F2 DANW046 | |
C2 DANW056 | |
C standard (CKS-G6-14-59mb) | |
C4 CKPL014 | |
G3 CKPL019 | |
D#3 CKHW025 | |
A#2 CKHW033 | |
F2 CKHW045 | |
C2 CKHW059 | |
B standard (CKS-G6-14-59mb) | |
B3 CKPL014 | |
F#3 CKPL019 | |
D3 CKHW025 | |
A2 CKHW033 | |
E2 CKHW045 | |
B1 CKHW059 | |
D standard drop C (medium balanced) | |
D4 DAPL011 | |
A3 DAPL015 | |
F3 DAPL019 | |
C3 DANW028 | |
G2 DANW037 | |
C2 DANW050 | |
""" | |
string_sets = {} | |
sets = sets+'\n\n' | |
title = None | |
for line in sets.splitlines(): | |
if not line: | |
title = None | |
continue | |
if not title: | |
title = line | |
string_sets[title] = [] | |
else: | |
note, string = line.split() | |
string_sets[title].append((note, string)) | |
print('for a scale length of {:>5.2f} inches'.format(default_scale_length)) | |
for name, strings in sorted(string_sets.items()): | |
print() | |
print('"{}"'.format(name)) | |
print_tensions(strings, default_scale_length) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
from data import * | |
from notes import note2freq | |
stock = [] | |
stock += daddario_plain_steel | |
stock += daddario_nickle_wound | |
stock += kalium_plain | |
stock += kalium_hybrid_wound | |
uw_const = 386.4 | |
def uw2tension(uw, freq, SL): | |
return (uw*(2*SL*freq)**2)/uw_const | |
def tension2uw(t, freq, SL): | |
return (t*uw_const)/(2*SL*freq)**2 | |
outfmt = '\ | |
{:<8} at {:>6.2f} lb ({:>+4.2f})' | |
finalfmt = '\ | |
average: {:>7.2f} lb ({:>+5.2f})\n\ | |
total: {:>7.2f} lb ({:>+5.2f})' | |
tension_outfmt = '\ | |
{:<3} {:<8} at {:>6.2f} lb' | |
tension_finalfmt = '\ | |
average: {:>7.2f} lb\n\ | |
total: {:>7.2f} lb' | |
def print_ideal_stock(strings, scale_length=25.512): | |
SL = scale_length | |
total_tension = 0 | |
total_desired_tension = 0 | |
for note, tension, req, length in strings: | |
freq = note2freq(note) | |
if length: | |
SL = length | |
else: | |
SL = scale_length | |
uw = tension2uw(tension, freq, SL) | |
kind = len(req) > 0 and req[0] | |
brand = len(req) > 1 and req[1] | |
closest = ('n/a', 0) | |
for name, stock_uw in stock: | |
if kind and kind == 'P' and name[2] != 'P': | |
continue | |
if kind and kind == 'W' and name[3] != 'W': | |
continue | |
if brand and brand[0] != name[0]: | |
continue | |
if abs(stock_uw - uw) < abs(closest[1] - uw): | |
closest = (name, stock_uw) | |
closest_tension = uw2tension(closest[1], freq, SL) | |
diff = closest_tension - tension | |
print(outfmt.format(closest[0], closest_tension, diff)) | |
total_tension += closest_tension | |
total_desired_tension += tension | |
error = total_tension - total_desired_tension | |
average_tension = total_tension/len(strings) | |
average_error = error/len(strings) | |
print(finalfmt.format(average_tension, average_error, total_tension, error)) | |
def print_tensions(strings, scale_length=25.512): | |
SL = scale_length | |
total_tension = 0 | |
for note, name in strings: | |
freq = note2freq(note) | |
uw = 0 | |
for stock_name, stock_uw in stock: | |
if name == stock_name or name + '*' == stock_name: | |
uw = stock_uw | |
break | |
if uw: | |
tension = uw2tension(uw, freq, SL) | |
else: | |
tension = 0 | |
print(tension_outfmt.format(note, name, tension)) | |
total_tension += tension | |
print(tension_finalfmt.format(total_tension/len(strings), total_tension)) | |
if __name__ == '__main__': | |
# DAd's data is all screwy so we use change scale lengths for a best-fit | |
SL = 25.4825 | |
D3 = note2freq('D3') | |
A2 = note2freq('A2') | |
E2 = note2freq('E2') | |
test_fmt = '{:8} {:10.8f} == {:10}' | |
def test(name, unit, tension, note): | |
print(test_fmt.format(name, tension2uw(tension, note, SL), unit)) | |
test('NW024' , '0.00010857', 15.73, D3) | |
test('NW025*', '?' , 17.21, D3) | |
test('NW026' , '0.00012671', 18.38, D3) | |
print() | |
test('NW036' , '0.00023964', 19.04, A2) | |
test('NW037*', '? ', 20.23, A2) | |
test('NW038' , '0.00026471', 20.96, A2) | |
print() | |
SL = 25.18 | |
test('NW039' , '0.00027932', 12.46, E2) | |
test('NW040*', '? ', 13.18, E2) | |
test('NW042' , '0.00032279', 14.37, E2) | |
print() | |
SL = 25.02 | |
test('NW049' , '0.00043014', 18.97, E2) | |
test('NW050*', '? ', 19.68, E2) | |
test('NW052' , '0.00048109', 21.15, E2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment