server update, add endpoints
server update (server_convolution.ts) add endpoints of peaks detection, valleys detection, vertices (including peaks and valleys) detection, outliers detection
This commit is contained in:
parent
4cd58e04d4
commit
e8e0e6de2a
3 changed files with 1932 additions and 175 deletions
|
|
@ -99,6 +99,9 @@ function applyBoundary1D(signal: number[], padding: number, boundary: string): n
|
|||
* @param options - Convolution options (mode, boundary)
|
||||
* @returns Convolution result with metadata
|
||||
*/
|
||||
/**
|
||||
* [CORRECTED] Performs 1D convolution between signal and kernel
|
||||
*/
|
||||
export function convolve1D(
|
||||
signal: number[],
|
||||
kernel: number[],
|
||||
|
|
@ -107,40 +110,54 @@ export function convolve1D(
|
|||
validateArray(signal, 'Signal');
|
||||
validateArray(kernel, 'Kernel');
|
||||
|
||||
const { mode = 'same', boundary = 'reflect' } = options;
|
||||
|
||||
// Flip kernel for convolution (not correlation)
|
||||
const { mode = 'full', boundary = 'zero' } = options;
|
||||
const flippedKernel = [...kernel].reverse();
|
||||
|
||||
const signalLen = signal.length;
|
||||
const kernelLen = flippedKernel.length;
|
||||
|
||||
let result: number[] = [];
|
||||
let paddedSignal = signal;
|
||||
|
||||
// Apply boundary conditions based on mode
|
||||
if (mode === 'same' || mode === 'full') {
|
||||
const padding = mode === 'same' ? Math.floor(kernelLen / 2) : kernelLen - 1;
|
||||
paddedSignal = applyBoundary1D(signal, padding, boundary);
|
||||
}
|
||||
|
||||
// Perform convolution
|
||||
const outputLength = mode === 'full' ? signalLen + kernelLen - 1 :
|
||||
mode === 'same' ? signalLen :
|
||||
signalLen - kernelLen + 1;
|
||||
|
||||
const result: number[] = new Array(outputLength);
|
||||
|
||||
const startIdx = mode === 'valid' ? 0 :
|
||||
mode === 'same' ? Math.floor(kernelLen / 2) : 0;
|
||||
|
||||
const halfKernelLen = Math.floor(kernelLen / 2);
|
||||
|
||||
for (let i = 0; i < outputLength; i++) {
|
||||
let sum = 0;
|
||||
for (let j = 0; j < kernelLen; j++) {
|
||||
const signalIdx = startIdx + i + j;
|
||||
if (signalIdx >= 0 && signalIdx < paddedSignal.length) {
|
||||
sum += paddedSignal[signalIdx] * flippedKernel[j];
|
||||
let signalIdx: number;
|
||||
|
||||
switch (mode) {
|
||||
case 'full':
|
||||
signalIdx = i - j;
|
||||
break;
|
||||
case 'same':
|
||||
signalIdx = i - halfKernelLen + j;
|
||||
break;
|
||||
case 'valid':
|
||||
signalIdx = i + j;
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle boundary conditions
|
||||
if (signalIdx >= 0 && signalIdx < signalLen) {
|
||||
sum += signal[signalIdx] * flippedKernel[j];
|
||||
} else if (boundary !== 'zero' && (mode === 'full' || mode === 'same')) {
|
||||
// This is a simplified boundary handler for the logic. Your more complex handler can be used here.
|
||||
let boundaryIdx = signalIdx;
|
||||
if (signalIdx < 0) {
|
||||
boundaryIdx = boundary === 'reflect' ? -signalIdx -1 : -signalIdx;
|
||||
} else if (signalIdx >= signalLen) {
|
||||
boundaryIdx = boundary === 'reflect' ? 2 * signalLen - signalIdx - 1 : 2 * signalLen - signalIdx - 2;
|
||||
}
|
||||
boundaryIdx = Math.max(0, Math.min(signalLen - 1, boundaryIdx));
|
||||
sum += signal[boundaryIdx] * flippedKernel[j];
|
||||
}
|
||||
// If boundary is 'zero', we add nothing, which is correct.
|
||||
}
|
||||
result.push(sum);
|
||||
result[i] = sum;
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue