Shiffman's Fourier Series

I’m going through the mess of sketches I have and found an interesting one I got from the coding train. I modified it by adding a slider to increase the number of circles it uses. When the number of circles gets big, the square wave exhibits what’s called Gibbs Phenomenon. Somehow I got the bright idea to try to correct that by adding a filter to make the square wave mo square.

The problem I see is that the filter works for awhile and then it shrinks the size of the circles. Here’s the code I have. If anyone knows how to fix it, thanks for the hints.

// Fourier Series
// Daniel Shiffman
// https://thecodingtrain.com/CodingChallenges/125-fourier-series.html
// https://youtu.be/Mm2eYfj0SgA
// https://editor.p5js.org/codingtrain/sketches/SJ02W1OgV
import controlP5.*;

float time = 0;
FloatList wave;
float increment = 1; // = 0.025f;
//int n = 5;
//int n = 5;
Controls controls;

  PFont font;
boolean Flag = false;
boolean Dummy = true;
int showControls;
boolean draggingZoomSlider = false;
boolean released = true;
float zoom = 3;
float tzoom = 4;
int harmonic;

void setup() {
//fullScreen(); //  size(600, 400);
size(600, 400);


wave = new FloatList();

 controls = new Controls();

 showControls = 1; 

      
}

void draw() {
  background(0);
  

  
  
  
        if (mousePressed) {
     if( (showControls == 1) && (controls.isZoomSliderEvent(mouseX, mouseY)) && mouseX < width/2 && mouseY < height/2 ) {
         draggingZoomSlider = true;     
         zoom = controls.getZoomValue(mouseY);

 zoom += (tzoom - zoom) * 0.1;

 
 harmonic =(int) (map(zoom,0,385,0,100));
  println(harmonic);

        }  
          else if (!draggingZoomSlider) {

     }
      }
  
  
      if (showControls == 1) {
     controls.render(); 
 //    toggle(Dummy);   
    }
  controls.updateZoomSlider(zoom);

 translate(width/2-150,height/2);

  float x = 0;
  float y = 0;


//n = (int)M;
//  for (int i = 0; i < n; i++) {
     for (int i = 0; i < harmonic; i++) {
    float prevx = x;
    float prevy = y;


    float n = i * 2 + 1;
    float radius = (75 * (4 / (n * PI))); 
   // float sigma = (n+1) * PI / harmonic+1; //wave.size();
    float sigma = (n) * PI / harmonic+1; //wave.size();

    for(int j = 0; j < harmonic - 60; j++){
    sigma = map(sigma,0, 1.5,1.0,-1.0);
    sigma = (sin(sigma)/sigma); 
   
    radius = (radius * sigma);

    }

    x += (radius * cos(n * time)); 
    y += (radius * sin(n * time)); 
  
    stroke(255, 100);
    noFill();
    ellipse(prevx, prevy, radius * 2, radius * 2);
    stroke(255);
    line(prevx, prevy, x, y);

  }
  
       


//  wave.insert(0, y);
// next 4 lines replace wave.insert(0,y)
// insert not working on Android


wave.set(0,y);
wave.reverse();
wave.append(y);
wave.reverse();


  translate(200, 0);
  line(x - 200, y, 0, wave.get(0));
  beginShape();
  noFill();
// for (int i = 0; i < wave.size(); i++) {
      for (int i = 0; i < wave.size(); i++) {

    vertex(i, (wave.get(i)));
    
     
  }
  endShape(); 
  

  time += 0.035; 

  if (wave.size() > 250*2) {
    for (int n = 250*2; n < wave.size(); n++) {
      wave.remove(n);
      
    }
  }  
}  


Here’s the slider code:

/*

 Kepler Visualization - Controls
 
 GUI controls added by Lon Riesberg, Laboratory for Atmospheric and Space Physics
 lon@ieee.org
 
 April, 2012
 
 Current release consists of a vertical slider for zoom control.  The slider can be toggled
 on/off by pressing the 'c' key.
 
 Slide out controls that map to the other key bindings is currently being implemented and
 will be released soon.
 
*/

class Controls {
   
   int barWidth;   
   int barX;                          // x-coordinate of zoom control
   int minY, maxY;                    // y-coordinate range of zoom control
   float minZoomValue, maxZoomValue;  // values that map onto zoom control
   float valuePerY;                   // zoom value of each y-pixel 
   int sliderY;                       // y-coordinate of current slider position
   float sliderValue;                 // value that corresponds to y-coordinate of slider
   int sliderWidth, sliderHeight;
   int sliderX;  // x-coordinate of left-side slider edge

                       
   
   Controls () {
      
      barX = 40;
      barWidth = 15;
 
      minY = 40;
      maxY = minY + height/3 - sliderHeight/2;
           
      minZoomValue = height - height;
      maxZoomValue = height;   // 300 percent
      valuePerY = (maxZoomValue - minZoomValue) / (maxY - minY);
      
      sliderWidth = 25;
      sliderHeight = 10;
      sliderX = ((barX + (barWidth/2)) - (sliderWidth/2));      
      sliderValue = minZoomValue; 
      sliderY = minY;     
   }
   
   
   void render() {

     // strokeWeight(1.5); 
        strokeWeight(1); 
    //  stroke(105, 105, 105);  // fill(0xff33ff99);
   //   stroke(0xff33ff99);  // fill(0xff33ff99);  0xffff0000
    ///////   stroke(0xffff0000);  ///red
      
      // zoom control bar
      fill(0, 0, 0, 0);
        
      rect(barX, minY, barWidth, maxY-minY);
      
      // slider
     // fill(105, 105, 105); //0x3300FF00
    ///////////////   fill(0xffff0000); // 0xff33ff99//0x3300FF00
    fill(255,255,255);
      rect(sliderX, sliderY, sliderWidth, sliderHeight);
   }
   
   
   float getZoomValue(int y) {
      if ((y >= minY) && (y <= (maxY - sliderHeight/2))) {
         sliderY = (int) (y - (sliderHeight/2));     
         if (sliderY < minY) { 
            sliderY = minY; 
         } 
         sliderValue = (y - minY) * valuePerY + minZoomValue;
      }     
      return sliderValue;
   }
   
   
   void updateZoomSlider(float value) {
      int tempY = (int) (value / valuePerY) + minY;
      if ((tempY >= minY) && (tempY <= (maxY-sliderHeight))) {
         sliderValue = value;
         sliderY = tempY;
      }
   }
   
   
   boolean isZoomSliderEvent(int x, int y) {
      int slop = 50;  // number of pixels above or below slider that's acceptable.  provided for ease of use.
      int sliderTop = (int) (sliderY - (sliderHeight/2)) - slop;
      int sliderBottom = sliderY + sliderHeight + slop;
      return ((x >= sliderX) && (x <= (sliderX    + sliderWidth)) && (y >= sliderTop)  && (y <= sliderBottom) || draggingZoomSlider );
   } 
}```

i m not sure i see the problem when running the code, looks good to me

however, could it be you use (int) in place of round() or even keep evrything as float?


println((int) 1.8f);
println(round(1.8f));

Sounds like you tried it. I’m not sure about consistency in float or int?

If you slide the slider almost to max, the circles shrink including the main circle. Yeah its a square wave but …

It does have a cool feature though. If you slide it to max and release, it snaps back to min and you get a single sine wave.