Calculating Fret Distances

Overview

I recently asked a friend of mine who is a machinist to make a straightedge for me which has notches on one side, which will allow the straightedge to rest on the fingerboard of a guitar without interference from the frets. He asked me to give him a list of the distances of each fret from the previous. I wrote a program to do these calculations. This is a semi-common task that the luthier is required to do, and it's a fairly interesting intellectual exercise, so I've decided to describe the process here.

Using Classical Physics to Calculate Fret Distances

In classical physics, wavelength, usually denoted with the greek letter lambda, is defined to be the inverse of frequency, usually denoted simply with the letter f. It happens to be the case that to calculate frequencies of succeeding half-tones using equal temperament, one takes the frequency of the previous note and multiplies it by the twelfth root of two. This is because we want to construct a sequence of twelve frequencies such that the twelfth frequency is exactly double the first frequency. Note that for a frequency f, it holds that
(1) 2f = (21/12)12 x f,
thus our coefficient for f here meets our need. So starting with any frequency, we can calculate the frequency which should follow in the twelve note chromatic scale, using the equation
(2) f2 = 21/12 x f1.
Note, however, that this does not tell us directly what we need to know, which is the distance between each fret on the guitar neck. But consider that for each fretted note on the guitar, when the string is plucked, a standing wave is created with nodes at the bridge and at the point where the string is fretted. The distance between these two nodes is the wavelength associated with the frequency at which this standing wave vibrates. (Actually, I believe this distance is really half the wavelength, but since we're calculating all of these distances relative to each other, the 1/2's cancel out, so the equation works as it is.) Thus we can substitute wavelength in equation 2 above to give
(3) 1/lambda2 = 21/12 x 1/lambda1.
This is all we need to calculate what we want to know. So, for example, on a guitar with a 25.5" scale length (scale length being the distance between the nut and the bridge), like a Fender Stratocaster or similar guitar, the distance between the first fret and the bridge would be 25.5"/(21/12) =~ 24.0688". Then the distance between the nut and the first fret would be 25.5" - 24.0688" =~ 1.4312". Similarly, the distance between the second fret and the bridge would be 24.0688"/(21/12) =~ 22.7179", and the distance between the first fret and the second fret would be 24.0688" - 22.7179" =~ 1.3509". One can calculate the rest of the fret distances in this fashion.

A Fret Scale Calculator Written in Java

To perform these calculations, I've written the following program in Java. In order to run it, you'll need to have a Java compiler and a Java runtime environment. It should work with any version of Java. If you have questions regarding compiling and running the calculator, feel free to email me at ihsahn[at]cs.jhu.edu.
  /**
    Written 06/12/2003 by Samuel Carliles.  Use the code as you wish, but
    don't start selling it and then come and sue me for having it posted
    publicly.  Also include this comment and leave it intact if you choose
    to distribute the code for some reason.
  */
  public class FretScale
  {
    public static void main(String[] args)
    {
      if(args.length < 3)
      {
        System.err.println("Usage: FretScale numFrets scaleLength precision");
        System.err.flush();
        System.exit(1);
      }

      FretScale scale = new FretScale(Integer.parseInt(args[0]),
                                      Double.parseDouble(args[1]),
                                      Integer.parseInt(args[2]));

      System.out.println(scale);
      System.out.flush();
    }

    public FretScale(int numFrets, double scaleLength, int precision)
    {
      setNumFrets(numFrets);
      setScaleLength(scaleLength);
      setPrecision(precision);
    }

    public int getNumFrets()
    {
      return _numFrets;
    }

    public double getScaleLength()
    {
      return _scaleLength;
    }

    public int getPrecision()
    {
      return _precision;
    }

    public double[] getDistancesFromBridge()
    {
      double[] result = new double[getNumFrets()];
      double lambda1 = getScaleLength();
      double factor = Math.pow(2.0, 1.0 / 12.0);

      for(int i = 0; i < getNumFrets(); ++i)
      {
        double lambda2 = lambda1 / factor;

        result[i] = lambda2;
        lambda1 = lambda2;
      }

      return result;
    }

    public double[] getDistancesFromNut()
    {
      double[] result = new double[getNumFrets()];
      double[] dFromBridge = getDistancesFromBridge();

      for(int i = 0; i < getNumFrets(); ++i)
      {
        result[i] = getScaleLength() - dFromBridge[i];
      }

      return result;
    }

    public double[] getDistancesFromPreviousFret()
    {
      double[] result = new double[getNumFrets()];
      double[] dFromBridge = getDistancesFromBridge();
      double lastD = getScaleLength();

      for(int i = 0; i < getNumFrets(); ++i)
      {
        result[i] = lastD - dFromBridge[i];
        lastD = dFromBridge[i];
      }

      return result;
    }

    public String toString()
    {
      return "Number of Frets: " + getNumFrets() + "\n" +
        "Scale Length: " + roundTo(getScaleLength(), getPrecision()) + "\n" +
        "Precision: " + (1.0 / Math.pow(10, getPrecision())) + "\n\n" +
        "Distances from Bridge\n" +
        "=====================\n" +
        printArray(getDistancesFromBridge(), getPrecision()) + "\n" +
        "Distances from Nut\n" +
        "==================\n" +
        printArray(getDistancesFromNut(), getPrecision()) + "\n" +
        "Distances from Previous Fret\n" +
        "(Nut in case of 1st Fret)\n" +
        "============================\n" +
        printArray(getDistancesFromPreviousFret(), getPrecision());
    }

    protected FretScale()
    {
    }

    protected String printArray(double[] a, int precision)
    {
      String result = "";

      for(int i = 0; i < a.length; ++i)
      {
        String numStr = roundTo(a[i], precision) + "";
        int gap = precision - numStr.replaceAll(".*\\.", "").length();

        for(int j = 0; j < gap; ++j)
        {
          numStr += "0";
        }

        result += (i + 1) + ": " + numStr + "\n";
      }

      return result;
    }

    protected double roundTo(double n, int precision)
    {
      double magnitude = Math.pow(10, precision);

      return Math.round(n * magnitude) / magnitude;
    }

    protected void setNumFrets(int numFrets)
    {
      _numFrets = numFrets;
    }

    protected void setScaleLength(double scaleLength)
    {
      _scaleLength = scaleLength;
    }

    protected void setPrecision(int precision)
    {
      _precision = precision;
    }

    protected int _numFrets;
    protected double _scaleLength;
    protected int _precision;
  }