I think the clock analogy is a bit confusing, it suggests there is some time involved here. It’s for any scalar value.
And it doesn’t use cosines, just modulo 1 to output values between 0 and 1
Here-s a code snippet:
# multi cycle encoder. As CycleEncoder yet its period varies linearly between a min and a max value
def VarCycleEncoder(sdr_size, period = 1, sdr_len = 0, seed = None):
me = Self()
if sdr_len == 0:
# Arbitrary initial sdr length.
sdr_len = sdr_size // 4
periods = np.linspace(period, period * math.e, sdr_size)
r = np.linspace(0,1, num = sdr_size, endpoint = False, dtype = np.float32)
r += 0.5 / sdr_size
np.random.seed(seed)
np.random.shuffle(r)
np.random.shuffle(periods)
@numba.njit
def dense(x):
return (r + x / periods) % 1
@numba.njit
def sdr(x, slen = sdr_len):
# dense2sdr(v, k) simply outputs 1 for top k values in v, and 0 for all others
# That's basic "sdr-ification" of the dense vector v
return dense2sdr(dense(x), slen)
me.dense, me.sdr, me.periods, me.r = dense, sdr, periods, r
return me
# Self is an empty class:
class Self: pass
# dense2sdr(vector, k) just return the indices of highest k values in vector