Source code for musisep.audio.performance

#!python3

"""
Module for calculation of the performance measures for blind source separation.
"""

from __future__ import absolute_import, division, print_function

import numpy as np
import itertools as it

[docs]def orthogonalize(signals): """ Orthogonalize the given signals. Parameters ---------- signals : array_like Matrix with the signals in its rows Returns ------- q_matrix : ndarray Matrix with the orthogonalized signals in its rows """ signals = np.asarray(signals) q_matrix, _ = np.linalg.qr(signals.T) return q_matrix.T
[docs]def project(signals, q_matrix): """ Project the given signals on the given space. Parameters ---------- signals : array_like Matrix with the signals in its rows q_matrix : array_like Matrix with an orthonormal basis of the space in its rows Returns ------- proj_signals : ndarray Matrix with the projected signals in its rows """ signals = np.asarray(signals) q_matrix = np.asarray(q_matrix) return q_matrix.T.dot(q_matrix.dot(signals.T)).T
[docs]class MeasureAcc: """ Container object for the computation of performance measures. Parameters ---------- n : int Number of instruments to consider """ def __init__(self, n): self.n = n self.target_sum = np.zeros((n, n)) self.proj_sum = np.zeros(n) self.distortion = np.zeros((n, n)) self.interference = np.zeros((n, n)) self.artifacts = np.zeros(n)
[docs] def add(self, synth_signals, orig_signals): """ Add portions of signals to the container. Parameters ---------- synth_signals : array_like Matrix with the synthesized signals in its rows orig_signals : array_like Matrix with the original signals in its rows """ synth_signals = np.asarray(synth_signals) orig_signals = np.asarray(orig_signals) orig_signals = orig_signals / np.linalg.norm(orig_signals, axis=1)[:, np.newaxis] proj_signals = project(synth_signals, orthogonalize(orig_signals)) target_signals = (orig_signals.dot(synth_signals.T)[:, :, np.newaxis] * orig_signals[:, np.newaxis, :]) self.target_sum += np.sum(np.square(target_signals), axis=2) self.proj_sum += np.sum(np.square(proj_signals), axis=1) self.distortion += np.sum(np.square(target_signals - synth_signals), axis=2) self.interference += np.sum(np.square(target_signals - proj_signals), axis=2) self.artifacts += np.sum(np.square(proj_signals - synth_signals), axis=1)
[docs] def perms(self): """ Obtain all the permutations of the signals and the related performance measures Returns ------- perms : list of ndarray Permutations of the indices of the signals measures : list of ndarray Arrays with SDR, SIR, and SAR for the signals in rows """ perms = [] measures = [] sig_sar = 10 * np.log10(self.proj_sum / self.artifacts) for p in it.permutations(range(self.n)): idcs0 = np.asarray(p) idcs1 = np.arange(self.n) sig_sdr = 10 * np.log10(self.target_sum[idcs0, idcs1] / self.distortion[idcs0, idcs1]) sig_sir = 10 * np.log10(self.target_sum[idcs0, idcs1] / self.interference[idcs0, idcs1]) perms.append(idcs0) measures.append(np.vstack((sig_sdr, sig_sir, sig_sar))) return perms, measures
[docs]def measures(synth_signals, orig_signals, size=1048576): """ Compute the SDR, SIR, and SAR in all permutations of the synthesized signals. Parameters ---------- synth_signals : array_like Array with the synthesized signals in its rows orig_signals : array_like Array with the original signals in its rows size : int Length of the signal fragments to consider at once Returns ------- perms : list of ndarray Permutations of the indices of the signals measures : list of ndarray Arrays with SDR, SIR, and SAR for the signals in rows """ synth_signals = np.asarray(synth_signals) orig_signals = np.asarray(orig_signals) m = MeasureAcc(orig_signals.shape[0]) pos = np.arange(0, orig_signals.shape[1], size) for p in pos: m.add(synth_signals[:, p:p+size], orig_signals[:, p:p+size]) return m.perms()
[docs]def select_perm(perms, measures): """ Select the permutation with the highest SIR sum. Parameters ---------- perms : list of array_like Permutations of the indices of the signals measures : list of array_like Arrays with SDR, SIR, and SAR for the signals in rows Returns ------- best_perm : ndarray Permutation of `synth_signals` with the lowest SIR sum best_measure : ndarray SDR, SIR, and SAR in the permutation with the lowest SIR sum """ perms = [np.asarray(p) for p in perms] measures = [np.asarray(m) for m in measures] sig_sirs = [np.sum(m[1, :]) for m in measures] idx = np.argmax(np.asarray(sig_sirs)) perm = perms[idx] idcs = np.zeros(perm.size, dtype='int') idcs[perm] = np.arange(perm.size) return perm, measures[idx][:, idcs]