Search code examples
javascriptmathnormal-distribution

Distribute load via normal distribution over 24 hours with the peak at noon?


I'm trying to unevenly distribute a load over each hour of a day with peak handling around noon when more people are available. Basically, I want a "Normal Distribution" of tasks as apposed to a simple n / 24 = hourly load.

The goal is that most of the work needs to be handed out during the middle of the day with less work early in the morning and late at night.

Normal Distribution Chart

This is as far as I've gotten producing something of a curve.

// Number per day
const numberPerDay = 600;
const numberPerHour = numberPerDay / 24;

let total = 0;
for (let hour = 1; hour < 24; hour++) {
  // Normal Distribution should be higher at 12pm / noon
  // This Inverse bell-curve is higher at 1am and 11pm
  const max = Math.min(24 - hour, hour);
  const min = Math.max(hour, 24 - hour);
  const penalty = Math.max(1, Math.abs(max - min));

  const percentage = Math.floor(100 * ((penalty - 1) / (24 - 1)));
  const number = Math.floor(numberPerHour - (numberPerHour * percentage / 100));

  console.log(`hour: ${hour}, penalty: ${penalty}, number: ${number}`);
  total += number;
}

console.log('Expected for today:', numberPerDay);
console.log('Actual for today:', total);

Live jsfiddle.

Which produces something like this:

demo chart


Solution

  • You need to implement a Gaussian function. The following link might be helpful: https://math.stackexchange.com/questions/1236727/the-x-y-coordinates-for-points-on-a-bell-curve-normal-distribution

    You would need to choose your mean and standard deviation (sigma). Here is a snippet I found:

    //taken from Jason Davies science library
    // https://github.com/jasondavies/science.js/
    function gaussian(x) {
        var gaussianConstant = 1 / Math.sqrt(2 * Math.PI),
        mean = 0,
        sigma = 1;
        x = (x - mean) / sigma;
        return gaussianConstant * Math.exp(-.5 * x * x) / sigma;
    };
    

    https://gist.github.com/phil-pedruco/88cb8a51cdce45f13c7e

    To get it to do 0-24 you set the mean to 12 and adjust the sigma to spread the curve out as much as you need. You'll also want to scale the "y" value a little bit.

    Update

    I have created a JS Fiddle for you that plots what I think you need. https://jsfiddle.net/arwmxc69/2/

    var data = [];
    var scaleFactor = 600
            mean = 12,
            sigma = 4;
    
    function gaussian(x) {
        var gaussianConstant = 1 / Math.sqrt(2 * Math.PI);
        x = (x - mean) / sigma;
        return gaussianConstant * Math.exp(-.5 * x * x) / sigma;
    };
    
    for(x=0;x<24;x+=1) {
        var y = gaussian(x)
        data.push({x:x,y:y*scaleFactor});
    }