Merge remote-tracking branch 'string_tensions/master'
This commit is contained in:
commit
07c587287a
5 changed files with 488 additions and 0 deletions
156
data.py
Executable file
156
data.py
Executable file
|
@ -0,0 +1,156 @@
|
||||||
|
# (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),
|
||||||
|
)
|
50
notes.py
Executable file
50
notes.py
Executable file
|
@ -0,0 +1,50 @@
|
||||||
|
#!/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)
|
81
run.py
Executable file
81
run.py
Executable file
|
@ -0,0 +1,81 @@
|
||||||
|
#!/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)
|
||||||
|
|
84
run2.py
Executable file
84
run2.py
Executable file
|
@ -0,0 +1,84 @@
|
||||||
|
#!/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)
|
117
strings.py
Executable file
117
strings.py
Executable file
|
@ -0,0 +1,117 @@
|
||||||
|
#!/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)
|
Loading…
Reference in a new issue