数学计算库

语音增强和语音识别系列博客

写算法的实现,离不开各种矩阵以及线性代数的运算,包括矩阵求逆,矩阵分解,SVD以及特征值,特征向量等;

尤其是复高斯模型或者在频域里做处理时用到复数矩阵相关运算;APP公司官网的加速链接中就有BLAS相关的API。

这里gsl是开源的计算库,该库的最新文档链接如下:https://www.gnu.org/software/gsl/doc/html/index.html。

music方法使用特征空间法估计信号(自关矩阵)的成分。自相关矩阵的特征值对应的不同特征向量是正交的(现在的深度学习方法也是在找若干组正交基的过程)。特征值最大的对应于该信号在该特征向量上的投影值比较大,也就是包含的信息量要比其它特征向量空间中的大,这在数据压缩领域有应用。

使用gsl实现MUSIC算法的实现代码片段如下:

```

#include <stdio.h>
#include <math.h>
#include "m_pd.h"

#include <gsl/gsl_eigen.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_complex_math.h>
#include <gsl/gsl_blas.h>

#define NOOFITERATIONS 1000
/* music~ : music-code for MUSIC Algorithm
commands for compiling with gcc:
> gcc -Wall -c music~.c
> ld -export-dynamic -shared -o music~.pd_linux music.o -lc -lm -lgsl -lgslcblas
*/
/* ------------------------ music~ ----------------------------- */

static t_class *music_tilde_class;

typedef struct _music_tilde
{
  t_object x_obj;
  t_outlet *x_outlet_value;
  t_outlet *x_outlet_index;
  gsl_matrix_complex *x_cmin;        //input signals
  gsl_matrix_complex *x_cov;        //covariance matrix
  gsl_vector *x_eval;            //eigenvalues
  gsl_matrix_complex *x_evec;        //eigenvectors
  gsl_matrix_complex *x_a;        //array response
  gsl_matrix_complex *x_c;        //
  gsl_matrix_complex *x_c2;
  gsl_eigen_hermv_workspace *x_w;    //calculating eigenvalues and -vectors
  int      x_count;            //sample counter

  t_float  x_msi;            //dummy
} t_music_tilde;

//Function for calculating the array response, which is stored in x->x_a matrix
static void array_response(t_music_tilde *x, double angle){
  double f = 1000;
  double lambda = 343/f;
  double d = 0.04;
  int i, no = 8;

  for (i=0; i<no; i++) {
    if (angle < 0){
      gsl_matrix_complex_set(x->x_a, (no-i-1), 0, gsl_complex_polar(1.0, (-(double)i*2*M_PI*d*sin(angle)/lambda)));
    }
    else {
      gsl_matrix_complex_set(x->x_a, i, 0,  gsl_complex_polar(1.0, (-(double)i*2*M_PI*d*sin(angle)/lambda)));
    }
  }
}

static t_int *music_tilde_perform(t_int *w)
{
  t_music_tilde *x = (t_music_tilde *) w[1];
  t_float *inarray[] = {(t_float *)w[2], (t_float *)w[3], (t_float *)w[4], (t_float *)w[5], (t_float *)w[6], (t_float *)w[7], (t_float *)w[8], (t_float *)w[9], (t_float *)w[10], (t_float *)w[11], (t_float *)w[12], (t_float *)w[13], (t_float *)w[14], (t_float *)w[15], (t_float *)w[16], (t_float *)w[17]};
  int n = (int)(w[18]);
  int i, j, p, nosources;
  int m=0;    //actual sample from 0 to n-1
  double f1, f2, theta_rad;
  gsl_matrix_complex_view nvec;
  gsl_vector *mdl = gsl_vector_alloc(8);
  const gsl_complex alpha = gsl_complex_rect((1/NOOFITERATIONS), (1/NOOFITERATIONS));
  const gsl_complex beta = gsl_complex_rect(0, 0);

  while (n--) {
    if (x->x_count == NOOFITERATIONS) {    // calculate eigenvalues and reset after a certain no of iterations
//normalize the covariance matrix
      gsl_matrix_complex_scale(x->x_cov, alpha);
//gsl command for calculating eigenvalues
      gsl_eigen_hermv(x->x_cov, x->x_eval, x->x_evec, x->x_w);
//print out the result
   //   post("cov[1][1]:%f cov[1][2]:%f cov[2][1]:%f cov[2][2]:%f eval[1]:%f eval[2]:%f", gsl_matrix_get(x->x_cov, 0, 0), gsl_matrix_get(x->x_cov, 0, 1), gsl_matrix_get(x->x_cov, 1, 0), gsl_matrix_get(x->x_cov, 1, 1), gsl_vector_get(x->x_eval, 0), gsl_vector_get(x->x_eval, 1));
//MDL Algorithm for estimating no of sources
      gsl_vector_reverse(x->x_eval);
      p = (int)x->x_eval->size;
      for (i = 0; i < p; i++){
        f1=1.0;
        f2=0.0;
        for (j = i; j < p; j++){
          f1*=pow(gsl_vector_get(x->x_eval, j), (1/(double)(p-i)));
          f2+=gsl_vector_get(x->x_eval, j);
        }
        f2=f2/(p-i);
        gsl_vector_set(mdl, i, (-log(pow((f1/f2), ((p-i)*NOOFITERATIONS)))+0.5*i*(2*p-i)*NOOFITERATIONS));
      }
      nosources = gsl_vector_min_index(mdl);
//Building nvec matrix
      nvec = gsl_matrix_complex_submatrix(x->x_evec, 0, 0, 8, (p-nosources));
      x->x_c = gsl_matrix_complex_alloc(1, (p-nosources));
//estimating the pmu function
      j=0;
      for (i=-90; i<=90; i++) {
        theta_rad=i*M_PI/180;
        array_response(x, theta_rad);
        gsl_blas_zgemm(CblasConjTrans, CblasNoTrans, alpha, x->x_a, &nvec.matrix, beta, x->x_c);
        gsl_blas_zgemm(CblasNoTrans, CblasConjTrans, alpha, x->x_c, x->x_c, beta, x->x_c2);
        outlet_float(x->x_outlet_value, GSL_REAL(gsl_matrix_complex_get(x->x_c2, 1, 1)));
        outlet_float(x->x_outlet_index, j);
        j++;
      }
//reset the temporary variables
      gsl_matrix_complex_set_zero(x->x_cov);
      x->x_count = 0;
    }
// aranging 16 inputs to a 8x1 complex matrix
    for (i=0; i<8; i++) {
      gsl_matrix_complex_set(x->x_cmin, i, 0, gsl_complex_rect((double)inarray[i*2][m], (double)inarray[i*2+1][m]));
    }
// estimating the covariance matrix from 8 complex input signals
    gsl_blas_zgemm(CblasNoTrans, CblasConjTrans, alpha, x->x_cmin, x->x_cmin, alpha, x->x_cov);
// increment counters
    m++;
    x->x_count++;
  }

  return (w+19);
}

static void music_tilde_dsp(t_music_tilde *x, t_signal **sp)
{
  dsp_add(music_tilde_perform, 18, x, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, sp[4]->s_vec, sp[5]->s_vec, sp[6]->s_vec, sp[7]->s_vec, sp[8]->s_vec, sp[9]->s_vec, sp[10]->s_vec, sp[11]->s_vec, sp[12]->s_vec, sp[13]->s_vec, sp[14]->s_vec, sp[15]->s_vec, sp[0]->s_n);
}



static void *music_tilde_new()
{
  t_music_tilde *x = (t_music_tilde *)pd_new(music_tilde_class);
  int k;
  for (k=2; k<=16; k++) {
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
  }
  x->x_outlet_value = outlet_new(&x->x_obj, &s_float);
  x->x_outlet_index = outlet_new(&x->x_obj, &s_float);

//allocating memory
  x->x_cmin = gsl_matrix_complex_alloc(8, 1);
  x->x_cov = gsl_matrix_complex_calloc(8, 8);
  x->x_eval = gsl_vector_alloc(8);
  x->x_evec = gsl_matrix_complex_alloc(8, 8);
  x->x_a = gsl_matrix_complex_alloc(8, 1);
  x->x_c2 = gsl_matrix_complex_alloc(1, 1);
  x->x_w = gsl_eigen_hermv_alloc(8);
  x->x_count = 0;

  return (x);
}

static void music_tilde_free(t_music_tilde *x)    //destructor for deallocating memory
{
  gsl_matrix_complex_free(x->x_cmin);
  gsl_matrix_complex_free(x->x_cov);
  gsl_vector_free(x->x_eval);
  gsl_matrix_complex_free(x->x_evec);
  gsl_matrix_complex_free(x->x_a);
  gsl_matrix_complex_free(x->x_c);
  gsl_matrix_complex_free(x->x_c2);
  gsl_eigen_hermv_free(x->x_w);
}

void music_tilde_setup(void)
{
  music_tilde_class = class_new(gensym("music~"), (t_newmethod)music_tilde_new, (t_method)music_tilde_free,
                 sizeof(t_music_tilde), 0, A_DEFFLOAT, 0);
  CLASS_MAINSIGNALIN(music_tilde_class, t_music_tilde, x_msi);
  class_addmethod(music_tilde_class, nullfn, gensym("signal"), 0);
  class_addmethod(music_tilde_class, (t_method)music_tilde_dsp, gensym("dsp"), 0);

  //class_sethelpsymbol(music_tilde_class, gensym("music/music~"));
}

```

猜你喜欢

转载自blog.csdn.net/shichaog/article/details/80762367
今日推荐