Matrix Spectrogram_to_Matrix (Spectrogram me) { try { autoMatrix thee = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, my ymin, my ymax, my ny, my dy, my y1); NUMmatrix_copyElements (my z, thy z, 1, my ny, 1, my nx); return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": not converted to Matrix."); } }
autoActivation Matrix_to_Activation (Matrix me) { try { autoActivation thee = Activation_create (my ny, my nx); NUMmatrix_copyElements (my z, thy z, 1, my ny, 1, my nx); return thee; } catch (MelderError) { Melder_throw (me, U": not converted to Activation."); } }
autoMatrix Activation_to_Matrix (Activation me) { try { autoMatrix thee = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, my ymin, my ymax, my ny, my dy, my y1); NUMmatrix_copyElements (my z, thy z, 1, my ny, 1, my nx); return thee; } catch (MelderError) { Melder_throw (me, U": not converted to Matrix."); } }
autoMelSpectrogram Matrix_to_MelSpectrogram (Matrix me) { try { autoMelSpectrogram thee = MelSpectrogram_create (my xmin, my xmax, my nx, my dx, my x1, my ymin, my ymax, my ny, my dy, my y1); NUMmatrix_copyElements (my z, thy z, 1, my ny, 1, my nx); return thee; } catch (MelderError) { Melder_throw (me, U": not converted to MelSpectrogram."); } }
autoTableOfReal SVD_extractRightSingularVectors (SVD me) { try { long mn_min = MIN (my numberOfRows, my numberOfColumns); autoTableOfReal thee = TableOfReal_create (my numberOfColumns, mn_min); NUMmatrix_copyElements (my v, thy data, 1, my numberOfColumns, 1, mn_min); return thee; } catch (MelderError) { Melder_throw (me, U": right singular vector not extracted."); } }
TableOfReal SVD_extractLeftSingularVectors (I) { iam (SVD); try { long mn_min = MIN (my numberOfRows, my numberOfColumns); autoTableOfReal thee = TableOfReal_create (my numberOfRows, mn_min); NUMmatrix_copyElements (my u, thy data, 1, my numberOfRows, 1, mn_min); return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": left singular vector not extracted."); } }
autoConfiguration TableOfReal_to_Configuration (TableOfReal me) { try { autoConfiguration thee = Configuration_create (my numberOfRows, my numberOfColumns); NUMmatrix_copyElements (my data, thy data, 1, my numberOfRows, 1, my numberOfColumns); TableOfReal_copyLabels (me, thee.peek(), 1, 1); return thee; } catch (MelderError) { Melder_throw (me, U": not converted."); } }
FormantFilter Matrix_to_FormantFilter (I) { iam (Matrix); try { autoFormantFilter thee = FormantFilter_create (my xmin, my xmax, my nx, my dx, my x1, my ymin, my ymax, my ny, my dy, my y1); NUMmatrix_copyElements (my z, thy z, 1, my ny, 1, my nx); return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": not converted to FormantFilter."); } }
autoAffineTransform Configurations_to_AffineTransform_congruence (Configuration me, Configuration thee, long maximumNumberOfIterations, double tolerance) { try { // Use Procrustes transform to obtain starting configuration. // (We only need the transformation matrix T.) autoProcrustes p = Configurations_to_Procrustes (me, thee, 0); NUMmaximizeCongruence (my data, thy data, my numberOfRows, p -> n, p -> r, maximumNumberOfIterations, tolerance); autoAffineTransform at = AffineTransform_create (p -> n); NUMmatrix_copyElements (p -> r, at -> r, 1, p -> n, 1, p -> n); return at; } catch (MelderError) { Melder_throw (me, U": no congruence transformation created."); } }
TableOfReal AffineTransform_extractMatrix (I) { iam (AffineTransform); try { autoTableOfReal thee = TableOfReal_create (my n, my n); NUMmatrix_copyElements (my r, thy data, 1, my n, 1, my n); for (long i = 1; i <= my n; i++) { wchar_t label[20]; (void) swprintf (label, 20, L"%ld", i); TableOfReal_setRowLabel (thee.peek(), i, label); TableOfReal_setColumnLabel (thee.peek(), i, label); } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": transformation matrix not extracted."); } }
static void Diagonalizer_and_CrossCorrelationTable_qdiag (Diagonalizer me, CrossCorrelationTables thee, double *cweights, long maxNumberOfIterations, double delta) { try { CrossCorrelationTable c0 = (CrossCorrelationTable) thy item[1]; double **w = my data; long dimension = c0 -> numberOfColumns; autoEigen eigen = Thing_new (Eigen); autoCrossCorrelationTables ccts = Data_copy (thee); autoNUMmatrix<double> pinv (1, dimension, 1, dimension); autoNUMmatrix<double> d (1, dimension, 1, dimension); autoNUMmatrix<double> p (1, dimension, 1, dimension); autoNUMmatrix<double> m1 (1, dimension, 1, dimension); autoNUMmatrix<double> wc (1, dimension, 1, dimension); autoNUMvector<double> wvec (1, dimension); autoNUMvector<double> wnew (1, dimension); autoNUMvector<double> mvec (1, dimension); for (long i = 1; i <= dimension; i++) // Transpose W for (long j = 1; j <= dimension; j++) { wc[i][j] = w[j][i]; } // d = diag(diag(W'*C0*W)); // W = W*d^(-1/2); NUMdmatrix_normalizeColumnVectors (wc.peek(), dimension, dimension, c0 -> data); // scale eigenvectors for sphering // [vb,db] = eig(C0); // P = db^(-1/2)*vb'; Eigen_initFromSymmetricMatrix (eigen.peek(), c0 -> data, dimension); for (long i = 1; i <= dimension; i++) { if (eigen -> eigenvalues[i] < 0) { Melder_throw (U"Covariance matrix not positive definite, eigenvalue[", i, U"] is negative."); } double scalef = 1 / sqrt (eigen -> eigenvalues[i]); for (long j = 1; j <= dimension; j++) { p[dimension - i + 1][j] = scalef * eigen -> eigenvectors[i][j]; } } // P*C[i]*P' for (long ic = 1; ic <= thy size; ic++) { CrossCorrelationTable cov1 = (CrossCorrelationTable) thy item[ic]; CrossCorrelationTable cov2 = (CrossCorrelationTable) ccts -> item[ic]; NUMdmatrices_multiply_VCVp (cov2 -> data, p.peek(), dimension, dimension, cov1 -> data, 1); } // W = P'\W == inv(P') * W NUMpseudoInverse (p.peek(), dimension, dimension, pinv.peek(), 0); NUMdmatrices_multiply_VpC (w, pinv.peek(), dimension, dimension, wc.peek(), dimension); // initialisation for order KN^3 for (long ic = 2; ic <= thy size; ic++) { CrossCorrelationTable cov = (CrossCorrelationTable) ccts -> item[ic]; // C * W NUMdmatrices_multiply_VC (m1.peek(), cov -> data, dimension, dimension, w, dimension); // D += scalef * M1*M1' NUMdmatrices_multiplyScaleAdd (d.peek(), m1.peek(), dimension, dimension, 2 * cweights[ic]); } long iter = 0; double delta_w; autoMelderProgress progress (U"Simultaneous diagonalization of many CrossCorrelationTables..."); try { do { // the standard diagonality measure is rather expensive to calculate so we compare the norms of // differences of eigenvectors. delta_w = 0; for (long kol = 1; kol <= dimension; kol++) { for (long i = 1; i <= dimension; i++) { wvec[i] = w[i][kol]; } update_one_column (ccts.peek(), d.peek(), cweights, wvec.peek(), -1, mvec.peek()); Eigen_initFromSymmetricMatrix (eigen.peek(), d.peek(), dimension); // Eigenvalues already sorted; get eigenvector of smallest ! for (long i = 1; i <= dimension; i++) { wnew[i] = eigen -> eigenvectors[dimension][i]; } update_one_column (ccts.peek(), d.peek(), cweights, wnew.peek(), 1, mvec.peek()); for (long i = 1; i <= dimension; i++) { w[i][kol] = wnew[i]; } // compare norms of eigenvectors. We have to compare ||wvec +/- w_new|| because eigenvectors // may change sign. double normp = 0, normm = 0; for (long j = 1; j <= dimension; j++) { double dm = wvec[j] - wnew[j], dp = wvec[j] + wnew[j]; normp += dm * dm; normm += dp * dp; } normp = normp < normm ? normp : normm; normp = sqrt (normp); delta_w = normp > delta_w ? normp : delta_w; } iter++; Melder_progress ((double) iter / (double) (maxNumberOfIterations + 1), U"Iteration: ", iter, U", norm: ", delta_w); } while (delta_w > delta && iter < maxNumberOfIterations); } catch (MelderError) { Melder_clearError (); } // Revert the sphering W = P'*W; // Take transpose to make W*C[i]W' diagonal instead of W'*C[i]*W => (P'*W)'=W'*P NUMmatrix_copyElements (w, wc.peek(), 1, dimension, 1, dimension); NUMdmatrices_multiply_VpC (w, wc.peek(), dimension, dimension, p.peek(), dimension); // W = W'*P: final result // Calculate the "real" diagonality measure // double dm = CrossCorrelationTables_and_Diagonalizer_getDiagonalityMeasure (thee, me, cweights, 1, thy size); } catch (MelderError) { Melder_throw (me, U" & ", thee, U": no joint diagonalization (qdiag)."); } }
/* This routine is modeled after qdiag.m from Andreas Ziehe, Pavel Laskov, Guido Nolte, Klaus-Robert Müller, A Fast Algorithm for Joint Diagonalization with Non-orthogonal Transformations and its Application to Blind Source Separation, Journal of Machine Learning Research 5 (2004), 777–800. */ static void Diagonalizer_and_CrossCorrelationTables_ffdiag (Diagonalizer me, CrossCorrelationTables thee, long maxNumberOfIterations, double delta) { try { long iter = 0, dimension = my numberOfRows; double **v = my data; autoCrossCorrelationTables ccts = CrossCorrelationTables_and_Diagonalizer_diagonalize (thee, me); autoNUMmatrix<double> w (1, dimension, 1, dimension); autoNUMmatrix<double> vnew (1, dimension, 1, dimension); autoNUMmatrix<double> cc (1, dimension, 1, dimension); for (long i = 1; i <= dimension; i++) { w[i][i] = 1; } autoMelderProgress progress (U"Simultaneous diagonalization of many CrossCorrelationTables..."); double dm_new = CrossCorrelationTables_getDiagonalityMeasure (ccts.peek(), nullptr, 0, 0); try { double dm_old, theta = 1, dm_start = dm_new; do { dm_old = dm_new; for (long i = 1; i <= dimension; i++) { for (long j = i + 1; j <= dimension; j++) { double zii = 0, zij = 0, zjj = 0, yij = 0, yji = 0; // zij = zji for (long k = 1; k <= ccts -> size; k++) { CrossCorrelationTable ct = (CrossCorrelationTable) ccts -> item [k]; zii += ct -> data[i][i] * ct -> data[i][i]; zij += ct -> data[i][i] * ct -> data[j][j]; zjj += ct -> data[j][j] * ct -> data[j][j]; yij += ct -> data[j][j] * ct -> data[i][j]; yji += ct -> data[i][i] * ct -> data[i][j]; } double denom = zjj * zii - zij * zij; if (denom != 0) { w[i][j] = (zij * yji - zii * yij) / denom; w[j][i] = (zij * yij - zjj * yji) / denom; } } } double norma = 0; for (long i = 1; i <= dimension; i++) { double normai = 0; for (long j = 1; j <= dimension; j++) { if (i != j) { normai += fabs (w[i][j]); } } if (normai > norma) { norma = normai; } } // evaluate the norm if (norma > theta) { double normf = 0; for (long i = 1; i <= dimension; i++) for (long j = 1; j <= dimension; j++) if (i != j) { normf += w[i][j] * w[i][j]; } double scalef = theta / sqrt (normf); for (long i = 1; i <= dimension; i++) { for (long j = 1; j <= dimension; j++) { if (i != j) { w[i][j] *= scalef; } } } } // update V NUMmatrix_copyElements (v, vnew.peek(), 1, dimension, 1, dimension); NUMdmatrices_multiply_VC (v, w.peek(), dimension, dimension, vnew.peek(), dimension); for (long k = 1; k <= ccts -> size; k++) { CrossCorrelationTable ct = (CrossCorrelationTable) ccts -> item[k]; NUMmatrix_copyElements (ct -> data, cc.peek(), 1, dimension, 1, dimension); NUMdmatrices_multiply_VCVp (ct -> data, w.peek(), dimension, dimension, cc.peek(), 1); } dm_new = CrossCorrelationTables_getDiagonalityMeasure (ccts.peek(), 0, 0, 0); iter++; Melder_progress ((double) iter / (double) maxNumberOfIterations, U"Iteration: ", iter, U", measure: ", dm_new, U"\n fractional measure: ", dm_new / dm_start); } while (fabs ((dm_old - dm_new) / dm_new) > delta && iter < maxNumberOfIterations); } catch (MelderError) { Melder_clearError (); } } catch (MelderError) { Melder_throw (me, U" & ", thee, U": no joint diagonalization (ffdiag)."); } }
Sound Sound_deepenBandModulation (Sound me, double enhancement_dB, double flow, double fhigh, double slowModulation, double fastModulation, double bandSmoothing) { try { autoSound thee = Data_copy (me); double maximumFactor = pow (10, enhancement_dB / 20), alpha = sqrt (log (2.0)); double alphaslow = alpha / slowModulation, alphafast = alpha / fastModulation; for (long channel = 1; channel <= my ny; channel ++) { autoSound channelSound = Sound_extractChannel (me, channel); autoSpectrum orgspec = Sound_to_Spectrum (channelSound.peek(), true); /* * Keep the part of the sound that is outside the filter bank. */ autoSpectrum spec = Data_copy (orgspec.peek()); Spectrum_stopHannBand (spec.peek(), flow, fhigh, bandSmoothing); autoSound filtered = Spectrum_to_Sound (spec.peek()); long n = thy nx; double *amp = thy z [channel]; for (long i = 1; i <= n; i ++) amp [i] = filtered -> z [1] [i]; autoMelderProgress progress (U"Deepen band modulation..."); double fmin = flow; while (fmin < fhigh) { /* * Take a one-bark frequency band. */ double fmid_bark = NUMhertzToBark (fmin) + 0.5, ceiling; double fmax = NUMbarkToHertz (NUMhertzToBark (fmin) + 1); if (fmax > fhigh) fmax = fhigh; Melder_progress (fmin / fhigh, U"Band: ", Melder_fixed (fmin, 0), U" ... ", Melder_fixed (fmax, 0), U" Hz"); NUMmatrix_copyElements (orgspec -> z, spec -> z, 1, 2, 1, spec -> nx); Spectrum_passHannBand (spec.peek(), fmin, fmax, bandSmoothing); autoSound band = Spectrum_to_Sound (spec.peek()); /* * Compute a relative intensity contour. */ autoSound intensity = Data_copy (band.peek()); n = intensity -> nx; amp = intensity -> z [1]; for (long i = 1; i <= n; i ++) amp [i] = 10 * log10 (amp [i] * amp [i] + 1e-6); autoSpectrum intensityFilter = Sound_to_Spectrum (intensity.peek(), true); n = intensityFilter -> nx; for (long i = 1; i <= n; i ++) { double frequency = intensityFilter -> x1 + (i - 1) * intensityFilter -> dx; double slow = alphaslow * frequency, fast = alphafast * frequency; double factor = exp (- fast * fast) - exp (- slow * slow); intensityFilter -> z [1] [i] *= factor; intensityFilter -> z [2] [i] *= factor; } intensity.reset (Spectrum_to_Sound (intensityFilter.peek())); n = intensity -> nx; amp = intensity -> z [1]; for (long i = 1; i <= n; i ++) amp [i] = pow (10, amp [i] / 2); /* * Clip to maximum enhancement. */ ceiling = 1 + (maximumFactor - 1.0) * (0.5 - 0.5 * cos (NUMpi * fmid_bark / 13)); for (long i = 1; i <= n; i ++) amp [i] = 1 / (1 / amp [i] + 1 / ceiling); n = thy nx; amp = thy z [channel]; for (long i = 1; i <= n; i ++) amp [i] += band -> z [1] [i] * intensity -> z [1] [i]; fmin = fmax; } } Vector_scale (thee.peek(), 0.99); /* Truncate. */ thy xmin = my xmin; thy xmax = my xmax; thy nx = my nx; thy x1 = my x1; return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": band modulation not deepened."); } }
/* Varimax rotation, implementation according to: Jos Ten Berge (1995), "Suppressing permutations or rigid planar rotations: a remedy against nonoptimal varimax rotations", Psychometrika 60, 437-446. */ static void NUMvarimax (double **xm, double **ym, long nr, long nc, int normalizeRows, int quartimax, long maximumNumberOfIterations, double tolerance) { Melder_assert (nr > 0 && nc > 0); NUMmatrix_copyElements (xm, ym, 1, nr, 1, nc); if (nc == 1) { return; } if (nc == 2) { maximumNumberOfIterations = 1; } autoNUMvector<double> u (1, nr); autoNUMvector<double> v (1, nr); autoNUMvector<double> norm; // Normalize sum of squares of each row to one. // After rotation we have to rescale. if (normalizeRows) { norm.reset (1, nr); for (long i = 1; i <= nr; i++) { for (long j = 1; j <= nc; j++) { norm[i] += ym[i][j] * ym[i][j]; } if (norm[i] <= 0.0) { continue; } norm[i] = sqrt (norm[i]); for (long j = 1; j <= nc; j++) { ym[i][j] /= norm[i]; } } } // Initial squared "variance". double varianceSq = NUMsquaredVariance (ym, nr, nc, quartimax); if (varianceSq == 0.0) { return; } // Treat columns pairwise. double varianceSq_old; long numberOfIterations = 0; do { for (long c1 = 1; c1 <= nc; c1++) { for (long c2 = c1 + 1; c2 <= nc; c2++) { double um = 0.0, vm = 0.0; for (long i = 1; i <= nr; i++) { double x = ym[i][c1], y = ym[i][c2]; u[i] = x * x - y * y; um += u[i]; v[i] = 2.0 * x * y; vm += v[i]; } um /= nr; vm /= nr; if (quartimax || nr == 1) { um = vm = 0.0; } /* In the paper just before equation (1): a = 2n u'v, b = n(u'u-v'v), c = sqrt(a^2+b^2) w = -sign(a) sqrt((b+c) / 2c) Tricks: multiplication with n drops out! a's multiplication by 2 outside the loop. */ double a = 0.0, b = 0.0; for (long i = 1; i <= nr; i++) { double ui = u[i] - um, vi = v[i] - vm; a += ui * vi; b += ui * ui - vi * vi; } double c = sqrt (4.0 * a * a + b * b); double w = sqrt ( (c + b) / (2.0 * c)); if (a > 0.0) { w = -w; } double cost = sqrt (0.5 + 0.5 * w); double sint = sqrt (0.5 - 0.5 * w); double t22 = cost; double t11 = cost; double t12 = sint; double t21 = -sint; // Prevent permutations: when w < 0, i.e., a > 0, swap columns of T:/ if (w < 0.0) { t11 = sint; t12 = t21 = cost; t22 = -sint; } // Rotate in the plane spanned by c1 and c2. for (long i = 1; i <= nr; i++) { double *xt = ym[i], xtc1 = xt[c1]; xt[c1] = xtc1 * t11 + xt[c2] * t21; xt[c2] = xtc1 * t12 + xt[c2] * t22; } } } numberOfIterations++; varianceSq_old = varianceSq; varianceSq = NUMsquaredVariance (ym, nr, nc, quartimax); } while (fabs (varianceSq_old - varianceSq) / varianceSq_old > tolerance && numberOfIterations < maximumNumberOfIterations); if (normalizeRows) { for (long i = 1; i <= nr; i++) { for (long j = 1; j <= nc; j++) { ym[i][j] *= norm[i]; } } } }