multiplet-analysis
Advanced tools
Comparing version 0.0.3 to 0.1.0
385
lib/index.js
@@ -5,2 +5,5 @@ 'use strict'; | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
var maxY = _interopDefault(require('ml-array-xy-max-y')); | ||
var fftJs = require('fft-js'); | ||
@@ -56,104 +59,2 @@ | ||
function symmetrize(y) { | ||
for (let indi = 0; indi < y.length / 2; indi++) { | ||
const average = (y[indi] + y[y.length - 1 - indi]) / 2; | ||
y[indi] = average; | ||
y[y.length - 1 - indi] = average; | ||
} | ||
return y; | ||
} | ||
function trigInterpolate(x, y, nextPowerTwo, addPhaseInterpolation) { | ||
let sca = Array(nextPowerTwo); | ||
let spe = Array(nextPowerTwo); | ||
let scaIncrement = (x[x.length - 1] - x[0]) / (x.length - 1); // delta one pt | ||
let scaPt = x[0] - scaIncrement / 2; // move to limit side - not middle of first point (half a pt left...) | ||
let trueWidth = scaIncrement * x.length; | ||
scaIncrement = trueWidth / nextPowerTwo; | ||
scaPt += scaIncrement / 2; // move from limit side to middle of first pt | ||
// set scale | ||
for (let loop = 0; loop < nextPowerTwo; loop++) { | ||
sca[loop] = scaPt; | ||
scaPt += scaIncrement; | ||
} | ||
// interpolate spectrum | ||
// prepare input for fft apply fftshift | ||
let nextPowerTwoAn = Math.pow( | ||
2, | ||
Math.round(Math.log(y.length - 1) / Math.log(2.0) + 0.5), | ||
); | ||
let an = [...Array(nextPowerTwoAn)].map(() => Array(2).fill(0)); // n x 2 array | ||
const halfNumPt = Math.floor(y.length / 2); // may ignore last pt... if odd number | ||
const halfNumPtB = y.length - halfNumPt; | ||
const shiftMult = nextPowerTwoAn - y.length; | ||
for (let loop = 0; loop < halfNumPt; loop++) { | ||
an[shiftMult + loop + halfNumPtB][0] = y[loop]; //Re | ||
an[shiftMult + loop + halfNumPtB][1] = 0; //Im | ||
} | ||
for (let loop = 0; loop < halfNumPtB; loop++) { | ||
an[loop][0] = y[loop + halfNumPt]; //Re | ||
an[loop][1] = 0; //Im | ||
} | ||
let out = fftJs.ifft(an); | ||
out[0][0] = out[0][0] / 2; // divide first point by 2 Re | ||
out[0][1] = out[0][1] / 2; // divide first point by 2 Im | ||
// move to larger array... | ||
let an2 = [...Array(nextPowerTwo)].map(() => Array(2).fill(0)); // n x 2 array | ||
for (let loop = 0; loop < halfNumPt; loop++) { | ||
an2[loop][0] = out[loop][0]; //* Math.cos((phase / 180) * Math.PI) + | ||
an2[loop][1] = out[loop][1]; //* Math.cos((phase / 180) * Math.PI) - | ||
} | ||
for (let loop = halfNumPt; loop < nextPowerTwo; loop++) { | ||
// zero filling | ||
an2[loop][0] = 0; | ||
an2[loop][1] = 0; | ||
} | ||
let out2 = fftJs.fft(an2); | ||
const halfNumPt2 = nextPowerTwo / 2; | ||
// applies fftshift | ||
let phase = addPhaseInterpolation; | ||
for (let loop = 0; loop < halfNumPt2; loop++) { | ||
//spe[loop] = out2[loop + halfNumPt2][0]; // only Re now... | ||
spe[loop] = | ||
out2[loop + halfNumPt2][0] * Math.cos((phase / 180) * Math.PI) + | ||
out2[loop + halfNumPt2][1] * Math.sin((phase / 180) * Math.PI); // only Re now... | ||
} | ||
for (let loop = 0; loop < halfNumPt2; loop++) { | ||
//spe[loop + halfNumPt2] = out2[loop][0]; // only Re now... | ||
spe[loop + halfNumPt2] = | ||
out2[loop][0] * Math.cos((phase / 180) * Math.PI) + | ||
out2[loop][1] * Math.sin((phase / 180) * Math.PI); // only Re now... | ||
} | ||
return { spectrum: spe, scale: sca }; | ||
} | ||
function scalarProduct(y1, y2, sens, incrementForSpeed) { | ||
// sens = 1; crude scalar product | ||
// sens =-1: flip spectrum first | ||
let v11 = 0; | ||
let v22 = 0; | ||
let v12 = 0; | ||
if (sens > 0) { | ||
for (let index = 0; index < y1.length; index += incrementForSpeed) { | ||
v12 += y1[index] * y2[index]; | ||
v11 += y1[index] * y1[index]; | ||
v22 += y2[index] * y2[index]; | ||
} | ||
} else { | ||
// Here as if flip left/right array | ||
for (let index = 0; index < y1.length; index += incrementForSpeed) { | ||
v12 += y1[index] * y2[y1.length - index - 1]; | ||
v11 += y1[index] * y1[index]; | ||
v22 += y2[index] * y2[index]; | ||
} | ||
} | ||
return v12 / Math.sqrt(v11 * v22); | ||
} | ||
/** | ||
@@ -217,7 +118,30 @@ * | ||
function scalarProduct(y1, y2, sens, incrementForSpeed) { | ||
// sens = 1; crude scalar product | ||
// sens =-1: flip spectrum first | ||
let v11 = 0; | ||
let v22 = 0; | ||
let v12 = 0; | ||
if (sens > 0) { | ||
for (let index = 0; index < y1.length; index += incrementForSpeed) { | ||
v12 += y1[index] * y2[index]; | ||
v11 += y1[index] * y1[index]; | ||
v22 += y2[index] * y2[index]; | ||
} | ||
} else { | ||
// Here as if flip left/right array | ||
for (let index = 0; index < y1.length; index += incrementForSpeed) { | ||
v12 += y1[index] * y2[y1.length - index - 1]; | ||
v11 += y1[index] * y1[index]; | ||
v22 += y2[index] * y2[index]; | ||
} | ||
} | ||
return v12 / Math.sqrt(v11 * v22); | ||
} | ||
function measureDeco( | ||
y, | ||
JStar, | ||
sign, | ||
chopTail, | ||
y, // input vector | ||
JStar, // tested value of J in pt | ||
sign, // sign of the split 1: ++ -1: +- | ||
chopTail, // 1: cut tail | ||
multiplicity, | ||
@@ -230,36 +154,36 @@ incrementForSpeed, | ||
y2 = deco(y, JStar, sign, -1, chopTail, multiplicity); // dir right to left | ||
return scalarProduct(y1, y2, 1, incrementForSpeed); | ||
return sign * scalarProduct(y1, y2, 1, incrementForSpeed); | ||
} | ||
function measureSym(y) { | ||
let spref; | ||
let spnew; | ||
function measureSymShift(y) { | ||
let ScalarProductReference; | ||
let ScalarProductNewValue; | ||
let movedBy = 0; | ||
spref = scalarProduct(y, y, -1, 1); | ||
ScalarProductReference = scalarProduct(y, y, -1, 1); | ||
// search left... | ||
for (let indi = 1; indi < y.length / 2; indi++) { | ||
spnew = scalarProduct( | ||
y.slice(indi, y.length), | ||
y.slice(indi, y.length), | ||
for (let i = 1; i < y.length / 2; i++) { | ||
ScalarProductNewValue = scalarProduct( | ||
y.slice(i, y.length), | ||
y.slice(i, y.length), | ||
-1, | ||
1, | ||
); | ||
if (spnew > spref) { | ||
// console.log(`${spnew} > ${spref} size: ${y.length}`); | ||
spref = spnew; | ||
movedBy = indi; | ||
if (ScalarProductNewValue > ScalarProductReference) { | ||
// console.log(`${ScalarProductNewValue} > ${ScalarProductReference} size: ${y.length}`); | ||
ScalarProductReference = ScalarProductNewValue; | ||
movedBy = i; | ||
} | ||
} | ||
if (movedBy === 0) { | ||
for (let indi = 1; indi < y.length / 2; indi++) { | ||
spnew = scalarProduct( | ||
y.slice(0, y.length - indi), | ||
y.slice(0, y.length - indi), | ||
for (let i = 1; i < y.length / 2; i++) { | ||
ScalarProductNewValue = scalarProduct( | ||
y.slice(0, y.length - i), | ||
y.slice(0, y.length - i), | ||
-1, | ||
1, | ||
); | ||
if (spnew > spref) { | ||
// console.log(`${spnew} > ${spref} size: ${y.length}`); | ||
spref = spnew; | ||
movedBy = -indi; | ||
if (ScalarProductNewValue > ScalarProductReference) { | ||
// console.log(`${ScalarProductNewValue} > ${ScalarProductReference} size: ${y.length}`); | ||
ScalarProductReference = ScalarProductNewValue; | ||
movedBy = -i; | ||
} | ||
@@ -272,9 +196,173 @@ } | ||
/** | ||
* Analyse X / Y array and extract multiplicity | ||
* @param {object} [data={}] An object containing properties x and y | ||
* @param {object} [options={}] Options (default is empty object) | ||
* @param {number} [options.frequency=400] Acquisition frequency, default is 400 MHz | ||
*/ | ||
function symmetrize(y) { | ||
for (let indi = 0; indi < y.length / 2; indi++) { | ||
const average = (y[indi] + y[y.length - 1 - indi]) / 2; | ||
y[indi] = average; | ||
y[y.length - 1 - indi] = average; | ||
} | ||
return y; | ||
} | ||
function trigInterpolate( | ||
x, | ||
y, | ||
numberOfPointOutput, | ||
addPhaseInterpolation, | ||
appliedPhaseCorrectionType, | ||
) { | ||
let sca = Array(numberOfPointOutput); | ||
let spe = Array(numberOfPointOutput); | ||
let scaIncrement = (x[x.length - 1] - x[0]) / (x.length - 1); // delta one pt | ||
//let scaPt = x[0] - scaIncrement / 2; // move to limit side - not middle of first point (half a pt left...) | ||
let scaPt = x[0]; // move to limit side - not middle of first point (half a pt left...) | ||
let trueWidth = scaIncrement * x.length; | ||
scaIncrement = trueWidth / numberOfPointOutput; | ||
//scaPt += scaIncrement / 2; // move from limit side to middle of first pt | ||
// set scale | ||
for (let loop = 0; loop < numberOfPointOutput; loop++) { | ||
sca[loop] = scaPt; | ||
scaPt += scaIncrement; | ||
} | ||
// interpolate spectrum | ||
// prepare input for fft apply fftshift | ||
let nextPowerTwoInput = Math.pow( | ||
2, | ||
Math.round(Math.log(y.length - 1) / Math.log(2.0) + 0.5), | ||
); | ||
//nextPowerTwoAn = Math.pow(2, Math.ceil(Math.log(y.length) / Math.log(2))); | ||
let an = [...Array(nextPowerTwoInput)].map(() => Array(2).fill(0)); // n x 2 array | ||
const halfNumPt = Math.floor(y.length / 2); // may ignore last pt... if odd number | ||
const halfNumPtB = y.length - halfNumPt; | ||
const shiftMultiplet = nextPowerTwoInput - y.length; | ||
for (let loop = 0; loop < halfNumPt; loop++) { | ||
an[shiftMultiplet + loop + halfNumPtB][0] = y[loop]; //Re | ||
an[shiftMultiplet + loop + halfNumPtB][1] = 0; //Im | ||
} | ||
for (let loop = 0; loop < halfNumPtB; loop++) { | ||
an[loop][0] = y[loop + halfNumPt]; //Re | ||
an[loop][1] = 0; //Im | ||
} | ||
let timeDomain = fftJs.ifft(an); | ||
/*an = fft(out); | ||
for (let loop = 0; loop < 2 * halfNumPt; loop++) { | ||
an[loop][1] = 0; //* Math.cos((phase / 180) * Math.PI) - | ||
} | ||
out = ifft(an);*/ | ||
timeDomain[0][0] = timeDomain[0][0] / 2; // divide first point by 2 Re | ||
timeDomain[0][1] = timeDomain[0][1] / 2; // divide first point by 2 Im | ||
// move to larger array... | ||
let timeDomainZeroFilled = [...Array(numberOfPointOutput)].map(() => | ||
Array(2).fill(0), | ||
); // n x 2 array | ||
for (let loop = 0; loop < halfNumPt; loop++) { | ||
timeDomainZeroFilled[loop][0] = timeDomain[loop][0]; //* Math.cos((phase / 180) * Math.PI) + | ||
timeDomainZeroFilled[loop][1] = timeDomain[loop][1]; //* Math.cos((phase / 180) * Math.PI) - | ||
} | ||
for (let loop = halfNumPt; loop < numberOfPointOutput; loop++) { | ||
// zero filling | ||
timeDomainZeroFilled[loop][0] = 0; | ||
timeDomainZeroFilled[loop][1] = 0; | ||
} | ||
let interpolatedSpectrum = fftJs.fft(timeDomainZeroFilled); | ||
const halfNumPt2 = Math.floor(numberOfPointOutput / 2); | ||
let tmp; | ||
// applies phase change | ||
let phaseRad = ((addPhaseInterpolation + 0.0) / 180.0) * Math.PI; // this is for testing additional phases | ||
if (phaseRad !== 0.0) { | ||
for (let loop = 0; loop < 2 * halfNumPt2; loop++) { | ||
tmp = | ||
interpolatedSpectrum[loop][0] * Math.cos(phaseRad) + | ||
interpolatedSpectrum[loop][1] * Math.sin(phaseRad); // only Re now... | ||
interpolatedSpectrum[loop][1] = | ||
-interpolatedSpectrum[loop][0] * Math.sin(phaseRad) + | ||
interpolatedSpectrum[loop][1] * Math.cos(phaseRad); // only Re now... | ||
interpolatedSpectrum[loop][0] = tmp; | ||
} | ||
} | ||
let returnedPhase = 0; | ||
if (appliedPhaseCorrectionType > 0) { | ||
let localPhaseRad = 0; | ||
let vectx; | ||
let vecty; | ||
let norm; | ||
// let sumNorms; | ||
for (let loo = 1; loo < 100; loo++) { | ||
localPhaseRad = 0; | ||
vectx = 0; | ||
vecty = 0; | ||
// sumNorms = 0; | ||
if (appliedPhaseCorrectionType > 0) { | ||
// if ( true ) { | ||
for (let loop = 0; loop < 2 * halfNumPt2; loop++) { | ||
if (interpolatedSpectrum[loop][0] !== 0) { | ||
localPhaseRad = Math.atan( | ||
interpolatedSpectrum[loop][1] / interpolatedSpectrum[loop][0], | ||
); | ||
} else { | ||
localPhaseRad = | ||
(Math.sign(interpolatedSpectrum[loop][1]) * Math.PI) / 2.0; | ||
} | ||
norm = Math.sqrt( | ||
interpolatedSpectrum[loop][1] * interpolatedSpectrum[loop][1] + | ||
interpolatedSpectrum[loop][0] * interpolatedSpectrum[loop][0], | ||
); | ||
vectx += Math.cos(localPhaseRad) * norm; | ||
vecty += Math.sin(localPhaseRad) * norm; | ||
// sumNorms += norm; | ||
} | ||
if (vectx !== 0) { | ||
localPhaseRad = Math.atan(vecty / vectx); | ||
} else { | ||
localPhaseRad = (Math.sign(vecty) * Math.PI) / 2.0; | ||
} | ||
} | ||
norm = Math.sqrt(vecty * vecty + vectx * vectx); | ||
phaseRad = -(10.0 / (loo * loo)) * Math.sign(vecty); | ||
returnedPhase -= (180.0 * phaseRad) / Math.PI; | ||
// console.log('localPhase ' + (180.0 * localPhaseRad) / Math.PI); | ||
//console.log('returnedPhase ' + returnedPhase); | ||
if (phaseRad !== 0.0) { | ||
for (let loop = 0; loop < 2 * halfNumPt2; loop++) { | ||
tmp = | ||
interpolatedSpectrum[loop][0] * Math.cos(phaseRad) + | ||
interpolatedSpectrum[loop][1] * Math.sin(phaseRad); // only Re now... | ||
interpolatedSpectrum[loop][1] = | ||
-interpolatedSpectrum[loop][0] * Math.sin(phaseRad) + | ||
interpolatedSpectrum[loop][1] * Math.cos(phaseRad); // only Re now... | ||
interpolatedSpectrum[loop][0] = tmp; | ||
} | ||
} | ||
} | ||
} | ||
// applies fftshift | ||
for (let loop = 0; loop < halfNumPt2; loop++) { | ||
spe[loop] = interpolatedSpectrum[loop + halfNumPt2][0]; // only Re now... | ||
} | ||
for (let loop = 0; loop < halfNumPt2; loop++) { | ||
spe[loop + halfNumPt2] = interpolatedSpectrum[loop][0]; | ||
} | ||
if (returnedPhase > 360.0) { | ||
returnedPhase -= 360.0; | ||
} | ||
return { | ||
spectrum: spe, | ||
scale: sca, | ||
phaseCorrectionOnMultipletInDeg: returnedPhase, | ||
}; | ||
} | ||
/* eslint-disable no-console */ | ||
/** | ||
@@ -305,2 +393,3 @@ * Analyse a multiplet | ||
forceFirstDeconvolutionToThisValue = 0, | ||
appliedPhaseCorrectionType = 0, | ||
} = options; | ||
@@ -334,6 +423,11 @@ | ||
let topPosJ = 0; | ||
if (resolutionHz > minimalResolution) { | ||
// need increase resolution | ||
let returned = trigInterpolate(x, y, nextPowerTwo, addPhaseInterpolation); | ||
let returned = trigInterpolate( | ||
x, | ||
y, | ||
nextPowerTwo, | ||
addPhaseInterpolation, | ||
appliedPhaseCorrectionType, | ||
); | ||
if (debug) console.log(`interpolating`); | ||
@@ -343,2 +437,4 @@ | ||
sca = returned.scale; | ||
result.phaseCorrectionOnMultipletInDeg = | ||
returned.phaseCorrectionOnMultipletInDeg; | ||
} else { | ||
@@ -390,3 +486,3 @@ sca = x; | ||
if (symmetrizeEachStep === true) { | ||
movedBy = -measureSym(spe); | ||
movedBy = -measureSymShift(spe); | ||
if (movedBy > 0) { | ||
@@ -539,7 +635,14 @@ spe = spe.slice(0, spe.length - movedBy); | ||
if (sca.length !== spe.length) { | ||
ErrorEvent('sts');// this is an ugly way to make sure to get an error when this occurs | ||
throw Error('sts'); | ||
} | ||
} | ||
} | ||
let curTop = -1000000000000000000.0; | ||
// to be tested ... | ||
let maxAmplitudePosition = maxY({ x: sca, y: spe }); | ||
result.chemShift = sca[maxAmplitudePosition.index]; | ||
// for non-javascript implementation | ||
/* | ||
let curTop = Number.NEGATIVE_INFINITY; | ||
let curChemShift; | ||
@@ -552,3 +655,4 @@ for (let i = 0; i < spe.length; i++) { | ||
} | ||
result.chemShift = curChemShift; | ||
result.chemShift = curChemShift;*/ | ||
// end to be commented | ||
@@ -675,3 +779,4 @@ return result; | ||
title(['J(' num2str(main_j_loop) ')=' num2str(symj(top_pos)*hz_per_pt_interp,3) ' Hz']) | ||
nbpt=symj(top_pos); | ||
=symj(top_pos); | ||
[v1, v2]=deco(segment_int',nbpt); | ||
@@ -678,0 +783,0 @@ segment_int=(v1*0.5+0.5*v2)'; |
111
package.json
{ | ||
"name": "multiplet-analysis", | ||
"version": "0.0.3", | ||
"description": "", | ||
"main": "lib/index.js", | ||
"module": "src/index.js", | ||
"files": [ | ||
"lib", | ||
"src" | ||
], | ||
"scripts": { | ||
"eslint": "eslint src", | ||
"eslint-fix": "npm run eslint -- --fix", | ||
"prepublishOnly": "rollup -c", | ||
"test": "npm run test-coverage && npm run eslint", | ||
"test-coverage": "jest --coverage", | ||
"test-only": "jest" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/cheminfo/multiplet-analysis.git" | ||
}, | ||
"keywords": [], | ||
"author": "Luc Patiny", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/cheminfo/multiplet-analysis/issues" | ||
}, | ||
"homepage": "https://github.com/cheminfo/multiplet-analysis#readme", | ||
"jest": { | ||
"testEnvironment": "node" | ||
}, | ||
"prettier": { | ||
"arrowParens": "always", | ||
"semi": true, | ||
"singleQuote": true, | ||
"tabWidth": 2, | ||
"trailingComma": "all" | ||
}, | ||
"devDependencies": { | ||
"@babel/plugin-transform-modules-commonjs": "^7.7.5", | ||
"eslint": "^6.8.0", | ||
"eslint-config-cheminfo": "^2.0.4", | ||
"eslint-plugin-import": "^2.20.0", | ||
"eslint-plugin-jest": "^23.4.0", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"esm": "^3.2.25", | ||
"jest": "^24.9.0", | ||
"nmr-simulation": "^1.0.19", | ||
"prettier": "^1.19.1", | ||
"rollup": "^1.29.0" | ||
}, | ||
"dependencies": { | ||
"fft-js": "0.0.12", | ||
"ml-fft": "^1.3.5" | ||
} | ||
"name": "multiplet-analysis", | ||
"version": "0.1.0", | ||
"description": "", | ||
"main": "lib/index.js", | ||
"module": "src/index.js", | ||
"files": [ | ||
"lib", | ||
"src" | ||
], | ||
"scripts": { | ||
"eslint": "eslint src", | ||
"eslint-fix": "npm run eslint -- --fix", | ||
"prepublishOnly": "rollup -c", | ||
"test": "npm run test-coverage && npm run eslint", | ||
"test-coverage": "jest --coverage", | ||
"test-only": "jest" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/cheminfo/multiplet-analysis.git" | ||
}, | ||
"keywords": [], | ||
"author": "Luc Patiny", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/cheminfo/multiplet-analysis/issues" | ||
}, | ||
"homepage": "https://github.com/cheminfo/multiplet-analysis#readme", | ||
"jest": { | ||
"testEnvironment": "node" | ||
}, | ||
"prettier": { | ||
"arrowParens": "always", | ||
"semi": true, | ||
"singleQuote": true, | ||
"tabWidth": 2, | ||
"trailingComma": "all" | ||
}, | ||
"devDependencies": { | ||
"@babel/plugin-transform-modules-commonjs": "^7.9.0", | ||
"eslint": "^6.8.0", | ||
"eslint-config-cheminfo": "^3.0.0", | ||
"eslint-plugin-import": "^2.20.2", | ||
"eslint-plugin-jest": "^23.8.2", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"esm": "^3.2.25", | ||
"jest": "^25.2.3", | ||
"nmr-simulation": "^1.0.19", | ||
"prettier": "^2.0.2", | ||
"rollup": "^2.2.0" | ||
}, | ||
"dependencies": { | ||
"fft-js": "0.0.12", | ||
"ml-array-xy-max-y": "^1.0.1", | ||
"ml-fft": "^1.3.5" | ||
} | ||
} |
@@ -27,2 +27,3 @@ # multiplet-analysis | ||
`node -r esm examples/simulate.js` to simulate from a user-defined spin system | ||
`node -r esm examples/dd-exp.js` to simulate from a user-defined spin system | ||
@@ -29,0 +30,0 @@ |
@@ -1,2 +0,1 @@ | ||
/** | ||
@@ -3,0 +2,0 @@ * |
@@ -0,1 +1,2 @@ | ||
/* eslint-disable no-console */ | ||
/** | ||
@@ -8,8 +9,10 @@ * Analyse X / Y array and extract multiplicity | ||
import maxY from 'ml-array-xy-max-y'; | ||
import { appendDebug } from './appendDebug'; | ||
import { deco } from './deco'; | ||
import { measureDeco } from './measureDeco'; | ||
import { measureSymShift } from './measureSymShift'; | ||
import { symmetrize } from './symmetrize'; | ||
import { trigInterpolate } from './trigInterpolate'; | ||
import { measureDeco } from './measureDeco'; | ||
import { deco } from './deco'; | ||
import { measureSym } from './measureSym'; | ||
@@ -41,2 +44,3 @@ /** | ||
forceFirstDeconvolutionToThisValue = 0, | ||
appliedPhaseCorrectionType = 0, | ||
} = options; | ||
@@ -70,6 +74,11 @@ | ||
let topPosJ = 0; | ||
if (resolutionHz > minimalResolution) { | ||
// need increase resolution | ||
let returned = trigInterpolate(x, y, nextPowerTwo, addPhaseInterpolation); | ||
let returned = trigInterpolate( | ||
x, | ||
y, | ||
nextPowerTwo, | ||
addPhaseInterpolation, | ||
appliedPhaseCorrectionType, | ||
); | ||
if (debug) console.log(`interpolating`); | ||
@@ -79,2 +88,4 @@ | ||
sca = returned.scale; | ||
result.phaseCorrectionOnMultipletInDeg = | ||
returned.phaseCorrectionOnMultipletInDeg; | ||
} else { | ||
@@ -126,3 +137,3 @@ sca = x; | ||
if (symmetrizeEachStep === true) { | ||
movedBy = -measureSym(spe); | ||
movedBy = -measureSymShift(spe); | ||
if (movedBy > 0) { | ||
@@ -275,7 +286,14 @@ spe = spe.slice(0, spe.length - movedBy); | ||
if (sca.length !== spe.length) { | ||
ErrorEvent('sts');// this is an ugly way to make sure to get an error when this occurs | ||
throw Error('sts'); | ||
} | ||
} | ||
} | ||
let curTop = -1000000000000000000.0; | ||
// to be tested ... | ||
let maxAmplitudePosition = maxY({ x: sca, y: spe }); | ||
result.chemShift = sca[maxAmplitudePosition.index]; | ||
// for non-javascript implementation | ||
/* | ||
let curTop = Number.NEGATIVE_INFINITY; | ||
let curChemShift; | ||
@@ -288,3 +306,4 @@ for (let i = 0; i < spe.length; i++) { | ||
} | ||
result.chemShift = curChemShift; | ||
result.chemShift = curChemShift;*/ | ||
// end to be commented | ||
@@ -411,3 +430,4 @@ return result; | ||
title(['J(' num2str(main_j_loop) ')=' num2str(symj(top_pos)*hz_per_pt_interp,3) ' Hz']) | ||
nbpt=symj(top_pos); | ||
=symj(top_pos); | ||
[v1, v2]=deco(segment_int',nbpt); | ||
@@ -414,0 +434,0 @@ segment_int=(v1*0.5+0.5*v2)'; |
@@ -0,9 +1,9 @@ | ||
import { deco } from './deco'; | ||
import { scalarProduct } from './scalarProduct'; | ||
import { deco } from './deco'; | ||
export function measureDeco( | ||
y, | ||
JStar, | ||
sign, | ||
chopTail, | ||
y, // input vector | ||
JStar, // tested value of J in pt | ||
sign, // sign of the split 1: ++ -1: +- | ||
chopTail, // 1: cut tail | ||
multiplicity, | ||
@@ -16,3 +16,3 @@ incrementForSpeed, | ||
y2 = deco(y, JStar, sign, -1, chopTail, multiplicity); // dir right to left | ||
return scalarProduct(y1, y2, 1, incrementForSpeed); | ||
} | ||
return sign * scalarProduct(y1, y2, 1, incrementForSpeed); | ||
} |
@@ -8,2 +8,2 @@ export function symmetrize(y) { | ||
return y; | ||
} | ||
} |
import { fft, ifft } from 'fft-js'; | ||
export function trigInterpolate(x, y, nextPowerTwo, addPhaseInterpolation) { | ||
let sca = Array(nextPowerTwo); | ||
let spe = Array(nextPowerTwo); | ||
export function trigInterpolate( | ||
x, | ||
y, | ||
numberOfPointOutput, | ||
addPhaseInterpolation, | ||
appliedPhaseCorrectionType, | ||
) { | ||
let sca = Array(numberOfPointOutput); | ||
let spe = Array(numberOfPointOutput); | ||
let scaIncrement = (x[x.length - 1] - x[0]) / (x.length - 1); // delta one pt | ||
let scaPt = x[0] - scaIncrement / 2; // move to limit side - not middle of first point (half a pt left...) | ||
//let scaPt = x[0] - scaIncrement / 2; // move to limit side - not middle of first point (half a pt left...) | ||
let scaPt = x[0]; // move to limit side - not middle of first point (half a pt left...) | ||
let trueWidth = scaIncrement * x.length; | ||
scaIncrement = trueWidth / nextPowerTwo; | ||
scaPt += scaIncrement / 2; // move from limit side to middle of first pt | ||
scaIncrement = trueWidth / numberOfPointOutput; | ||
//scaPt += scaIncrement / 2; // move from limit side to middle of first pt | ||
// set scale | ||
for (let loop = 0; loop < nextPowerTwo; loop++) { | ||
for (let loop = 0; loop < numberOfPointOutput; loop++) { | ||
sca[loop] = scaPt; | ||
@@ -21,13 +28,14 @@ scaPt += scaIncrement; | ||
// prepare input for fft apply fftshift | ||
let nextPowerTwoAn = Math.pow( | ||
let nextPowerTwoInput = Math.pow( | ||
2, | ||
Math.round(Math.log(y.length - 1) / Math.log(2.0) + 0.5), | ||
); | ||
let an = [...Array(nextPowerTwoAn)].map(() => Array(2).fill(0)); // n x 2 array | ||
//nextPowerTwoAn = Math.pow(2, Math.ceil(Math.log(y.length) / Math.log(2))); | ||
let an = [...Array(nextPowerTwoInput)].map(() => Array(2).fill(0)); // n x 2 array | ||
const halfNumPt = Math.floor(y.length / 2); // may ignore last pt... if odd number | ||
const halfNumPtB = y.length - halfNumPt; | ||
const shiftMult = nextPowerTwoAn - y.length; | ||
const shiftMultiplet = nextPowerTwoInput - y.length; | ||
for (let loop = 0; loop < halfNumPt; loop++) { | ||
an[shiftMult + loop + halfNumPtB][0] = y[loop]; //Re | ||
an[shiftMult + loop + halfNumPtB][1] = 0; //Im | ||
an[shiftMultiplet + loop + halfNumPtB][0] = y[loop]; //Re | ||
an[shiftMultiplet + loop + halfNumPtB][1] = 0; //Im | ||
} | ||
@@ -39,35 +47,117 @@ for (let loop = 0; loop < halfNumPtB; loop++) { | ||
let out = ifft(an); | ||
let timeDomain = ifft(an); | ||
/*an = fft(out); | ||
for (let loop = 0; loop < 2 * halfNumPt; loop++) { | ||
an[loop][1] = 0; //* Math.cos((phase / 180) * Math.PI) - | ||
} | ||
out = ifft(an);*/ | ||
out[0][0] = out[0][0] / 2; // divide first point by 2 Re | ||
out[0][1] = out[0][1] / 2; // divide first point by 2 Im | ||
timeDomain[0][0] = timeDomain[0][0] / 2; // divide first point by 2 Re | ||
timeDomain[0][1] = timeDomain[0][1] / 2; // divide first point by 2 Im | ||
// move to larger array... | ||
let an2 = [...Array(nextPowerTwo)].map(() => Array(2).fill(0)); // n x 2 array | ||
let timeDomainZeroFilled = [...Array(numberOfPointOutput)].map(() => | ||
Array(2).fill(0), | ||
); // n x 2 array | ||
for (let loop = 0; loop < halfNumPt; loop++) { | ||
an2[loop][0] = out[loop][0]; //* Math.cos((phase / 180) * Math.PI) + | ||
an2[loop][1] = out[loop][1]; //* Math.cos((phase / 180) * Math.PI) - | ||
timeDomainZeroFilled[loop][0] = timeDomain[loop][0]; //* Math.cos((phase / 180) * Math.PI) + | ||
timeDomainZeroFilled[loop][1] = timeDomain[loop][1]; //* Math.cos((phase / 180) * Math.PI) - | ||
} | ||
for (let loop = halfNumPt; loop < nextPowerTwo; loop++) { | ||
for (let loop = halfNumPt; loop < numberOfPointOutput; loop++) { | ||
// zero filling | ||
an2[loop][0] = 0; | ||
an2[loop][1] = 0; | ||
timeDomainZeroFilled[loop][0] = 0; | ||
timeDomainZeroFilled[loop][1] = 0; | ||
} | ||
let out2 = fft(an2); | ||
const halfNumPt2 = nextPowerTwo / 2; | ||
let interpolatedSpectrum = fft(timeDomainZeroFilled); | ||
const halfNumPt2 = Math.floor(numberOfPointOutput / 2); | ||
let tmp; | ||
// applies phase change | ||
let phaseRad = ((addPhaseInterpolation + 0.0) / 180.0) * Math.PI; // this is for testing additional phases | ||
if (phaseRad !== 0.0) { | ||
for (let loop = 0; loop < 2 * halfNumPt2; loop++) { | ||
tmp = | ||
interpolatedSpectrum[loop][0] * Math.cos(phaseRad) + | ||
interpolatedSpectrum[loop][1] * Math.sin(phaseRad); // only Re now... | ||
interpolatedSpectrum[loop][1] = | ||
-interpolatedSpectrum[loop][0] * Math.sin(phaseRad) + | ||
interpolatedSpectrum[loop][1] * Math.cos(phaseRad); // only Re now... | ||
interpolatedSpectrum[loop][0] = tmp; | ||
} | ||
} | ||
let returnedPhase = 0; | ||
if (appliedPhaseCorrectionType > 0) { | ||
let localPhaseRad = 0; | ||
let vectx; | ||
let vecty; | ||
let norm; | ||
// let sumNorms; | ||
for (let loo = 1; loo < 100; loo++) { | ||
localPhaseRad = 0; | ||
vectx = 0; | ||
vecty = 0; | ||
// sumNorms = 0; | ||
if (appliedPhaseCorrectionType > 0) { | ||
// if ( true ) { | ||
for (let loop = 0; loop < 2 * halfNumPt2; loop++) { | ||
if (interpolatedSpectrum[loop][0] !== 0) { | ||
localPhaseRad = Math.atan( | ||
interpolatedSpectrum[loop][1] / interpolatedSpectrum[loop][0], | ||
); | ||
} else { | ||
localPhaseRad = | ||
(Math.sign(interpolatedSpectrum[loop][1]) * Math.PI) / 2.0; | ||
} | ||
norm = Math.sqrt( | ||
interpolatedSpectrum[loop][1] * interpolatedSpectrum[loop][1] + | ||
interpolatedSpectrum[loop][0] * interpolatedSpectrum[loop][0], | ||
); | ||
vectx += Math.cos(localPhaseRad) * norm; | ||
vecty += Math.sin(localPhaseRad) * norm; | ||
// sumNorms += norm; | ||
} | ||
if (vectx !== 0) { | ||
localPhaseRad = Math.atan(vecty / vectx); | ||
} else { | ||
localPhaseRad = (Math.sign(vecty) * Math.PI) / 2.0; | ||
} | ||
} | ||
norm = Math.sqrt(vecty * vecty + vectx * vectx); | ||
phaseRad = -(10.0 / (loo * loo)) * Math.sign(vecty); | ||
returnedPhase -= (180.0 * phaseRad) / Math.PI; | ||
// console.log('localPhase ' + (180.0 * localPhaseRad) / Math.PI); | ||
//console.log('returnedPhase ' + returnedPhase); | ||
if (phaseRad !== 0.0) { | ||
for (let loop = 0; loop < 2 * halfNumPt2; loop++) { | ||
tmp = | ||
interpolatedSpectrum[loop][0] * Math.cos(phaseRad) + | ||
interpolatedSpectrum[loop][1] * Math.sin(phaseRad); // only Re now... | ||
interpolatedSpectrum[loop][1] = | ||
-interpolatedSpectrum[loop][0] * Math.sin(phaseRad) + | ||
interpolatedSpectrum[loop][1] * Math.cos(phaseRad); // only Re now... | ||
interpolatedSpectrum[loop][0] = tmp; | ||
} | ||
} | ||
} | ||
} | ||
// applies fftshift | ||
let phase = addPhaseInterpolation; | ||
for (let loop = 0; loop < halfNumPt2; loop++) { | ||
//spe[loop] = out2[loop + halfNumPt2][0]; // only Re now... | ||
spe[loop] = | ||
out2[loop + halfNumPt2][0] * Math.cos((phase / 180) * Math.PI) + | ||
out2[loop + halfNumPt2][1] * Math.sin((phase / 180) * Math.PI); // only Re now... | ||
spe[loop] = interpolatedSpectrum[loop + halfNumPt2][0]; // only Re now... | ||
} | ||
for (let loop = 0; loop < halfNumPt2; loop++) { | ||
//spe[loop + halfNumPt2] = out2[loop][0]; // only Re now... | ||
spe[loop + halfNumPt2] = | ||
out2[loop][0] * Math.cos((phase / 180) * Math.PI) + | ||
out2[loop][1] * Math.sin((phase / 180) * Math.PI); // only Re now... | ||
spe[loop + halfNumPt2] = interpolatedSpectrum[loop][0]; | ||
} | ||
return { spectrum: spe, scale: sca }; | ||
if (returnedPhase > 360.0) { | ||
returnedPhase -= 360.0; | ||
} | ||
return { | ||
spectrum: spe, | ||
scale: sca, | ||
phaseCorrectionOnMultipletInDeg: returnedPhase, | ||
}; | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
59947
15
1497
105
3
+ Addedml-array-xy-max-y@^1.0.1
+ Addedbinary-search@1.3.6(transitive)
+ Addedml-array-xy-max-y@1.0.2(transitive)
+ Addednum-sort@2.1.0(transitive)