Jitter

Jitter is the random modulation of a value. It is usually bipolar, meaning that it might shift a value upwards or downwards.

On a normalised scale of 0..1 scale, let's say we want to apply jitter of 10% to a value of 0.5. If the jitter was to be absolute, that yields a potential new value of 0.4 - 0.6. An algorithm for this is:

// repl-pad
import { clamp } from 'https://unpkg.com/ixfx/dist/bundle.js';

const jitter = (value, jitter) => {
  // Double jitter in order to +- and apply random
  const j = jitter * 2 * Math.random();
  // Offset value, add j and clamp to 0-1
  return clamp(value - jitter + j);
}
// Jitter a value of 50% by 10%
// Yields a range of 0.4-0.6
jitter(0.5, 0.1);

Another option is to jitter by a relative amount, with respect to the input value. In that case, jittering 0.5 by 10% yields a range of 0.45 - 0.55, because 10% of 0.5 is 0.05. Thus for a given jitter amount, a larger input value will jitter more wildly than a smaller value, creating a sense of instability.

ixfx provides both of these approaches with jitter.

// repl-pad
import { jitter } from 'https://unpkg.com/ixfx/dist/modulation.js';

// Absolute jitter 0.5 by 10%
jitter({ absolute: 0.1 })(0.1); // number 0.4-0.6

// Relative jitter 0.5 by 10%
jitter({ relative: 0.1 })(0.5); // number 0.45-0.55

Remember that jitter returns a function (which is why there's the double parenthesis in the example above). This is so the same jitter options can be reused without scattering them all over the place.

// One-time setup
const jitterFn = jitter({ absolute: 0.1 });

// Re-use the function when you like
jitterFn(100); // Jitter 100 by an absolute 10%;
jitterFn(50);  // Jitter 50 by an absolute 10%

Try adjusting the value-to-jitter and jitter amount:

By default jitter uses Math.random, but you could just as well plug in a weighted, or gaussian random number generator.

import { jitter } from 'https://unpkg.com/ixfx/dist/modulation.js';
import { gaussian } from 'https://unpkg.com/ixfx/dist/random.js';

// Note we pass in as a function, so no () after gaussian
const jitterFn = jitter({ absolute:0.2, source: gaussian });

In the plot below, notice how jitter is more likely to be close to the original value, instead of being evenly distributed across the whole specified jitter range. A more organic outcome?