Inductosyn Encoder meshing

We use an inductosyn encoder system for both the elevation and azimuth axes of the MMT telescope. Each encoder is read in two parts, consisting of a pair of 16 bit words. The resolver changes slowly passing through its full range of values in a 360 degree motion. The indexer moves 512 times faster, passing through a full range of values every 360/512 degrees.
(360/512 = 0.703125 degrees = 42.1875 arc-seconds).

The raw values are laid out like this:

Resolver:

--------------------
|    r9   |r3 | r4 |
--------------------

Indexer
--------------------
|i3 |    i13       |
--------------------

This is 32 bits of information, but 7 bits are redundant, so that 32 bits of raw data reduces to 25 bits of actual encoder resolution. This gives us 93206.756 counts per degree (25.89 counts per arc-second), or put another way one encoder count is 0.0386 arc-seconds of angular motion.

Unfortunately combining the two "halves" of the encoder is not as simple as trimming off the 7 redundant bits and juxtaposing the remaining pieces. In the diagram above, the low 4 bits of the resolver (r4) is indeed discarded, and then the overlapping 3 bit sections r3 and i3 are considered to determine whether a bit needs to be carried into or borrowed from the upper 9 bits of the resolver (r9). Once r9 has been adjusted by this carry or borrow, then indeed r9 + i3 + i13 are concatenated and yield the 25 bit output value.

A number of mysterious algorithms have been used over the years to properly "mesh" the resolver and indexer values. A value known as the "coarse offset" is a fudge factor for the original algorithm, and can have 8 possible values (since it adjusts the 3 overlapping bits r3 and i3). A streamlined version of the original algorithm (in the ruby language) is as follows:

def combine2 ( resolver, indexer, coffset )

        value = (resolver>>4) + coffset

        c3 = value & 0x7
        f3 = indexer >> 13

        fix = f3 - c3

        if fix > 4
            fix -= 8
        end
        if fix < -4
            fix += 8
        end

        value += fix
        value >>= 3

        return (value << 16) | indexer
end

The value for the coarse offset coffset is 3 for the elevation axis, and currently -7 for the azimuth axis. (The coarse offset for azimuth was -4 prior to December of 2005).

Another algorithm, demonstrated to be correct for elevation, but not for azimuth is:

def mesh ( resolver, indexer )

    cd = resolver >> 5
    ab = indexer >> 14

    if (ab == 0)
        cd += 2
    end

    if (ab == 1)
        cd += 1
    end

    if (ab == 3)
        cd -= 1
    end

    out = (cd & 0xfffc) << 14
    return out | indexer

end

The following are some meshing tables from the original an new algorithm. These algorithms are not identical for any values of the coarse offset supplied to the original algorithm, but are close for a coarse offset value of 1.

The meshing table indicates whether a borrow, or carry, or no change occurs to the upper 9 bits of the resolver value based on the values of the 3 bits in the overlap zone. The values 0-7 across the top are the 3 bits from the indexer, and the values 0-7 along the left are the 3 bits from the resolver.

Here is the meshing table for the original algorithm with a coarse offset of 3

      0   1   2   3   4   5   6   7
-----------------------------------
  0 | 0   0   0   0   0   0   0   0
  1 | 0   0   0   0   0   0   0   0
  2 | 1   0   0   0   0   0   0   0
  3 | 1   1   0   0   0   0   0   0
  4 | 1   1   1   0   0   0   0   0
  5 | 1   1   1   1   1   0   0   0
  6 | 1   1   1   1   1   1   0   0
  7 | 1   1   1   1   1   1   1   0

Here is the meshing table for the original algorithm with a coarse offset of 1

      0   1   2   3   4   5   6   7
-----------------------------------
  0 | 0   0   0   0   0   0  -1  -1
  1 | 0   0   0   0   0   0   0  -1
  2 | 0   0   0   0   0   0   0   0
  3 | 0   0   0   0   0   0   0   0
  4 | 1   0   0   0   0   0   0   0
  5 | 1   1   0   0   0   0   0   0
  6 | 1   1   1   0   0   0   0   0
  7 | 1   1   1   1   1   0   0   0

Here is the meshing table for the new algorithm

      0   1   2   3   4   5   6   7
-----------------------------------
  0 | 0   0   0   0   0   0  -1  -1
  1 | 0   0   0   0   0   0  -1  -1
  2 | 0   0   0   0   0   0   0   0
  3 | 0   0   0   0   0   0   0   0
  4 | 1   1   0   0   0   0   0   0
  5 | 1   1   0   0   0   0   0   0
  6 | 1   1   1   1   0   0   0   0
  7 | 1   1   1   1   0   0   0   0