Normal / U-Distributions with sin(), random(), randomGaussian() and map()

edited October 2016 in How To...

Excuse the newbieness but:

I need to distribute the numbers from a[30]={ABC...} in b[300] slots. let's say m=30, n=300. Usually we just do:

delta = m/n for (int c=0; c<=n; c++) { int ix= round(c*delta); b[c]=a[ix] }

so b={AAAAAAAAAABBBBBBBBBBCCCCCCCCCC...}

The thing is that the values are distributed evenly. I mean, if the actual distribution is {10,10,10,10,10,10,10,10,10} I need it now {15,12,11,10,7,10,11,12,15} or something like that ("slower" increment/decrement at the ends)

I'm making sense?

Thanks for any help!

Answers

  • @grumo I'm not sure I understand what distribution you want, but it sounds like you can either:

    1. Just use randomGaussian() to populate your 300 slots if you want a Gaussian distribution
    2. write a function for your curve.

    E.g.

    float myCurve(float x){
      float y = x; // change to formula for your curve
      return y;
    }
    

    Then loop through i<300, call myCurve(i), and save the result in your array. If you actually just need to return a (letter grade?) instead, just have myCurve return char letter.

  • Thanks jeremy! What could be the formula for a curve that goes like the distribution like this one: 18,11,7,4,2,1,0,1,2,4,7,11,18-? basically I need something like a inverted bell curve that cold be expressed in simple terms (not interested in too much detail, just something that gives bigger values at the beginning, shorter values in the middle and then bigger ones again at the end)

  • Answer ✓

    look at map

    y= map(x,0,300,0,36);

    y=y-18;

    y=abs(y);

  • There is an easy way to approximate the normal distribution curve (bell curve) and that is simply to add 6 random number in the range -1 to +1 and divide by 6.

    Try this sketch to see what I mean. Notice the map() function to shift the random normal value to the new range.

    int[] d;
    int mean;
    
    void setup() {
      size(200, 400);
      stroke(0, 200, 0);
      d = new int[width];
      mean = width/2;
    }
    
    void draw() {
      background(250);
      // Calculate 10 values per frame
      for (int n = 0; n <10; n++) {
        int idx = int(map(normValue(), -1, +1, 0, width- 1));
        d[idx]++;
      }
      for (int i = 0; i < width; i++)
        line(i, height - d[i], i, height);
    }
    
    /*
    Returns a random number in tghe range -1 to +1 
     with an approximately normal distribution
     */
    float normValue() {
      float n = random(-1, 1) + random(-1, 1) + random(-1, 1) + random(-1, 1) + random(-1, 1) + random(-1, 1);
      return n / 6; // make range -1 to +1
    }
    
  • edited October 2016

    Thanks @quark ! The thing is that I need the values in a sequence, not random values in normal distribution..

    Basically I have some values that I need to distribute in an Array. The final array could look like { AAAAAAABBBBBBCCCCDDEDDCCCCBBBBBBAAAAAAAA } --At the ends of the array the number of each values is bigger and then decreases towards the mean. Again, I just need something like an inverted bell curve that cold be expressed in simple terms (not interested in too much detail, just something that gives bigger values at the beginning, shorter values in the middle and then bigger ones again at the end)

  • Don't you like mine? Just for loop over it, and use the value as upper bound for a 2nd nested fot loop to insert A, B etc. in the right number into an Array or so

  • Hi @Chisir! I just tested and it works! Thanks a lot+ Any idea how to attenuate it or modify the curve?

  • Well, now it's 0 to 36 in map

    Try 0 to 24 and adjust- 18 accordingly

  • edited October 2016 Answer ✓

    @grumo for two general approaches in addition to @Chrisir 's map(), here are two implementations using sin() and randomGaussian(). Each function takes the number of values you want, and the scale (0-y range of values) and returns a u-shaped sorted list.

    TwoUDistributions

    /**
     * Two U-Distributions
     * 2016-10-04
     * One with randomGaussian(), one with sin()
     * Hold down any key to refresh.
     **/
    float[] myGauss;
    float[] mySine;
    int count;
    
    void setup(){
      size(200,200);
      count = 50;
      myGauss = gaussianDist(count, height/4);
      mySine = sineDist(count, height/4);
      noLoop();
    }
    
    void draw(){
      background(192);
      for(int i = 0; i<count; i++){
        line(i*width/count, height/2, i*width/count, height/2-mySine[i]);
        line(i*width/count, height-5, i*width/count, height-myGauss[i]-5);
      }
    }
    
    void keyPressed(){
      myGauss = gaussianDist(count, height/4);
      mySine = sineDist(count, height/4);
      redraw();
    }
    
    //// see also https:// processing.org/reference/sin_.html
    float[] sineDist(int count, float scale){
      float[] vals = new float[count];
      float x = PI;
      for (int i = 0; i < count; i++) {
        vals[i] = (1 + sin(x)) * scale;
        x = x + (PI)/count;
      }
      return vals;
    }
    
    
    //// see also https:// processing.org/reference/randomGaussian_.html
    float[] gaussianDist(int count, float scale){
      float[] vals = new float[count];
      //// fill a list with random numbers
      for(int i = 0; i<vals.length; i++){
        vals[i] = randomGaussian();
      }
      //// sort to -1..0..+1 dist
      vals = sort(vals);
      //// flip to +1..0..+1 dist, scale
      float vmax = max(abs(max(vals)),abs(min(vals)));
      for(int i = 0; i<vals.length; i++){
        vals[i] = abs(vals[i] * scale/vmax);
      }
      return vals;
    }
    
  • great! I thought I could use sin(), this is fantastic. Thanks a lot!

  • edited October 2016 Answer ✓

    @grumo -- glad it was helpful. For the sake of completeness I also added examples based on the @Chrisir and @quark solutions to the demo sketch.

    FourUDistributions

    /**
     * Four U-Distributions
     * 2016-10-05 Jeremy Douglass
     * One with randomGaussian(), one with sin().
     * Hold down any key to refresh.
     * Processing 3.2.1
     **/
    float[] myGauss;
    float[] myMap;
    float[] myNorm;
    float[] mySine;
    int count;
    
    void setup(){
      size(200,200);
      textAlign(CENTER,CENTER);
      count = 50;
      myGauss = gaussianDist(count, height/5);
      myMap = mapDist(count, height/5);
      myNorm = normDist(count, height/5);
      mySine = sineDist(count, height/5);
      noLoop();
    }
    
    void draw(){
      background(192);
      for(int i = 0; i<count; i++){
        line(i*width/count, height*1/4, i*width/count, height*1/4 - myGauss[i]);
        line(i*width/count, height*2/4, i*width/count, height*2/4 - myMap[i]);
        line(i*width/count, height*3/4, i*width/count, height*3/4 - myNorm[i]);
        line(i*width/count, height,     i*width/count, height     - mySine[i]);
      }
      text("PRESS SPACE TO REFRESH", width/2,height/32);
      text("gaussian",width/2,height*1/8);
      text("map",     width/2,height*3/8);
      text("normal",  width/2,height*5/8);
      text("sine",    width/2,height*7/8);
    }
    
    void keyPressed(){
      myGauss = gaussianDist(count, height/5);
      myMap = mapDist(count, height/5);
      myNorm = normDist(count, height/5);
      mySine = sineDist(count, height/5);
      redraw();
    }
    
    //// see also https:// processing.org/reference/sin_.html
    float[] sineDist(int count, float scale){
      float[] vals = new float[count];
      float x = PI;
      for (int i = 0; i < count; i++) {
        vals[i] = (1 + sin(x)) * scale;
        x = x + (PI)/count;
      }
      return vals;
    }
    
    
    //// see also https:// processing.org/reference/randomGaussian_.html
    float[] gaussianDist(int count, float scale){
      float[] vals = new float[count];
      //// fill a list with random numbers
      for(int i = 0; i<vals.length; i++){
        vals[i] = randomGaussian();
      }
      //// sort to -1..0..+1 dist
      vals = sort(vals);
      //// flip to +1..0..+1 dist, scale
      float vmax = max(abs(max(vals)),abs(min(vals)));
      for(int i = 0; i<vals.length; i++){
        vals[i] = abs(vals[i] * scale/vmax);
      }
      return vals;
    }
    
    //// based on quark https:// forum.processing.org/two/discussion/comment/75903/#Comment_75903
    float[] normDist(int count, float scale){
      float[] vals = new float[count];
      for(int i = 0; i<vals.length; i++){
        vals[i] = (random(-1, 1) + random(-1, 1) + random(-1, 1) + random(-1, 1) + random(-1, 1) + random(-1, 1))/6;
      }
      vals = sort(vals);
      for(int i = 0; i<vals.length; i++){
        vals[i] = abs(vals[i]*scale);
      }
      return vals;
    }
    
    //// based on Chrisir https:// forum.processing.org/two/discussion/comment/75885/#Comment_75885
    float[] mapDist(int count, float scale){
      float[] vals = new float[count];
      for(int i = 0; i<vals.length; i++){
        vals[i] = abs(map(i,0,scale,-count/2,count/2));
      }
      return vals;
    }
    
  • Wow, really helpful and relevant. Renaming this discussion for proper indexing. Thanks @jeremydouglass

Sign In or Register to comment.