主頁 > 企業開發 > 如何可視化傅立葉級數/傅立葉系數?

如何可視化傅立葉級數/傅立葉系數?

2022-02-17 05:43:38 企業開發

我目前在可視化傅立葉級數時遇到困難。為了找出錯誤,我嘗試了大約 3 次相同的事情,但徒勞無功。

現在我什至不知道我的代碼或對傅里葉級數的理解有什么問題。

我正在嘗試制作的內容類似于以下 Youtube 視頻中所示的內容:如何可視化傅立葉級數/傅立葉系數?

(2) 引數

如何可視化傅立葉級數/傅立葉系數?

所以現在我想以引數化的方式繪制更復雜的東西請讓我展示我走過的程序。

① 從 svg 路徑,獲取坐標。例如,

// svg path
const d = 'M 0 0 L 20 30 L 10 20 ... ... ... Z';
↓ convert with some processing...
const cx = [0, 20, 10, ...]; // function Fx(t)
const cy = [0, 30, 20, ...]; // function Fy(t)

② Get Fourier coefficients from Fx(t), Fy(t), respectively. After that, I can get approximated coordinates by calculating Fourier series respectively by using the coefficients I got. For example,

Let's say I have a0_x, an_x, bn_x, a0_y, an_y, bn_y.
Then, Fx(t) = a0_x   an_x[1] * cos(1wt)   bn_x[1] * cos(1wt)
                     an_x[2] * cos(2wt)   bn_x[2] * cos(2wt)   ...;

      Fy(t) = a0_y   an_y[1] * cos(1wt)   bn_y[1] * cos(1wt)
                     an_y[2] * cos(2wt)   bn_y[2] * cos(2wt)   ...;

Therefore a set of points (Fx(t), Fy(t)) is an approximated path!

This is all! Only thing left is just drawing!

Meanwhile, I processed the data in the following way:

const d = [svg path data];
const split = d.split(/[, ]/);
const points = get_points(split);
const normalized = normalize(points);
const populated = populate(normalized, 8);
const cx = populated.x; // Fx(t)
const cy = populated.y; // Fy(t)

/**
 * This function does the below job.
 * populate([0,3,6], 2) => output 0 12 3 45 6
 * populate([0,4,8], 3) => output 0 123 4 567 8
 */
function populate(data, n) {
  if (data.x.length <= 1) throw new Error('NotEnoughData');
  if (n < 1) throw new Error('InvalidNValue');

  const arr_x = new Array(data.x.length   (data.x.length - 1) * n);
  const arr_y = new Array(data.y.length   (data.y.length - 1) * n);

  for (let i = 0; i < data.x.length; i  ) {
    arr_x[i * (n   1)] = data.x[i];
    arr_y[i * (n   1)] = data.y[i];
  }

  for (let i = 0; i <= arr_x.length - n - 1 - 1; i  = (n   1)) {
    const x_interpolation = (arr_x[i   n   1] - arr_x[i]) / (n   1);
    const y_interpolation = (arr_y[i   n   1] - arr_y[i]) / (n   1);

    for (let j = 1; j <= n; j  ) {
      arr_x[i   j] = arr_x[i]   x_interpolation * j;
      arr_y[i   j] = arr_y[i]   y_interpolation * j;
    }
  }

  return { x: arr_x, y: arr_y };
}

// This function makes all values are in range of [-1, 1].
// I just did it... because I don't want to deal with big numbers (and not want numbers having different magnitude depending on data).
function normalize(obj) {
  const _x = [];
  const _y = [];

  const biggest_x = Math.max(...obj.x);
  const smallest_x = Math.min(...obj.x);
  const final_x = Math.max(Math.abs(biggest_x), Math.abs(smallest_x));

  const biggest_y = Math.max(...obj.y);
  const smallest_y = Math.min(...obj.y);
  const final_y = Math.max(Math.abs(biggest_y), Math.abs(smallest_y));

  for (let i = 0; i < obj.x.length; i  ) {
    _x[i] = obj.x[i] / final_x;
    _y[i] = obj.y[i] / final_y;
  }

  return { x: _x, y: _y };
}

