javascript - 傅里叶级数模拟器

标签 javascript processing p5.js

我编写了一个绘图应用程序,可以将绘图转换为傅立叶级数,但它在向内螺旋时做了一件奇怪的事情。出于某种原因,该系列的所有常数的大小都相似(我认为这是不正确的,但我可能是错的)。这是我的代码:

var states = ["START", "DRAWING", "CIRCLES"];
var currentState = states[0];

var graph = [];
var constants = [];

// Half because ranging from -50 to 50
var halfNumCircles = 50;
var time = 0;
var deltaTime = 0.01;


// INITIAL SETUP
function setup() {
  createCanvas(window.innerWidth, window.innerHeight);
  angleMode(DEGREES);

  frameRate(30);
  cursor(CROSS);
}


// DRAWING LOOP
function draw() {
  background(255);

  // Axes
  stroke(100);
  line(width / 2, 0, width / 2, height);
  line(0, height / 2, width, height / 2);


  // Drawing
  stroke(0);
  if (currentState == states[1]) {
    // Add mousepos to graph
    graph.push([mouseX - width / 2, mouseY - height / 2]);

    // Draw graph
    for (let i = 0; i < graph.length - 1; i++) {
      line(graph[i][0] + width / 2, graph[i][1] + height / 2,
        graph[i + 1][0] + width / 2, graph[i + 1][1] + height / 2);
    }
  }


  // Circles
  stroke(0);
  if (currentState == states[2]) {
    // Starting at origin, draw lines to each boundary between circles
    var points = [[0, 0]];

    // For each constant, add a point
    for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
      // n is 0,1,-1,2,-2...
      var n = 0;
      if (i % 2 == 0) {
        n = -i / 2;
      } else {
        n = i / 2;
      }

      var pointX = constants[i][0] * cos(n * 2 * Math.PI * time) -
        constants[i][1] * sin(n * 2 * Math.PI * time);
      var pointY = constants[i][0] * sin(n * 2 * Math.PI * time) +
        constants[i][1] * cos(n * 2 * Math.PI * time);

      // Add new arrow to the last one
      points.push([points[points.length - 1][0] + pointX, points[points.length - 1][1] + pointY]);
    }

    // Draw lines between points
    for (let i = 0; i < points.length - 1; i++) {
      line(points[i][0] + width / 2, points[i][1] + height / 2,
        points[i + 1][0] + width / 2, points[i + 1][1] + height / 2)
    }

    // Increment time
    time = (time + deltaTime);
  }
}


// FOURIER SERIES OF FUNCTION
function getConstants(graph) {
  // Returns array with constants
  // Note that constants are complex numbers

  // Set constants to 0, to be added to in the next loop
  var constants = []
  for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
    constants.push([0, 0]);
  }

  // For each constant
  for (let c = -halfNumCircles; c <= halfNumCircles; c++) {
    var deltaT = 1.0 / graph.length;

    // Loop through the graph: sum of f(t)*e^{-c*2pi*i*t}*deltaT from 0 <= t <= 1
    for (let i = 0; i < graph.length; i++) {
      // Effective points on graph
      var a = graph[i][0];
      var b = graph[i][1];

      var t = i / graph.length;

      // Complex multiplication f(t)*e^{-c*2pi*i*t}
      var xChange = a * cos(-c * 2 * Math.PI * t) - b * sin(-c * 2 * Math.PI * t);
      var yChange = a * sin(-c * 2 * Math.PI * t) + b * cos(-c * 2 * Math.PI * t);

      constants[c + halfNumCircles][0] += xChange * deltaT;
      constants[c + halfNumCircles][1] += yChange * deltaT;
    }

  }

  // Reorder from [...-2, -1, 0, 1, 2...] to [0, 1, -1, 2, -2...]
  var orderedConstants = []
  for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
    orderedConstants.push([0, 0]);
  }

  for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
    if (i % 2 == 0) {
      orderedConstants[i] = constants[halfNumCircles - i / 2];
    } else {
      orderedConstants[i] = constants[halfNumCircles + (i + 1) / 2];
    }
  }

  return orderedConstants;
}


