the arithmetic of why no keyboard is in tune
No String Divides Evenly
A real string resists being bent, so its tenth partial is not ten times its first. Pluck one string near your microphone and this page reports B, the stiffness coefficient of that particular string, after the same estimator has recovered five known answers including a synthesised string whose stiffness is exactly zero. Then it turns your B into the cents of octave stretch it forces, which is the reason a piano tuner cannot make every octave beatless and 2:1 at once.
Your string
Pluck or strike one string, once, firmly but not violently, and let it ring. Anything with a string will do: a guitar, a ukulele, a piano, a rubber band stretched over a box. Nothing leaves your device; the recording is held in memory for the few seconds the measurement takes and is never uploaded, stored, or sent anywhere.
not measured
B is dimensionless and small, and for a plain wire it follows from three things you can measure and two you have to look up: diameter, speaking length and pitch, then the wire's density and its stiffness as a material. No tension chart and no gauge table, because tension is whatever puts that wire at that pitch. The looked-up half is where the honest uncertainty would sit: B is directly proportional to Young's modulus, and nothing here measures the modulus of anything. So this page never predicts a B from a string packet. The five specimens are synthesised at a modulus we declare, which makes their B exact by construction whatever real steel does, and your own string's B is measured from the sound it makes and not computed from its dimensions. Four of the five strings on the slate below have stiffness, and they span 3.98e-5, which is what 0.33 mm plain steel gives at 648 mm and 246.94 Hz, to 2.48e-3, which is what 1.00 mm gives at 390 mm and 261.63 Hz. The fifth has none at all, B exactly 0, and it is there to catch an estimator that finds stiffness in everything. Small numbers, and then the arithmetic runs away with them: push B to 0.01 and partial 10 no longer sits at ten times the fundamental, it sits at 14.1 times it, a full 600 cents sharp of where a harmonic ladder would put it. No tuning of any keyboard absorbs that.
What is actually being fitted
A perfectly flexible string, the one in the textbook, has partials at exactly
n F. A real string is a wire, and a wire resists being bent. That bending
stiffness adds a fourth-derivative term to the wave equation, and for a string hinged at
both ends the answer comes out closed form:
fn = n F √(1 + B n2)
Square it and divide by n: (f_n/n)^2 = F^2 + F^2 B n^2. So
plotting the squared partial-over-index against n^2 gives a straight line whose
intercept is F^2 and whose slope is F^2 B. One ordinary least
squares fit, in closed form, with no starting guess and no iteration. Every number this page
reports about a string falls out of that one line, and the interval on B is the delta method
applied to slope over intercept, the standard first-order treatment of a ratio of two
correlated fitted parameters. It is not the only one: Fieller's theorem gives the exact
interval and is wider when the intercept is poorly determined. Here the intercept is
F^2, the best determined number in the whole fit, and the verifier recomputes
Fieller's interval from the same five moments: the two agree to better than one part in
100,000 on all five shipped strings.
Before it measures you, it measures five things it already knows
Five recordings run on the slate below. Every one is synthesised by us from a closed
form, so its true B is exact by construction; the four with stiffness span
--, nearly two decades, and the fifth has none
at all. The same
estimate() runs on all five and on whatever your microphone hears, with no
branch between them: it is handed samples and a sample rate and nothing else, so it has no
way to know which is which. Until it recovers all five, it will not report yours.
running the slate…
The four specimens with stiffness are not generated from the equation being fitted. That would test the FFT and nothing else. They are generated by solving the clamped-end eigenvalue problem numerically, a different boundary condition whose frequencies are not of the form above, and the estimator fits the pinned-end closed form to them. (The fifth has no stiffness to solve for: at B exactly 0 both boundary conditions give the same perfectly harmonic ladder, and that is what it is built from.) The gap between the two models is real physics, and it is what the tolerances are made of. Measured against the exact clamped roots of the four stiff ones, the clamped end turns out to act almost entirely as a common factor on every partial (well fitted by 1 + (2/π)√B + (4/π2)B), which the fit absorbs into F and not into B: what is left over in B is +0.12 per cent on the most flexible of them, +0.14 per cent at its largest anywhere on the slate, and −2.5 per cent on the stiffest.
What a fake would do
The same five specimens, run through an estimator that ignores its input entirely and always returns the anchor's value with a small error bar. It sails through the anchor. It cannot pass four controls at four different values at once. This is executed on your device, right now, not promised.
…
The objection this page exists to answer
Here it is, at full strength, and it is not a strawman:
You did not measure stiffness. You fitted a curve with a free parameter to a decaying pluck. Any non-stationary or noisy spectrum will hand you a nonzero B. Your number is an artefact of how hard you hit the string.
That is true of the obvious implementation, and it is true for a specific mechanical reason. A hard pluck stretches the string enough to raise its own pitch, and the pitch falls back over the first half second as the amplitude decays. High partials die fastest, so inside any long analysis window they are weighted toward the early, sharp part of the recording. That weighting rises with partial number the way stiffness does, and it is close enough to fool a single fit. It is not close enough to fool the exponent test below, which is the point of having one. A perfectly flexible string, plucked hard, will report stiffness it does not have.
So here is that failure, shipped, and made operable. This specimen is the harmonic control from the slate above, same synthesis, same seed, same phases, same hiss, same decay envelope, with one thing added: 60 cents of downward pitch glide decaying with a 0.5 second time constant. Its true B is exactly 0. Press the button and watch the same estimator invent stiffness out of it.
The trap
not run
The answer is not a better fit. The answer is that stiffness is a constant of the string, and a constant does not care which half second you look at. So the analysis window is not a detail, it is the load-bearing free choice on this page, and the honest thing to do with a load-bearing free choice is to sweep it and show the reader the shape. Run the anchor through the same sweep and compare.
B against window length
not run
Each line is divided by its own value at the 0.5 second window, because the point is the shape and not the magnitude: a constant of the string is a flat line at 1, whatever its size. The raw numbers are underneath, unnormalised, so nothing hides in the normalisation.
There is a second discriminator, free, from the same fit. Stiffness says the stretch grows
as n^2 and as nothing else. Refit with the exponent free, f_n = n F
(1 + B n^p)^(1/2), and see where p lands. For any fixed p
the model is still a straight line in n^p, so the two linear parameters profile
out exactly and only p has to be searched. On the four shipped strings that
have stiffness it comes back between 1.975 and
2.000, the worst of them being the stiffest string, where the
clamped-versus-pinned gap is largest. On the trap it does not come back at 2 at all, and the
number is printed in the trap panel above rather than described here.
And there is a third one, which costs nothing and is the only test here that needs no
threshold at all. B = pi^2 E I / (T L^2): Young's modulus, the second moment of
area, the tension and the length are every one of them positive, so B is positive for every
string that exists. A fit whose whole interval sits below zero has therefore not
measured a small stiffness, it has measured something that is not stiffness, and no
tolerance had to be chosen to say so. It is reachable: a pitch that rises as it rings
puts it there, which is what a bent note let back, or a peg still settling, or a new string
still stretching does. This page refuses that recording instead of printing a negative
stiffness coefficient. The one thing the rule must not do is catch a genuinely flexible
string, whose B is small and whose interval covers zero from both sides, and the check below
runs the B = 0 specimen through it at every window to make sure it does not.
A prediction you can break in ten seconds
B is proportional to 1 / (T L2): tension and speaking length, and nothing about how hard you played. Stop a string at the twelfth fret and you have halved L without changing the wire or its tension, because the twelfth fret is the halfway point by the definition of a fretboard. So B has to go up by a factor of four. Not roughly four. Four.
This is a prediction of the model this page fits, not a published measured result, and it is the reader's independent way to falsify the whole apparatus. Here it is on the shipped pair, which is the same wire at 648 mm and at 324 mm:
…
Now yours. Measure your open string with the button at the top, then stop it at the twelfth fret, pluck again, and press this.
Your fret test
open string: not measured yet stopped at the twelfth fret: not measured yet
Honest edges, stated before you run it rather than after it disagrees. A real bridge is compensated by a few millimetres, so the stopped length is not exactly half. Pressing the string down behind a fret raises its tension, which pushes the ratio below four. A wound string is not a uniform wire at all and its bending stiffness is not what this geometry predicts. Any of those can move the number, and a ratio that comes back at 3.2 is a result about your instrument, not a bug on this page.
What your number does to an octave
Here is where B stops being a curiosity. An octave can be tuned by measuring a frequency ratio, or it can be tuned until it stops beating, and on a stiff string those are not the same octave. Beating is between partials, so which pair you silence is a choice. Take the obvious one first: the lower note's second partial against the upper note's first. Set those equal:
Fup √(1 + B) = 2 Flow √(1 + 4B)
so the beatless octave is not 2:1 but 2 sqrt((1+4B)/(1+B)), which is
600 log2((1+4B)/(1+B)) cents wide of it. At B = 0 that is exactly zero, which
is the whole reason a perfectly flexible string was ever a good idea. On any real string it
is not zero, and there is no way to have both.
And that is one choice of pair, not the only one. Silence the lower note's fourth
partial against the upper note's second instead, and the same algebra with both partial
numbers doubled gives 600 log2((1+16B)/(1+4B)); the sixth against the third
gives 600 log2((1+36B)/(1+9B)). These are not small differences and they are not
a refinement of the first answer, they are different answers to a differently posed question.
For B small they come out at four times and nine times the number above, because the stretch
is riding on B n^2 and n has been doubled or tripled. All three are printed
below from your own B, because picking one and printing it alone would be presenting a
choice as a fact. Nothing on this page tells you which pair a tuner in front of a real piano
silences, because we have not read a source that would let us say.
The octave your string forces
source: --, B = --
- Silencing the lower note's 2nd partial against the upper note's 1st, one octave has to be -- cents wider than 2:1. Silencing the 4th against the 2nd instead: -- cents. The 6th against the 3rd: -- cents. Same string, same B, same arithmetic, three answers.
- If every string on an instrument had this B, and every octave were tuned by the first of those three rules, the top of a seven-octave compass would end up -- cents above where equal temperament puts it. -- Under the second rule it would be -- and under the third --, and that spread is the choice of rule alone, with the measurement held fixed.
That second line is a conditional and it is written as one on purpose. B is not a constant of an instrument, it is a constant of a string, and it changes from string to string. Take the formula at the top of this page and scale a keyboard the ideal way, halving the speaking length for every octave up and keeping the wire: L goes as 1/f0, and B = π2E d2 / (64 ρ L4 f02) collapses to B proportional to f02. Stiffness quadruples every octave you go up. The fret test above is exactly that factor of four, on your own instrument, in ten seconds. Which is why a stretch curve worked out string by string bends upward instead of running straight.
What we could not put beside it
The intention was to lay your number against the published Railsback curve, the measured stretch of real tuned pianos. We are not going to, because the papers we went to for it return 403 to us, and quoting a magnitude we have not read would be the one thing this project does not do. Here is the state of each source, and which of them we did read.
- Railsback's 1938 paper is a one-page abstract in a JASA supplement (doi:10.1121/1.1902056). The publisher's site returns 403 to us, so we have not read it and quote no figure from it.
- Fletcher's 1964 paper (doi:10.1121/1.1918933) is the paper this literature points to for the relation at the top of this page: Murray's companion article, which we did read, says the model “was brought into the active literature by NH Fletcher in the 1960s” and cites this paper as where he laid the maths out. We did not read it ourselves; pubs.aip.org returns 403 to us, checked again on 2026-08-17, and so does its two-page erratum in the same volume (doi:10.1121/1.1919187). A two-page correction to a seven-page paper is not a footnote, so no value from it appears anywhere on this page, and the equation is used because it is derivable from the wave equation here rather than because it is printed there. We do not call it the origin either: JASA published R. W. Young, Inharmonicity of Plain Wire Piano Strings, 24(3), 267–273 (doi:10.1121/1.1906888), twelve years earlier, and that is behind the same 403.
- Giordano (doi:10.1121/1.4931439) argues that inharmonicity plus sensory dissonance quantitatively predicts the stretch. We read the abstract only, and we cite it for the existence of that argument, not for any number.
- Murray and Whitfield's Inharmonicity in plucked guitar strings (doi:10.1119/5.0064373) compares B derived from string material against B derived from audio. That paper is behind the same 403, so what we have of it is the abstract, which says “very good agreement between the two determinations of B for monofilament strings” and “rather poor agreement for wound strings”, and no percentage at all. The two magnitudes below are therefore not from it. They are from Chris Murray's earlier open companion article, Musical String Inharmonicity, in ASTRA: The McNair Scholars' Journal (UW–Eau Claire, 2021), pages 17–26, which we did read in full from that archived issue: half of the monofilament strings tested gave B ranges that did not overlap between the two methods, and “almost all of those only disagreed by a one to two percentage points or less”, while for the wound strings “none of the value ranges for the 2 testing methods provided overlaps”. That is why the fret test above is offered on a plain string and why a wound string is called out as a known disagreement rather than as a failure of your playing. It is also the only evidence anywhere near this page that audio-derived B matches material-derived B on real strings at all, which is worth saying plainly: every specimen our own estimator has been validated against is synthetic.
So what is on this page instead is arithmetic that anyone can check, five specimens whose answers we generated ourselves, and your own string.
Every free choice this page made
Each of these moves the answer. They are read out of the estimator's own constants object at run time, so this table cannot state a setting the code does not use.
| choice | set to | why, and what it costs |
|---|---|---|
| analysis window | The load-bearing one. Short enough that the pluck's own pitch glide has mostly decayed, long enough for the partials to separate. Longer windows fabricate stiffness, which is what the sweep above is for. | |
| attack skip | Skipped after the loudest frame, to clear the hammer or plectrum noise, which is broadband and would raise the local median that the prominence gate measures against. | |
| pitch band | Where the fundamental is looked for. A string below or above it is refused rather than measured wrongly, and until 2026-08-17 that sentence sat here without being true. The pitch finder searches a range of periods and returns the best it saw; on a string too low for the range there is no real peak anywhere in it and the search hands back the edge, which is not a detection. Fed a bass guitar's low E at 41.2 Hz, this page used to answer B = −3.7e-3 with a fundamental of about 480 Hz and a window sweep that read flat, and it did the same for a low B and for a piano's bottom octave. It now recognises a search that ran to its own edge and says so. A number that is refused is the cheapest kind of honesty on this page; the expensive kind was finding out it was not being refused. | |
| prominence gate | A candidate partial under this is dropped, not fitted. Dropping partials widens the interval; keeping noise would move the answer. | |
| minimum partials | Below this the page refuses. B lives in the high partials. Three points would already leave one residual degree of freedom, and an interval built on one degree of freedom is mostly luck; six is the fewest that gives the slope anything to stand on. | |
| partial ceiling | Above 0.45 of the sample rate a partial is unreliable. This one costs more than it looks: until 2026-08-17 this cell said fewer partials buy a wider interval, which is true and is not the whole cost. On a string whose ends are clamped rather than hinged, where this fit is an approximation, the ceiling moves the answer itself. Fitting the pinned form to the exact clamped partials of the shipped anchor returns B +0.46 per cent high over six partials and −0.37 per cent low over thirty, crossing zero in between; on the stiffest string here it runs +0.51 to −2.53. So the count is printed because it is part of the answer, not only part of the error bar. The ceiling of 30 binds below 720 Hz at every sample rate a browser offers, so it is the same choice for every reader whose string is lower than that. | |
| zero padding | Interpolation only. It adds no information and cannot beat 1/T; it removes bin snapping before the parabolic peak fit, and the final frequency is refined off the grid by Goertzel anyway. | |
| sweep ladder | The window lengths the flatness test uses. The top of it is capped by how much recording follows your pluck; where it does not fit, the page says so and drops that point rather than shortening it silently. | |
| flatness thresholds | Spread inside three sigma is called flat. Spread beyond half of B itself is called not stiffness and the number is refused. Between the two the interval printed in the readout is the widened one, stretched to cover every window the sweep ran, and the number is marked provisional. Fewer than three windows fitting at all is a fourth verdict, inconclusive, and it says so rather than borrowing one of the other three. Whose sigma is a real choice and it is the largest in the sweep, which errs permissive: a bad window raises the threshold as well as the spread, so a worse recording is judged more leniently. The stricter reading, the smallest sigma, was tried and it refuses the specimen that has to pass: on the string with B exactly 0 the spread is 2.2e-8 against a smallest sigma of 2.3e-9, so a rule built on it calls a flat line at zero contaminated. Neither reading is free, and this is the one whose failures are visible in the other tests. |
What this cannot do
- It is not a tuner and it will not tell you how to tune anything, and a large B is not a fault report on your instrument. B follows from the wire's diameter, the speaking length and the pitch by the formula above, and from nothing about how the instrument is kept.
- A piano note is two or three strings tuned a cent or two apart. Each partial is therefore split into two or three peaks, and the tracker takes whichever is loudest. Until 2026-08-17 this line told you to expect ten per cent of error on a piano's middle range. That figure was never measured by anyone here. It came off a planning note, citing a prototype that was never run in this repository, and it sat on the page for as long as the page existed. Seven synthesised unisons do now get run, by the check below: two and three strings, detuned by one to three cents, with equal amplitudes and decays and with deliberately unequal ones. The split moves B by 0.60 per cent at worst. Which is a statement about seven synthetic notes and not about your piano, because no real piano has ever been through this pipeline.
- A wound string is a core with a winding on it, not a uniform wire. Its stiffness is real and this page will measure it, but the geometry route that predicts B from diameter and length does not apply, and the comparison cited below found no overlap at all between the two routes on any wound string it tested.
- The equation this page fits is exact for a string hinged at both ends. A nut, a bridge saddle and a piano agraffe are none of them hinges, and none of them are perfect clamps either; a real string's ends sit somewhere between the two. That gap is not only a property of the specimens on the slate, it applies to your string as well, and this page does not correct for it or fold it into the interval. Solving the clamped problem exactly says where it goes: almost all of it lands on the fundamental rather than on B. At the stiffness of a plain guitar string it moves F by about 0.4 per cent and B by about 0.1; it only becomes a B effect worth naming on a piano-treble string, where it reaches 2.5 per cent on the stiffest specimen here. If your ends are nearer clamped than hinged, that is the size of the systematic sitting under your number.
- Body and soundboard resonances pull individual partials by a cent or two, and a string vibrating in two planes at slightly different frequencies splits its peaks. Both inflate the fit residuals and therefore the interval. The RMS residual of the straight line through your own partials is printed under the readout, and no partial is ever dropped for disagreeing with the line: residuals are left where they are and paid for in the interval.
- If your browser will not turn its noise suppression off, the spectrum reaching this page has been reshaped before it arrived. The page reads back what the track actually granted and says so under the readout.
The check, in full
…
Offline, node research/inharmonicity-railsback/verify-inharmonicity-railsback.mjs
regenerates all eight WAV files from their closed forms and compares sha256 against the
committed bytes, loads this page's own inharm.js in a sandbox rather than
reimplementing it, recomputes the five declared truths from the geometry, checks that the
clamped-versus-pinned model gap is where this page says it is, requires the trap to trip
the flatness test and a hard-coded stub to fail the slate, drives the one sweep verdict
nothing on this page reaches, recomputes Fieller's interval against the one printed here,
and asserts each refusal path fires on a signal built to trigger it. Since 2026-08-17 it
also builds the seven synthesised unisons quoted above and measures what the split really
costs, drives all three arms of the fret test including the one that refuses to call a
band too wide to separate 4 from 3 a confirmation, and requires the negative-stiffness
refusal to fire on a ladder that goes flat as it rings while leaving the string with B
exactly 0 measured rather than refused. Where this page
prints a number to two or three decimals, that check formats the recomputed value the same
way and compares the text, rather than accepting any value inside a band. It reports
262/262 checks passed.
Separately, node scripts/check-live-sensor.mjs --only=inharmonicity-railsback
launches a real Chromium, replaces the microphone with a WAV of known B, and drives this
page's own capture path. It asserts that the slate arms, that a hard-coded estimator does
not arm it, that the live path recovers the injected value, that a different
injected value moves the reported number with it, and that refusing permission produces a
structured refusal rather than a crash or a plausible number.
Sources
- Harvey Fletcher, Normal Vibration Frequencies of a Stiff Piano String, JASA 36(1), 203–209 (1964), doi:10.1121/1.1918933, and its erratum, JASA 36(6), 1214–1215 (1964), doi:10.1121/1.1919187. Not read, 403. Cited for the form of the relation only. No table or numeric value from either is used here, for the reason given above.
- R. W. Young, Inharmonicity of Plain Wire Piano Strings, JASA 24(3), 267–273 (1952), doi:10.1121/1.1906888. Not read, 403. Cited for its existence and its date, which are the reason this page does not name Fletcher's 1964 paper as the origin of anything.
- O. L. Railsback, Scale Temperament as Applied to Piano Tuning, JASA 9(3 Supplement), 274 (1938), doi:10.1121/1.1902056. Cited for existence. Not read, 403.
- N. Giordano, Explaining the Railsback stretch in terms of the inharmonicity of piano tones and sensory dissonance, JASA 138(4), 2359–2366 (2015), doi:10.1121/1.4931439. Abstract read, full text 403.
- C. J. Murray and S. B. Whitfield, Inharmonicity in plucked guitar strings, American Journal of Physics 90(7), 487–493 (2022), doi:10.1119/5.0064373. Abstract read, full text 403. No magnitude on this page comes from it.
- Chris Murray, Musical String Inharmonicity, in ASTRA: The McNair Scholars' Journal, University of Wisconsin–Eau Claire (2021), pages 17–26. Read in full. The open companion to the paper above, and the source of the only two magnitudes about real strings quoted anywhere on this page: the one to two percentage point disagreement on monofilament strings, and the absence of any overlap on wound ones.
- The specimens carry no licence, because there is no third-party work in them: every WAV
on this page is generated by our own code from our own closed forms at build time. The
generator is
research/inharmonicity-railsback/make-specimens.mjsand the clamped-end solver it calls isresearch/inharmonicity-railsback/strings.mjs.