// returns Fx(t) and Fy(t) from svg path data
function get_points(arr) {
  const x = [];
  const y = [];
  let i = 0;

  while (i < arr.length) {
    const path_command = arr[i];

    if (path_command === "M") {
      x.push(Number(arr[i   1]));
      y.push(Number(arr[i   2]));
      i  = 3;
    } else if (path_command === 'm') {
      if (i === 0) {
        x.push(Number(arr[i   1]));
        y.push(Number(arr[i   2]));
        i  = 3;
      } else {
        x.push(x.at(-1)   Number(arr[i   1]));
        y.push(y.at(-1)   Number(arr[i   2]));
        i  = 3;
      }
    } else if (path_command === 'L') {
      x.push(Number(arr[i   1]));
      y.push(Number(arr[i   2]));
      i  = 3;
    } else if (path_command === 'l') {
      x.push(x.at(-1)   Number(arr[i   1]));
      y.push(y.at(-1)   Number(arr[i   2]));
      i  = 3;
    } else if (path_command === 'H') {
      x.push(Number(arr[i   1]));
      y.push(y.at(-1));
      i  = 2;
    } else if (path_command === 'h') {
      x.push(x.at(-1)   Number(arr[i   1]));
      y.push(y.at(-1));
      i  = 2;
    } else if (path_command === 'V') {
      x.push(x.at(-1));
      y.push(Number(arr[i   1]));
      i  = 2;
    } else if (path_command === 'v') {
      x.push(x.at(-1));
      y.push(y.at(-1)   Number(arr[i   1]));
      i  = 2;
    } else if (path_command === 'Z' || path_command === 'z') {
      i  ;
      console.log('reached to z/Z, getting points done');
    } else if (path_command === 'C' || path_command === 'c' || path_command === 'S' || path_command === 's' || path_command === 'Q' || path_command === 'q' || path_command === 'T' || path_command === 't' || path_command === 'A' || path_command === 'a') {
      throw new Error('unsupported path command, getting points aborted');
    } else {
      x.push(x.at(-1)   Number(arr[i]));
      y.push(y.at(-1)   Number(arr[i   1]));
      i  = 2;
    }
  }

  return { x, y };
}

Meanwhile, in order to calculate Fourier coefficients, I used numerical integration. This is the code.

/**
 * This function calculates Riemann sum (area approximation using rectangles).
 * @param {Number} div division number (= number of rectangles to be used)
 * @param {Array | Function} subject subject of integration
 * @param {Number} start where to start integration
 * @param {Number} end where to end integration
 * @param {Number} nth this parameter will be passed to 'subject'
 * @param {Function} paramFn this parameter will be passed to 'subject'
 * @returns {Number} numerical-integrated value
 */
function numerical_integration(div, subject, start, end, nth = null, paramFn = null) {
  if (div < 1) throw new Error(`invalid div; it can't be 0 or 0.x`);

  let sum = 0;
  const STEP = 1 / div;
  const isSubjectArray = Array.isArray(subject);
  
  if (isSubjectArray) {
    for (let t = start; t < end; t  ) {
      for (let u = 0; u < div; u  ) {
        sum  = subject[t   1] * STEP;
      }
    }
  } else {
    for (let t = start; t < end; t  ) {
      for (let u = 0; u < div; u  ) {
        const period = end - start;
        const isParamFnArray = Array.isArray(paramFn);

        if (isParamFnArray) sum  = subject((t   1), period, nth, paramFn) * STEP;
        else sum  = subject(((t   STEP)   STEP * u), period, nth, paramFn) * STEP;
      }
    }
  }

  return sum;

// console.log(numerical_integration(10, (x) => x ** 3, 0, 2));
}

The approximation is near. For (x) => x, division 10, from 0 to 2, the approximation is 2.1 while actual answer is 2. For (x) => x ** 2, division 10, from 0 to 2, the approximation is 2.87, while actual answer is 2.67. For (x) => x ** 3, division 10, from 0 to 2, the approximation is 4.41, while actual answer is 4.

