""" Module: libfmp.c4.c4s4_novelty_kernel Author: Meinard Müller, Julian Reck License: The MIT license, https://opensource.org/licenses/MIT This file is part of the FMP Notebooks (https://www.audiolabs-erlangen.de/FMP) """ import numpy as np from numba import jit def compute_kernel_checkerboard_box(L): """Compute box-like checkerboard kernel [FMP, Section 4.4.1] Notebook: C4/C4S4_NoveltySegmentation.ipynb Args: L: Parameter specifying the kernel size 2*L+1 Returns: kernel: Kernel matrix of size (2*L+1) x (2*L+1) """ axis = np.arange(-L, L+1) kernel = np.outer(np.sign(axis), np.sign(axis)) return kernel @jit(nopython=True) def compute_kernel_checkerboard_gaussian(L, var=1, normalize=True): """Compute Guassian-like checkerboard kernel [FMP, Section 4.4.1] See also: https://scipython.com/blog/visualizing-the-bivariate-gaussian-distribution/ Notebook: C4/C4S4_NoveltySegmentation.ipynb Args: L: Parameter specifying the kernel size M=2*L+1 var: Variance parameter determing the tapering (epsilon) Returns: kernel: Kernel matrix of size M x M """ taper = np.sqrt(1/2) / (L * var) axis = np.arange(-L, L+1) gaussian1D = np.exp(-taper**2 * (axis**2)) gaussian2D = np.outer(gaussian1D, gaussian1D) kernel_box = np.outer(np.sign(axis), np.sign(axis)) kernel = kernel_box * gaussian2D if normalize: kernel = kernel / np.sum(np.abs(kernel)) return kernel # @jit(nopython=True) def compute_novelty_ssm(S, kernel=None, L=10, var=0.5, exclude=False): """Compute novelty function from SSM [FMP, Section 4.4.1] Notebook: C4/C4S4_NoveltySegmentation.ipynb Args: S: SSM kernel: Checkerboard kernel (if kernel==None, it will be computed) L: Parameter specifying the kernel size M=2*L+1 var: Variance parameter determing the tapering (epsilon) exclude: Sets the first L and last L values of novelty function to zero Returns: nov: Novelty function """ if kernel is None: kernel = compute_kernel_checkerboard_gaussian(L=L, var=var) N = S.shape[0] M = 2*L + 1 nov = np.zeros(N) # np.pad does not work with numba/jit S_padded = np.pad(S, L, mode='constant') for n in range(N): # Does not work with numba/jit nov[n] = np.sum(S_padded[n:n+M, n:n+M] * kernel) if exclude: right = np.min([L, N]) left = np.max([0, N-L]) nov[0:right] = 0 nov[left:N] = 0 return nov