// STATE CHANGING EVENTS
function mousePressed() {
  // When clicked from start, start drawing
  // When clicked from circles, reset
  if (currentState == states[0]) {
    currentState = states[1];
  } else if (currentState == states[2]) {
    currentState = states[0];
    graph = [[]];
  }
}
function mouseReleased() {
  // When released, stop drawing, start circles
  if (currentState == states[1]) {
    currentState = states[2];
    time = 0;

    // Add first element of graph to the end, creating a loop
    graph.push(graph[0]);

    // Computationally intensive step
    constants = getConstants(graph);
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Circle Drawing</title>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.js" type="text/javascript"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.dom.js" type="text/javascript"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.sound.js" type="text/javascript"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/5.2.3/math.js" type="text/javascript"></script>

  <script src="circles.js" type="text/javascript"></script>

  <style media="screen">
    body {
      padding: 0;
      margin: 0;
    }
  </style>

</head>

<body>
</body>

</html>

我似乎找不到错误。我认为它可能与输入的规模有关,但这没有意义,因为在这种情况下单位是任意的。如果您知道我做错了什么,请告诉我。感谢您的帮助!

最佳答案

deltaTime的单位是毫秒。样本周期太大。

将时间除以 1000.0 得到以秒为单位的时间:

var times_s = time/1000.0;
var pointX = constants[i][0] * cos(n * 2 * Math.PI * times_s) -
    constants[i][1] * sin(n * 2 * Math.PI * times_s);
var pointY = constants[i][0] * sin(n * 2 * Math.PI * times_s) +
    constants[i][1] * cos(n * 2 * Math.PI * times_s);

var states = ["START", "DRAWING", "CIRCLES"];
var currentState = states[0];

var graph = [];
var constants = [];

// Half because ranging from -50 to 50
var halfNumCircles = 50;
var time = 0;
var deltaTime = 0.01;


// INITIAL SETUP
function setup() {
  createCanvas(window.innerWidth, window.innerHeight);
  angleMode(DEGREES);

  frameRate(30);
  cursor(CROSS);
}


// DRAWING LOOP
function draw() {
  background(255);

  // Axes
  stroke(100);
  line(width / 2, 0, width / 2, height);
  line(0, height / 2, width, height / 2);


  // Drawing
  stroke(0);
  if (currentState == states[1]) {
    // Add mousepos to graph
    graph.push([mouseX - width / 2, mouseY - height / 2]);

    // Draw graph
    for (let i = 0; i < graph.length - 1; i++) {
      line(graph[i][0] + width / 2, graph[i][1] + height / 2,
        graph[i + 1][0] + width / 2, graph[i + 1][1] + height / 2);
    }
  }


  // Circles
  stroke(0);
  if (currentState == states[2]) {
    // Starting at origin, draw lines to each boundary between circles
    var points = [[0, 0]];

    // For each constant, add a point
    for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
      // n is 0,1,-1,2,-2...
      var n = 0;
      if (i % 2 == 0) {
        n = -i / 2;
      } else {
        n = i / 2;
      }

      var times_s = time/1000.0;
      var pointX = constants[i][0] * cos(n * 2 * Math.PI * times_s) -
        constants[i][1] * sin(n * 2 * Math.PI * times_s);
      var pointY = constants[i][0] * sin(n * 2 * Math.PI * times_s) +
        constants[i][1] * cos(n * 2 * Math.PI * times_s);

      // Add new arrow to the last one
      points.push([points[points.length - 1][0] + pointX, points[points.length - 1][1] + pointY]);
    }

    // Draw lines between points
    for (let i = 0; i < points.length - 1; i++) {
      line(points[i][0] + width / 2, points[i][1] + height / 2,
        points[i + 1][0] + width / 2, points[i + 1][1] + height / 2)
    }

    // Increment time
    time = (time + deltaTime);
  }
}


// FOURIER SERIES OF FUNCTION
function getConstants(graph) {
  // Returns array with constants
  // Note that constants are complex numbers

  // Set constants to 0, to be added to in the next loop
  var constants = []
  for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
    constants.push([0, 0]);
  }

  // For each constant
  for (let c = -halfNumCircles; c <= halfNumCircles; c++) {
    var deltaT = 1.0 / graph.length;

    // Loop through the graph: sum of f(t)*e^{-c*2pi*i*t}*deltaT from 0 <= t <= 1
    for (let i = 0; i < graph.length; i++) {
      // Effective points on graph
      var a = graph[i][0];
      var b = graph[i][1];

      var t = i / graph.length;

      // Complex multiplication f(t)*e^{-c*2pi*i*t}
      var xChange = a * cos(-c * 2 * Math.PI * t) - b * sin(-c * 2 * Math.PI * t);
      var yChange = a * sin(-c * 2 * Math.PI * t) + b * cos(-c * 2 * Math.PI * t);

      constants[c + halfNumCircles][0] += xChange * deltaT;
      constants[c + halfNumCircles][1] += yChange * deltaT;
    }

  }

  // Reorder from [...-2, -1, 0, 1, 2...] to [0, 1, -1, 2, -2...]
  var orderedConstants = []
  for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
    orderedConstants.push([0, 0]);
  }

  for (let i = 0; i < 2 * halfNumCircles + 1; i++) {
    if (i % 2 == 0) {
      orderedConstants[i] = constants[halfNumCircles - i / 2];
    } else {
      orderedConstants[i] = constants[halfNumCircles + (i + 1) / 2];
    }
  }

  return orderedConstants;
}


// STATE CHANGING EVENTS
function mousePressed() {
  // When clicked from start, start drawing
  // When clicked from circles, reset
  if (currentState == states[0]) {
    currentState = states[1];
  } else if (currentState == states[2]) {
    currentState = states[0];
    graph = [[]];
  }
}
function mouseReleased() {
  // When released, stop drawing, start circles
  if (currentState == states[1]) {
    currentState = states[2];
    time = 0;

    // Add first element of graph to the end, creating a loop
    graph.push(graph[0]);

    // Computationally intensive step
    constants = getConstants(graph);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>

关于javascript - 傅里叶级数模拟器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58705778/

相关文章:

javascript - Jquery Slidetoggle,如何只显示一个元素?

javascript - 更改 Youtube API 的发送 URL

Javascript 字符串数组

java - 在处理层映射 GPS 点

java - 通过电子邮件更新带有图片的状态。 (Java邮件)

java - 有没有办法使for循环中的循环增加随机化?

javascript - 我怎样才能每次 vol > 6 时以 1 计数

javascript - 引用错误 : soundFormats is not defined

javascript - 鼠标拖动旋转

javascript - Redux 中的订阅 Redux 中订阅的奇怪行为