And I found a0, an, bn by the following: (※ You can find Fourier coefficients formulas in 如何可視化傅立葉級數/傅立葉系數?

The below is the canvas drawing code:

const $cvs = document.createElement('canvas');
const cctx = $cvs.getContext('2d');

$cvs.setAttribute('width', 1000);
$cvs.setAttribute('height', 800);
$cvs.setAttribute('style', 'border: 1px solid black;');
document.body.appendChild($cvs);

window.requestAnimationFrame(draw_tick);

// offset
const xoo = { x: 200, y: 600 }; // x oscillator offset
const yoo = { x: 600, y: 200 }; // y ~

// path
const path = [];

// drawing function
let deg = 0;

function draw_tick() {
  const rAF = window.requestAnimationFrame(draw_tick);

  // initialize
  cctx.clearRect(0, 0, 1000, 800);
  
  // y oscillator
  const py = { x: 0, y: 0 };

  // a0
    // a0 circle
  cctx.beginPath();
  cctx.strokeStyle = 'black';
  cctx.arc(yoo.x   py.x, yoo.y   py.y, Math.abs(ya0), 0, 2 * Math.PI);
  cctx.stroke();

    // a0 line
  cctx.beginPath();
  cctx.strokeStyle = 'black';
  cctx.moveTo(yoo.x   py.x, yoo.y   py.y);

  py.x  = ya0 * Math.cos(0 * deg * Math.PI / 180);
  py.y  = ya0 * Math.sin(0 * deg * Math.PI / 180);
  cctx.lineTo(yoo.x   py.x, yoo.y   py.y);
  cctx.stroke();
  
  // an
  for (let i = 0; i < yan.length; i  ) {
    const radius = yan[i];

    // an circles
    cctx.beginPath();
    cctx.strokeStyle = 'black';
    cctx.arc(yoo.x   py.x, yoo.y   py.y, Math.abs(radius), 0, 2 * Math.PI);
    cctx.stroke();

    // an lines
    cctx.beginPath();
    cctx.strokeStyle = 'black';
    cctx.moveTo(yoo.x   py.x, yoo.y   py.y);

    py.x  = radius * Math.cos((i 1) * deg * Math.PI / 180);
    py.y  = radius * Math.sin((i 1) * deg * Math.PI / 180);
    cctx.lineTo(yoo.x   py.x, yoo.y   py.y);
    cctx.stroke();
  }
  
  // bn
  for (let i = 0; i < ybn.length; i  ) {
    const radius = ybn[i];

    // bn circles
    cctx.beginPath();
    cctx.strokeStyle = 'black';
    cctx.arc(yoo.x   py.x, yoo.y   py.y, Math.abs(radius), 0, 2 * Math.PI);
    cctx.stroke();

    // bn lines
    cctx.beginPath();
    cctx.strokeStyle = 'black';
    cctx.moveTo(yoo.x   py.x, yoo.y   py.y);

    py.x  = radius * Math.cos((i 1) * deg * Math.PI / 180);
    py.y  = radius * Math.sin((i 1) * deg * Math.PI / 180);
    cctx.lineTo(yoo.x   py.x, yoo.y   py.y);
    cctx.stroke();
  }

  // x oscillator
  const px = { x: 0, y: 0 };

  // a0
    // a0 circle
  cctx.beginPath();
  cctx.strokeStyle = 'black';
  cctx.arc(yoo.x   py.x, yoo.y   py.y, Math.abs(xa0), 0, 2 * Math.PI);
  cctx.stroke();

    // a0 line
  cctx.beginPath();
  cctx.strokeStyle = 'black';
  cctx.moveTo(yoo.x   py.x, yoo.y   py.y);

  py.x  = xa0 * Math.cos(0 * deg * Math.PI / 180);
  py.y  = xa0 * Math.sin(0 * deg * Math.PI / 180);
  cctx.lineTo(yoo.x   py.x, yoo.y   py.y);
  cctx.stroke();
  
  // an
  for (let i = 0; i < xan.length; i  ) {
    const radius = xan[i];

    // an circles
    cctx.beginPath();
    cctx.strokeStyle = 'black';
    cctx.arc(xoo.x   px.x, xoo.y   px.y, Math.abs(radius), 0, 2 * Math.PI);
    cctx.stroke();

    // an lines
    cctx.beginPath();
    cctx.strokeStyle = 'black';
    cctx.moveTo(xoo.x   px.x, xoo.y   px.y);

    px.x  = radius * Math.cos((i 1) * deg * Math.PI / 180);
    px.y  = radius * Math.sin((i 1) * deg * Math.PI / 180);
    cctx.lineTo(xoo.x   px.x, xoo.y   px.y);
    cctx.stroke();
  }

  // bn
  for (let i = 0; i < xbn.length; i  ) {
    const radius = xbn[i];

    // bn circles
    cctx.beginPath();
    cctx.strokeStyle = 'black';
    cctx.arc(xoo.x   px.x, xoo.y   px.y, Math.abs(radius), 0, 2 * Math.PI);
    cctx.stroke();

    // bn lines
    cctx.beginPath();
    cctx.strokeStyle = 'black';
    cctx.moveTo(xoo.x   px.x, xoo.y   px.y);

    px.x  = radius * Math.cos((i 1) * deg * Math.PI / 180);
    px.y  = radius * Math.sin((i 1) * deg * Math.PI / 180);
    cctx.lineTo(xoo.x   px.x, xoo.y   px.y);
    cctx.stroke();
  }

  // y oscillator line
  cctx.strokeStyle = 'black';
  cctx.beginPath();

  cctx.moveTo(yoo.x   py.x, yoo.y   py.y);
  cctx.lineTo(xoo.x   px.x, yoo.y   py.y);

  cctx.stroke();

  // x oscillator line
  cctx.strokeStyle = 'black';
  cctx.beginPath();

  cctx.moveTo(xoo.x   px.x, xoo.y   px.y);
  cctx.lineTo(xoo.x   px.x, yoo.y   py.y);

  cctx.stroke();

  // path
  path.push({ x: px.x, y: py.y });

  cctx.beginPath();
  cctx.strokeStyle = 'black';
  
  cctx.moveTo(200   path[0].x, 200   path[0].y);

  for (let i = 0; i < path.length; i  ) {
    cctx.lineTo(200   path[i].x, 200   path[i].y);
  }

  cctx.stroke();

  // degree update
  if (deg === 359) {
    window.cancelAnimationFrame(rAF);
  } else {
    deg  ;
  }
}

So! I decided to be logical. First, I checked whether the converted path data is correct by drawing it at canvas. The below is the canvas code and the data.

let count = 0;

function draw_tick2() {
  const rAF = window.requestAnimationFrame(draw_tick2);

  const s = 100; // scale up

  // initialize
  cctx.clearRect(0, 0, 1000, 800);

  cctx.beginPath();
  
  // 200 has no meaning I just added it to move the path.
  for (let i = 0; i < count; i  ) {
    if (i === 0) cctx.moveTo(200   s * cx[i], 200   s * cy[i]);
    else cctx.lineTo(200   s * cx[i], 200   s * cy[i]);
  }

  cctx.stroke();

  if (count < cx.length - 1) {
    count  ;
  } else {
    window.cancelAnimationFrame(rAF);
  }
}
const paimon = 'm 0,0 -2.38235,-2.87867 -1.58823,-1.29045 -1.9853,-0.893384 -3.17647,-0.39706 1.58824,-1.98529 1.09191,-2.08456 v -2.38235 l -0.79412,-2.87868 1.88603,2.18383 1.6875,1.88602 1.78677,0.99265 1.78676,0.39706 1.78676,-0.19853 -1.6875,1.58824 -0.69485,1.68749 -0.0993,2.084564 0.39706,2.18383 9.62867,3.87132 2.77941,1.9853 4.66544,-1.09192 3.07721,-1.88603 1.9853,-2.58088 -3.97059,0.49633 -3.375,-0.79412 -2.87868,-2.58088 -2.08456,-3.077214 2.38235,1.48897 2.08456,0.19853 3.57353,-0.89338 2.58089,-2.48162 -3.07721,0.39706 -3.87132,-1.88603 -2.97794,-2.08456 -2.48162,-2.87868 -3.87133,-4.06985 -4.06985,-2.68015 -5.95588,-2.58088 -5.85662,-0.79412 -5.45956,0.99265 0.59559,1.6875 -0.99265,1.09191 -0.79412,3.47427 -1.29044,-2.97794 -0.89338,-1.19118 0.79412,-1.48897 1.6875,-0.79412 0.39706,-3.772057 1.48897,1.290441 1.78676,0.09926 -2.08456,-1.985293 1.78677,-0.893382 4.36765,-0.19853 4.86397,0.992648 1.19117,1.091912 -2.38235,1.985301 3.17647,-0.49633 2.87868,-2.680149 -3.57353,-2.580881 -5.45956,-1.488972 h -4.46691 l -3.6728,-3.176471 -0.79412,1.389706 -0.79411,-1.488969 0.69485,-0.595588 -1.58824,-3.871325 -0.39706,3.672795 -0.69485,0.297794 0.89338,1.091911 v 1.091912 h -1.19113 l -0.59559,-0.992648 -1.98529,2.878677 -4.06986,1.588236 -4.26838,1.985293 3.27574,3.871329 2.87867,1.88603 2.58088,0.29779 -2.58088,-1.58823 -0.89338,-2.084566 4.86397,-0.992645 -1.19118,2.382351 h 1.58824 l 1.48897,-1.88603 0.29779,2.77942 -2.38235,2.38235 -3.57353,2.87868 -3.97059,4.86397 -2.08456,3.67279 -2.58088,2.58088 -2.68015,1.09192 -3.17647,0.0993 -1.3897,-0.69485 1.09191,3.17647 2.18382,3.573534 3.375,2.38235 -1.78676,5.85662 -1.38971,6.05514 0.39706,4.36765 1.38971,4.66544 3.87132,4.46691 -0.79412,-3.57352 -0.49632,-4.06986 v -2.48162 l 1.78676,5.85662 3.07721,3.17647 3.07721,1.29044 3.37499,0.79412 2.28309,-0.89338 0.69486,-1.48897 -1.19118,0.49632 -2.48162,-1.98529 -2.28309,-2.87868 2.28309,2.48162 h 0.99265 l 0.69485,-0.49632 0.2978,-1.19118 0.0993,-0.79412 -0.89339,0.59559 -1.58823,-0.99265 -1.29044,-1.3897 -1.19118,-2.38236 -0.89338,-4.86397 -0.0993,-4.56617 0.29779,-4.96324 0.39706,0.89338 1.19118,-0.44669 0.0496,-0.89338 1.09191,0.69485 1.48897,0.2978 1.53861,0.89338 0.99264,0.64522 h -0.79411 l 0.49632,2.43199 -0.44669,1.58823 -1.78676,0.39706 -1.24081,-1.24081 -0.24817,-1.43934 0.84375,-0.94301 1.19118,-0.49633 1.14154,0.94302 0.24816,1.14154 -0.0993,1.48897 -1.83639,0.64523 -1.58824,-1.53861 -0.44669,-1.48897 -0.24816,-2.18382 -1.43934,0.99264 0.0496,-0.99264 -0.44669,1.78676 0.69485,3.12684 1.09192,4.26838 1.78676,1.78677 6.89889,3.02757 -2.53124,0.99265 -3.17647,1.3897 -0.79412,0.39706 0.59559,0.39706 1.34007,-0.69485 0.0496,1.19117 1.98529,-0.39705 2.68015,-0.44669 -0.2978,-1.93567 0.79412,1.58824 2.82905,-0.44669 4.06985,-1.34008 1.04229,-0.59559 -0.2978,-1.78676 -0.34743,-1.73713 -4.9136,2.48162 -2.58088,0.94301 -3.17648,-4.81434 1.53861,0.49633 1.3897,0.0496 1.43935,-0.24816 -1.34008,0.24816 h -1.58824 l -1.41452,-0.54596 3.12684,4.78953 2.63052,-0.89339 4.86397,-2.4568 2.65533,-2.08456 0.39706,-5.90625 -0.84375,1.5386 -1.14155,0.54596 -1.5386,0.19853 -1.29044,-0.89338 -0.59559,-1.09191 -0.24816,-1.73714 0.24816,-1.3897 -2.08456,0.54595 -0.29779,-0.34742 0.34743,-0.49633 0.64522,-0.39706 1.5386,-0.39705 2.18382,-0.19853 1.24081,0.0993 1.14154,0.54596 0.4467,1.43934 -0.19853,1.63786 -0.59559,1.29044 -1.24081,0.89339 -1.43934,-0.39706 -0.99264,-1.09191 -0.0496,-1.19118 0.79412,-0.89338 0.89338,-0.44669 1.19118,-0.0496 0.64522,1.04228 0.34742,0.79412 -0.14889,1.14155 0.99265,-0.4467 0.29779,-1.34007 -0.19853,-4.06985 -1.93566,-0.44669 -2.53125,-1.6875 -2.23346,-1.88603 -2.23345,-4.069864 -0.44669,3.920964 0.64522,4.21875 1.5386,3.92096 0.74448,0.44669 h -1.73713 l -2.18383,-0.54596 -3.12684,-2.08456 -1.58823,-2.28309 -1.14154,-2.08456 -1.29044,-3.871324 -1.38971,2.481624 -1.48897,2.63051 -0.94302,1.9853 3.8217,-6.948534 1.29044,3.672794 2.33272,3.92096 2.9283,2.13419 0.49633,0.44669 2.28309,0.49632 h 1.63787 l -0.69485,-0.69485 -0.84375,-1.93566 -1.34008,-5.80698 0.44669,-3.970594 2.33273,4.069854 4.56617,3.47426 2.08456,0.59559 0.19853,2.82905 -0.0496,3.97058 -0.0993,6.00552 -0.54595,3.02757 -1.58824,2.77941 -1.5386,0.89339 -1.19118,0.24816 -1.48897,-0.69485 -0.69485,-0.1489 0.69485,1.24081 1.43934,1.6875 2.68015,1.19117 3.17647,0.2978 3.77206,-2.23346 1.3897,-2.77941 0.89339,-3.82169 0.0496,-3.375 0.14889,6.25368 -1.14154,5.11213 -2.08456,3.27573 -2.08456,1.6875 -1.88603,0.59559 -2.28308,-0.79412 1.78676,1.6875 4.9136,1.88603 2.43199,0.2978 2.68015,-0.39706 2.72977,-1.09191 3.62317,-3.27574 0.89338,-3.97059 0.49632,-3.57353 -0.0993,-2.87867 -0.39706,-3.17647 -0.49632,-3.07721 1.98529,3.47427 1.19117,2.18382 0.39706,1.29044 0.39706,-2.28309 -0.39706,-3.0772 -1.29044,-3.77206 -1.29044,-2.87868 -1.6875,-3.27573 -10.125,-4.16912 z';

如何可視化傅立葉級數/傅立葉系數?

This is ★Paimon chan★. Thus it is proved that there are no flaws at the data, since all the data is plotted correctly.

Next, I plotted the approximated (Fx(t), Fy(t)) points so that I can check whether there is a problem. And It turned out that there was a problem. But I don't understand what is the problem. At the same time this path is interesting; The beginning part of the path seems like the hairpin.

如何可視化傅立葉級數/傅立葉系數?

This is the drawing code:

function approxFn(t) {
  let x = xa0;
  let y = ya0;

  for (let i = 0; i < xan.length; i  ) {
    x  = xan[i] * Math.cos(2 * Math.PI * i * t / cx.length);
    x  = xbn[i] * Math.sin(2 * Math.PI * i * t / cx.length);
    y  = yan[i] * Math.cos(2 * Math.PI * i * t / cx.length);
    y  = ybn[i] * Math.sin(2 * Math.PI * i * t / cx.length);
  }

  return { x, y };
}

function draw_tick3() {
  const rAF = window.requestAnimationFrame(draw_tick3);

  const s = 5;

  // initialize
  cctx.clearRect(0, 0, 1000, 800);

  cctx.beginPath();

  for (let t = 0; t < count; t  ) {
    if (count === 0) cctx.moveTo(200   s * approxFn(t).x, 200   s * approxFn(t).y);
    else cctx.lineTo(200   s * approxFn(t).x, 200   s * approxFn(t).y);
  }

  cctx.stroke();

  if (count < cx.length - 1) {
    count  ;
  } else {
    window.cancelAnimationFrame(rAF);
  }
}

The above is all the code in my js file. In where I made a mistake? It's a mystery! I know this question is exceptionally seriously long question. But please help me! I want to realize Paimon chan! ?w?

※ (This section is irrelevant with the question) Meanwhile I made a success to draw the path in a complex number plane. If you're interested, please see my work... I would like to add circle things to this but I have no idea what is 'radius' in this case.

如何可視化傅立葉級數/傅立葉系數?

如何可視化傅立葉級數/傅立葉系數?

如何可視化傅立葉級數/傅立葉系數?

// You can see that I used real part for x and imaginary part for y.

for (let i = 0; i <= count; i  ) {
    if (i === 0) {
      cctx.moveTo(coords[i].real * scaler   paimonPosition, coords[i].imag * scaler   paimonPosition);
    } else {
      cctx.lineTo(coords[i].real * scaler   paimonPosition, coords[i].imag * scaler   paimonPosition);
    }
  }

And this is the result. But what makes me confused is a case of cn = -5000 ~ 5000. As far as I understand, more cn, more accurate as original wave. But why it crashes when cn is so big?

Anyways, thank you very much for reading this long question!

uj5u.com熱心網友回復:

如何可視化傅立葉級數/傅立葉系數?

你好我自己!

首先,代碼中的錯誤...

  1. 您沒有考慮在繪圖命令之后出現值序列的情況。例如,您的get_points函式無法處理類似h 0 1 2.

  2. 當前get_points函式無法處理第二個m繪圖命令。如果您有多個路徑,則需要手動連接字串。

  3. 需要手動設定mxy為m 0 0,否則看不到canvas繪圖。(也許值太小而無法繪制)

其次,簡而言之,如果您在 xy 平面上近似 f(t),則無法繪制具有固定大小的旋轉矢量的形狀。這是因為你近似的不是形狀本身,而是形狀的坐標。

第三,當您嘗試繪制近似資料時,您得到奇怪形狀的原因在于您的approxFn()功能。

x  = xan[i] * Math.cos(2 * Math.PI * i * t / cx.length);
x  = xbn[i] * Math.sin(2 * Math.PI * i * t / cx.length);
y  = yan[i] * Math.cos(2 * Math.PI * i * t / cx.length);
y  = ybn[i] * Math.sin(2 * Math.PI * i * t / cx.length);

不是 t,(t 1) 是正確的。您的近似資料沒有問題。

第四,如果要旋轉矢量,則需要采用復平面方法。在這種情況下,圓的半徑是實部矢量和虛部矢量的和矢量的大小(勾股定理)。

第五,在Cn公式中,你錯過了1 / T。

Sixth, The reason it crashed is... I don't know the exact reason but I think numerical integration and/or finding Cn is wrong. The new code I wrote don't crash at high Cn.

p.s. I wrote some writings about Fourier series. Please see if you are interested: https://logic-finder.github.io/FourierSeriesExploration/opening/opening-en.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/424819.html

標籤:javascript math html5-canvas fft

上一篇:帶有Numpy的Sigma表示法

下一篇:如何創建一個指向多個度數的AB單位向量并計算它們之間的角度?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more