fft.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.createFft = void 0;
  7. var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
  8. var _array = require("../../utils/array.js");
  9. var _factory = require("../../utils/factory.js");
  10. var name = 'fft';
  11. var dependencies = ['typed', 'matrix', 'addScalar', 'multiplyScalar', 'divideScalar', 'exp', 'tau', 'i', 'dotDivide', 'conj', 'pow', 'ceil', 'log2'];
  12. var createFft = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
  13. var typed = _ref.typed,
  14. matrix = _ref.matrix,
  15. addScalar = _ref.addScalar,
  16. multiplyScalar = _ref.multiplyScalar,
  17. divideScalar = _ref.divideScalar,
  18. exp = _ref.exp,
  19. tau = _ref.tau,
  20. I = _ref.i,
  21. dotDivide = _ref.dotDivide,
  22. conj = _ref.conj,
  23. pow = _ref.pow,
  24. ceil = _ref.ceil,
  25. log2 = _ref.log2;
  26. /**
  27. * Calculate N-dimensional fourier transform
  28. *
  29. * Syntax:
  30. *
  31. * math.fft(arr)
  32. *
  33. * Examples:
  34. *
  35. * math.fft([[1, 0], [1, 0]]) // returns [[{re:2, im:0}, {re:2, im:0}], [{re:0, im:0}, {re:0, im:0}]]
  36. *
  37. *
  38. * See Also:
  39. *
  40. * ifft
  41. *
  42. * @param {Array | Matrix} arr An array or matrix
  43. * @return {Array | Matrix} N-dimensional fourier transformation of the array
  44. */
  45. return typed(name, {
  46. Array: _ndFft,
  47. Matrix: function Matrix(matrix) {
  48. return matrix.create(_ndFft(matrix.toArray()));
  49. }
  50. });
  51. /**
  52. * Perform an N-dimensional Fourier transform
  53. *
  54. * @param {Array} arr The array
  55. * @return {Array} resulting array
  56. */
  57. function _ndFft(arr) {
  58. var size = (0, _array.arraySize)(arr);
  59. if (size.length === 1) return _fft(arr, size[0]);
  60. // ndFft along dimension 1,...,N-1 then 1dFft along dimension 0
  61. return _1dFft(arr.map(function (slice) {
  62. return _ndFft(slice, size.slice(1));
  63. }), 0);
  64. }
  65. /**
  66. * Perform an 1-dimensional Fourier transform
  67. *
  68. * @param {Array} arr The array
  69. * @param {number} dim dimension of the array to perform on
  70. * @return {Array} resulting array
  71. */
  72. function _1dFft(arr, dim) {
  73. var size = (0, _array.arraySize)(arr);
  74. if (dim !== 0) return new Array(size[0]).fill(0).map(function (_, i) {
  75. return _1dFft(arr[i], dim - 1);
  76. });
  77. if (size.length === 1) return _fft(arr);
  78. function _transpose(arr) {
  79. // Swap first 2 dimensions
  80. var size = (0, _array.arraySize)(arr);
  81. return new Array(size[1]).fill(0).map(function (_, j) {
  82. return new Array(size[0]).fill(0).map(function (_, i) {
  83. return arr[i][j];
  84. });
  85. });
  86. }
  87. return _transpose(_1dFft(_transpose(arr), 1));
  88. }
  89. /**
  90. * Perform an 1-dimensional non-power-of-2 Fourier transform using Chirp-Z Transform
  91. *
  92. * @param {Array} arr The array
  93. * @return {Array} resulting array
  94. */
  95. function _czt(arr) {
  96. var n = arr.length;
  97. var w = exp(divideScalar(multiplyScalar(-1, multiplyScalar(I, tau)), n));
  98. var chirp = [];
  99. for (var i = 1 - n; i < n; i++) {
  100. chirp.push(pow(w, divideScalar(pow(i, 2), 2)));
  101. }
  102. var N2 = pow(2, ceil(log2(n + n - 1)));
  103. var xp = [].concat((0, _toConsumableArray2["default"])(new Array(n).fill(0).map(function (_, i) {
  104. return multiplyScalar(arr[i], chirp[n - 1 + i]);
  105. })), (0, _toConsumableArray2["default"])(new Array(N2 - n).fill(0)));
  106. var ichirp = [].concat((0, _toConsumableArray2["default"])(new Array(n + n - 1).fill(0).map(function (_, i) {
  107. return divideScalar(1, chirp[i]);
  108. })), (0, _toConsumableArray2["default"])(new Array(N2 - (n + n - 1)).fill(0)));
  109. var fftXp = _fft(xp);
  110. var fftIchirp = _fft(ichirp);
  111. var fftProduct = new Array(N2).fill(0).map(function (_, i) {
  112. return multiplyScalar(fftXp[i], fftIchirp[i]);
  113. });
  114. var ifftProduct = dotDivide(conj(_ndFft(conj(fftProduct))), N2);
  115. var ret = [];
  116. for (var _i = n - 1; _i < n + n - 1; _i++) {
  117. ret.push(multiplyScalar(ifftProduct[_i], chirp[_i]));
  118. }
  119. return ret;
  120. }
  121. /**
  122. * Perform an 1-dimensional Fourier transform
  123. *
  124. * @param {Array} arr The array
  125. * @return {Array} resulting array
  126. */
  127. function _fft(arr) {
  128. var len = arr.length;
  129. if (len === 1) return [arr[0]];
  130. if (len % 2 === 0) {
  131. var ret = [].concat((0, _toConsumableArray2["default"])(_fft(arr.filter(function (_, i) {
  132. return i % 2 === 0;
  133. }), len / 2)), (0, _toConsumableArray2["default"])(_fft(arr.filter(function (_, i) {
  134. return i % 2 === 1;
  135. }), len / 2)));
  136. for (var k = 0; k < len / 2; k++) {
  137. var p = ret[k];
  138. var q = multiplyScalar(ret[k + len / 2], exp(multiplyScalar(multiplyScalar(tau, I), divideScalar(-k, len))));
  139. ret[k] = addScalar(p, q);
  140. ret[k + len / 2] = addScalar(p, multiplyScalar(-1, q));
  141. }
  142. return ret;
  143. } else {
  144. // use chirp-z transform for non-power-of-2 FFT
  145. return _czt(arr);
  146. }
  147. // throw new Error('Can only calculate FFT of power-of-two size')
  148. }
  149. });
  150. exports.createFft = createFft;