console
var data, tstep = 0.01, ti=0, nxh=3;
var nstep = Math.floor(1/tstep);
const fourier = window.fourier;
function xfft2(array) {
const N = array.length;
if (N === 1) {
return array;
}
if (N % 2 === 0) {
const even = [];
const odd = [];
for (let i = 0; i < N / 2; i++) {
even[i] = array[2 * i];
odd[i] = array[2 * i + 1];
}
const evenFFT = fft(even);
const oddFFT = fft(odd);
const t = [];
for (let k = 0; k < N / 2; k++) {
const tk = Math.cos(-2 * Math.PI * k / N) * oddFFT[k];
const tk2 = Math.sin(-2 * Math.PI * k / N) * oddFFT[k];
t[k] = tk;
t[k + N / 2] = tk2;
}
const result = [];
for (let k = 0; k < N / 2; k++) {
result[k] = (evenFFT[k] + t[k]);
result[k + N / 2] = (evenFFT[k] - t[k]);
}
return result;
}
throw new Error('FFT not implemented for odd length arrays.');
}
function col(d, i) {
var tpd = []
for (k in d) {
tpd.push(d[k][i])
}
return tpd
}
function xor0(v) {
return v > 0 ? v : 0
}
function xsx(d){
var s=[],x=[],a=[];
for(var i=0,iL=d.length/2;i<iL;i++){
s.push(d[i].re);
x.push(d[i].im);
a.push((d[i].re**2+d[i].im**2)**0.5)
}
return [s,x,a]
}
function xser(n){
var tp = []
for(var i=0;i<n;i++){
tp.push(i)
}
return tp
}
function getMaxIndices(d, n) {
const indexedData = d.map((value, index) => ({ value, index }));
indexedData.sort((a, b) => b.value - a.value);
return indexedData.slice(0, n).map(item => item.index);
}
function ks(me) {
if (me.value == "开始") {
data = [];
for (var i = 0, iL = 1024*nxh; i < iL; i++) {
data.push([i * tstep, Math.sin(i/10)*1+Math.sin(i/7)*1+Math.random()*9]);
}
myChart.setOption({
series: {
id: 0,
data: data
}
})
me.value = "结束";
me.tp = setInterval(function(){
ti+=nstep;
if(ti>data.length){ ti -= data.length}
var tiend = ti + 1024, tpdata;
if( tiend>data.length){
tiend = 1024-(data.length-ti);
tpdata = [...data.slice(ti,data.length),...data.slice(0,tiend)]
}else{
tpdata = data.slice(ti,tiend)
}
var sx = xsx(xFFT(col(tpdata,1)))
sx[0][0]=0; sx[1][0]=0; sx[2][0]=0;
console.log(getMaxIndices(sx[2].slice(0,512),2))
myChart.setOption({
series:[
{id: 1,data: sx[2].slice(0,112)},
]
})
},1000);
} else {
clearInterval(me.tp);
me.value = "开始";
}
}
option = {
xAxis: [{
id: 0,
name: 'time',
}, {
id: 1,
gridIndex: 1,
type:'category',
name: 'q',
}],
yAxis: [{
name: 'a',
type: 'value',
scale: false
}, {
gridIndex: 1,
name: 'log10(f)',
type: 'value',
scale: false,
min: 0
}],
grid: [
{ bottom: '60%' },
{ top: '60%' },
],
dataZoom: {},
series: [{
id: 0,
xAxisIndex: 0,
yAxisIndex: 0,
type: 'line',
data: null,
encode: { x: 0, y: 1 },
symbol: 'none',
}, {
id: 1,
xAxisIndex: 1,
yAxisIndex: 1,
type: 'line',
data: null,
clip: true,
}, {
id: 2,
xAxisIndex: 1,
yAxisIndex: 1,
type: 'line',
data: null,
clip: true,
}]
};
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
<div id="main"></div>
<div id="ctrl">
<input type="button" onclick="ks(this)" id="bt" value="开始"></input>
<input type="button" value="导出"></input>
</div>
<script>
class Complex {
constructor(re = 0, im = 0) {
this.re = re;
this.im = im;
}
add(other) {
return new Complex(this.re + other.re, this.im + other.im);
}
sub(other) {
return new Complex(this.re - other.re, this.im - other.im);
}
mul(other) {
return new Complex(
this.re * other.re - this.im * other.im,
this.re * other.im + this.im * other.re
);
}
scale(scalar) {
return new Complex(this.re * scalar, this.im * scalar);
}
conjugate() {
return new Complex(this.re, -this.im);
}
}
function xFFT(input, isInverse = false) {
const complexInput = input.map(n =>
n instanceof Complex ? n : new Complex(n, 0)
);
const N = complexInput.length;
const log2N = Math.log2(N);
if (!Number.isInteger(log2N)) {
const nextPower = Math.ceil(log2N);
const paddedLength = Math.pow(2, nextPower);
return FFT([...complexInput, ...Array(paddedLength - N).fill(new Complex())]);
}
const reversed = Array(N).fill().map((_, i) =>
parseInt(i.toString(2).padStart(log2N, '0').split('').reverse().join(''), 2)
);
const arr = reversed.map(i => complexInput[i]);
for (let s = 1; s <= log2N; s++) {
const m = 1 << s;
const angle = (isInverse ? 2 : -2) * Math.PI / m;
const wm = new Complex(Math.cos(angle), Math.sin(angle));
for (let k = 0; k < N; k += m) {
let w = new Complex(1, 0);
for (let j = 0; j < m/2; j++) {
const t = w.mul(arr[k + j + m/2]);
const u = arr[k + j];
arr[k + j] = u.add(t);
arr[k + j + m/2] = u.sub(t);
w = w.mul(wm);
}
}
}
return isInverse ? arr.map(x => x.scale(1/N)) : arr;
}
</script>
html,body {
width: 100%;
height: 94%;
margin: 3% 0 0 0;
padding: 0;
}
#main {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#ctrl {
position: absolute;
z-index: 999;
left: 10px;
top: 10px;
}