66 for(n=0; n<order+2; n++)
69 for(n=0; n < order+1; n++)
70 for(i=o[n]; i < o[n+1]; i++)
85 if(pData->
hSTFT==NULL)
87 else if(arraySpecs->
newQ != arraySpecs->
Q || nSH != new_nSH){
92 arraySpecs->
Q = arraySpecs->
newQ;
102 int i, j, band, n, order, nSH;
103 double alpha, beta, g_lim, regPar;
106 float* Y_mic, *pinv_Y_mic;
107 float_complex* pinv_Y_mic_cmplx, *diag_bN_inv_R;
108 const float_complex calpha = cmplxf(1.0f, 0.0f);
const float_complex cbeta = cmplxf(0.0f, 0.0f);
112 nSH = (order+1)*(order+1);
113 arraySpecs->
R =
SAF_MIN(arraySpecs->
R, arraySpecs->
r);
118 for(i=0; i<arraySpecs->
Q; i++){
124 Y_mic =
malloc1d(nSH*(arraySpecs->
Q)*
sizeof(
float));
125 getRSH(order, (
float*)sensorCoords_deg_local, arraySpecs->
Q, Y_mic);
126 pinv_Y_mic =
malloc1d( arraySpecs->
Q * nSH *
sizeof(
float));
128 pinv_Y_mic_cmplx =
malloc1d((arraySpecs->
Q) * nSH *
sizeof(float_complex));
129 for(i=0; i<(arraySpecs->
Q)*nSH; i++)
130 pinv_Y_mic_cmplx[i] = cmplxf(pinv_Y_mic[i], 0.0f);
159 if(arraySpecs->
R == arraySpecs->
r )
177 for(n=0; n < order+1; n++)
178 pData->
bN[band*(order+1)+n] = ccdiv(pData->
bN[band*(order+1)+n], cmplx(4.0*
SAF_PId, 0.0));
183 for(n=0; n < order+1; n++)
184 pData->
bN_modal[band][n] = ccdiv(cmplx(1.0,0.0), (pData->
bN[band*(order+1)+n]));
191 g_lim = sqrt(arraySpecs->
Q)*pow(10.0,(regPar/20.0));
193 for(n=0; n < order+1; n++)
194 pData->
bN_inv[band][n] = crmul(pData->
bN_modal[band][n], (2.0*g_lim*cabs(pData->
bN[band*(order+1)+n]) /
SAF_PId)
195 * atan(
SAF_PId / (2.0*g_lim*cabs(pData->
bN[band*(order+1)+n]))) );
200 alpha = sqrt(arraySpecs->
Q)*pow(10.0,(regPar/20.0));
202 for(n=0; n < order+1; n++){
203 beta = sqrt((1.0-sqrt(1.0-1.0/ pow(alpha,2.0)))/(1.0+sqrt(1.0-1.0/pow(alpha,2.0))));
204 pData->
bN_inv[band][n] = ccdiv(conj(pData->
bN[band*(order+1)+n]), cmplx((pow(cabs(pData->
bN[band*(order+1)+n]), 2.0) + pow(beta, 2.0)),0.0));
212 diag_bN_inv_R =
calloc1d(nSH*nSH,
sizeof(float_complex));
215 diag_bN_inv_R[i*nSH+i] = cmplxf((
float)creal(pData->
bN_inv_R[band][i]), (
float)cimag(pData->
bN_inv_R[band][i]));
216 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasTrans, nSH, (arraySpecs->
Q), nSH, &calpha,
218 pinv_Y_mic_cmplx, nSH, &cbeta,
249 for (n=0; n<order+1; n++){
251 H[band][n] = 1.0/(1.0+ pow((
double)(pData->
freqVector[band]/f_lim[n]),2.0));
253 H[band][n] = pow((
double)(pData->
freqVector[band]/f_lim[n-1]), (
double)order+1.0 ) /
254 (1.0 + pow((
double)(pData->
freqVector[band]/f_lim[n-1]), (
double)order+1.0));
256 H[band][n] = pow((
double)(pData->
freqVector[band]/f_lim[n-1]), (
double)n+1.0 ) /
257 (1.0 + pow((
double)(pData->
freqVector[band]/f_lim[n-1]), (
double)n+1.0)) *
258 (1.0 / (1.0 + pow((
double)(pData->
freqVector[band]/f_lim[n]), (
double)n+2.0)));
262 for (n=0; n<order+1; n++)
263 H[band][n] = H[band][n]/normH;
289 if(arraySpecs->
R == arraySpecs->
r )
308 for(n=0; n < order+1; n++)
309 pData->
bN_modal[band][n] = ccdiv(cmplx(4.0*
SAF_PId, 0.0), pData->
bN[band*(order+1)+n]);
313 for (n=0; n<order+1; n++)
314 Hs[band][n] = ccmul(cexp(cmplx(0.0, kr[band])), ccdiv(cmplx(4.0*
SAF_PId, 0.0), pData->
bN[band*(order+1)+n]));
322 for (n=0; n<order+1; n++){
324 wn =
calloc1d(nSH_n*nSH_n,
sizeof(
float));
326 for (i=0; i<n+1; i++)
327 wn[(i*i)*nSH_n+(i*i)] = 1.0f;
331 for (i=0; i<n+1; i++)
332 scale += (
double)(2*i+1)*pow((
double)wn[(i*i)*nSH_n + (i*i)], 2.0);
333 for (i=0; i<n+1; i++)
334 W[i][n] = (
double)wn[(i*i)*nSH_n + (i*i)]/ sqrt(scale);
338 for (n=0; n<order+1; n++)
339 for (i=0; i<order+1; i++)
346 for (n=0; n<order+1; n++){
348 for (i=n, j=0; i<order+1; i++, j++)
349 H_np[band][j] = H[band][i];
350 for (i=n, j=0; i<order+1; i++, j++)
352 cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans,
HYBRID_BANDS, 1, order+1-n, 1.0,
357 pData->
bN_inv[band][n] = crmul(Hs[band][n], HW[band]);
362 diag_bN_inv_R =
calloc1d(nSH*nSH,
sizeof(float_complex));
365 diag_bN_inv_R[i*nSH+i] = cmplxf((
float)creal(pData->
bN_inv_R[band][i]), (
float)cimag(pData->
bN_inv_R[band][i]));
366 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasTrans, nSH, (arraySpecs->
Q), nSH, &calpha,
368 pinv_Y_mic_cmplx, nSH, &cbeta,
374 pData->
order = order;
381 free(pinv_Y_mic_cmplx);
389 int i, j, band, array_order, idxf_alias, nSH;
390 float f_max, kR_max, f_alias, f_f_alias;
391 double_complex* dM_diffcoh_s;
392 const double_complex calpha = cmplx(1.0, 0.0);
const double_complex cbeta = cmplx(0.0, 0.0);
403 dM_diffcoh_s =
malloc1d((arraySpecs->
Q)*(arraySpecs->
Q) *
sizeof(double_complex));
405 kR_max = 2.0f*
SAF_PI*f_max*(arraySpecs->
r)/pData->
c;
406 array_order =
SAF_MIN((
int)(ceilf(2.0f*kR_max)+0.01f), 28);
409 for(i=0; i<arraySpecs->
Q; i++){
448 if( fabsf(pData->
freqVector[band]-f_alias) < f_f_alias){
449 f_f_alias = fabsf(pData->
freqVector[band]-f_alias);
455 for(i=0; i<arraySpecs->
Q; i++)
456 for(j=0; j<arraySpecs->
Q; j++)
457 dM_diffcoh_s[i*(arraySpecs->
Q)+j] = cmplx(dM_diffcoh[i*(arraySpecs->
Q)* (
HYBRID_BANDS) + j*(
HYBRID_BANDS) + (idxf_alias)], 0.0);
459 for(j=0; j<arraySpecs->
Q; j++)
460 pData->W_tmp[i*
MAX_NUM_SENSORS+j]= cmplx((
double)crealf(pData->
W[idxf_alias][i][j]), (
double)cimagf(pData->
W[idxf_alias][i][j]));
461 cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSH, (arraySpecs->
Q), (arraySpecs->
Q), &calpha,
463 dM_diffcoh_s, (arraySpecs->
Q), &cbeta,
465 cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, nSH, nSH, (arraySpecs->
Q), &calpha,
474 for(i=0; i<arraySpecs->
Q; i++)
475 for(j=0; j<arraySpecs->
Q; j++)
478 for(j=0; j<arraySpecs->
Q; j++)
479 pData->W_tmp[i*
MAX_NUM_SENSORS+j]= cmplx((
double)crealf(pData->
W[band][i][j]), (
double)cimagf(pData->
W[band][i][j]));
480 cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSH, (arraySpecs->
Q), (arraySpecs->
Q), &calpha,
482 dM_diffcoh_s, (arraySpecs->
Q), &cbeta,
484 cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasConjTrans, nSH, nSH, (arraySpecs->
Q), &calpha,
491 cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSH, (arraySpecs->
Q), nSH, &calpha,
496 for(j=0; j<arraySpecs->
Q; j++)
512 for(n = 0; n <pData->
order+1; n++){
513 pData->
bN_inv_dB[band][n] = 20.0f * (float)log10(cabs(pData->
bN_inv[band][n]));
523 int band, i, j, simOrder, order, nSH;
527 float_complex* Y_grid, *H_array, *Wshort;
529 saf_assert(pData->
W != NULL,
"The initCodec function must have been called prior to calling array2sh_evaluateSHTfilters()");
594 order = pData->
order;
595 nSH = (order+1)*(order+1);
596 Y_grid_real =
malloc1d(nSH*812*
sizeof(
float));
598 Y_grid =
malloc1d(nSH*812*
sizeof(float_complex));
599 for(i=0; i<nSH*812; i++)
600 Y_grid[i] = cmplxf(Y_grid_real[i], 0.0f);
606 for(j=0; j<(arraySpecs->
Q); j++)
607 Wshort[band*nSH*(arraySpecs->
Q) + i*(arraySpecs->
Q) + j] = pData->
W[band][i][j];
619 *hPars = (
void*)pars;
635 _Atomic_INT32* arrayOrder,
644 case MICROPHONE_ARRAY_PRESET_DEFAULT:
651 for(ch=0; ch<Q; ch++){
658 case MICROPHONE_ARRAY_PRESET_AALTO_HYDROPHONE:
665 for(ch=0; ch<Q; ch++){
672 case MICROPHONE_ARRAY_PRESET_SENNHEISER_AMBEO:
679 for(ch=0; ch<Q; ch++){
686 case MICROPHONE_ARRAY_PRESET_CORE_SOUND_TETRAMIC:
693 for(ch=0; ch<Q; ch++){
700 case MICROPHONE_ARRAY_PRESET_ZOOM_H3VR_PRESET:
707 for(ch=0; ch<Q; ch++){
714 case MICROPHONE_ARRAY_PRESET_SOUND_FIELD_SPS200:
721 for(ch=0; ch<Q; ch++){
728 case MICROPHONE_ARRAY_PRESET_ZYLIA_1D:
735 for(ch=0; ch<Q; ch++){
742 case MICROPHONE_ARRAY_PRESET_EIGENMIKE32:
749 for(ch=0; ch<Q; ch++){
756 case MICROPHONE_ARRAY_PRESET_EIGENMIKE64:
763 for(ch=0; ch<Q; ch++){
770 case MICROPHONE_ARRAY_PRESET_DTU_MIC:
777 for(ch=0; ch<Q; ch++){
795 if(firstInitFlag==1){
797 pars->
newQ = pars->
Q;
#define MAX_SH_ORDER
Maximum supported Ambisonic order.
#define MAX_NUM_SH_SIGNALS
Maximum number of spherical harmonic components/signals supported.
void afSTFT_clearBuffers(void *const hSTFT)
Flushes time-domain buffers with zeros.
void afSTFT_create(void **const phSTFT, int nCHin, int nCHout, int hopsize, int lowDelayMode, int hybridmode, AFSTFT_FDDATA_FORMAT format)
Creates an instance of afSTFT.
void afSTFT_channelChange(void *const hSTFT, int new_nCHin, int new_nCHout)
Re-allocates memory to support a change in the number of input/output channels.
@ AFSTFT_BANDS_CH_TIME
nBands x nChannels x nTimeHops
#define HOP_SIZE
STFT hop size.
#define HYBRID_BANDS
Number of frequency bands.
ARRAY2SH_MICROPHONE_ARRAY_PRESETS
Available microphone array presets.
@ FILTER_Z_STYLE
Encoding filters based on a linear-phase filter- bank approach [3].
@ FILTER_SOFT_LIM
Encoding filters based on a 'soft-limiting' regularised inversion of the modal responses [1].
@ FILTER_Z_STYLE_MAXRE
Same as FILTER_Z_STYLE, only it also has max_rE weights baked in.
@ FILTER_TIKHONOV
Encoding filters based on a 'Tikhonov' regularised inversion of the modal responses [2].
@ WEIGHT_RIGID_OMNI
Rigid baffle construction with omni sensors.
@ WEIGHT_OPEN_OMNI
Open array construction with omni sensors.
@ WEIGHT_OPEN_DIPOLE
Open array construction with dipole sensors.
@ WEIGHT_RIGID_CARD
Rigid baffle construction with cardioid sensors.
@ WEIGHT_RIGID_DIPOLE
Rigid baffle construction with dipole sensors.
@ WEIGHT_OPEN_CARD
Open array construction with cardioid sensors.
@ ARRAY_CYLINDRICAL
Cylindrial arrangement of sensors (open/rigid)
@ ARRAY_SPHERICAL
Spherical arrangement of sensors (open/rigid)
@ EVAL_STATUS_NOT_EVALUATED
Encoder has not been evaluated.
void array2sh_evaluateSHTfilters(void *hA2sh)
Evaluates the spherical harmonic transform performance with the currently configured microphone/hydro...
void array2sh_calculate_sht_matrix(void *const hA2sh)
Computes the spherical harmonic transform (SHT) matrix, to spatially encode input microphone/hydropho...
void array2sh_initTFT(void *const hA2sh)
Initialise the filterbank used by array2sh.
void array2sh_initArray(void *const hPars, ARRAY2SH_MICROPHONE_ARRAY_PRESETS preset, _Atomic_INT32 *arrayOrder, int firstInitFlag)
Intialises an instance of a struct based on a preset, which contains the array configuration data.
void array2sh_calculate_mag_curves(void *const hA2sh)
Computes the magnitude responses of the equalisation filters; the absolute values of the regularised ...
void array2sh_apply_diff_EQ(void *const hA2sh)
Applies diffuse-field equalisation at frequencies above the spatial aliasing limit.
void array2sh_destroyArray(void **const hPars)
Destroys an instance of a struct, which contains the array configuration data.
static void array2sh_replicate_order(void *const hA2sh, int order)
Takes the bNs computed up to N+1, and replicates them to be of length (N+1)^2 (replicating the 1st or...
void array2sh_createArray(void **const hPars)
Creates an instance of a struct, which contains the array configuration data.
Spatially encodes spherical microphone array signals into spherical harmonic signals (aka: Ambisonic ...
#define MAX_NUM_SENSORS
Maximum permitted number of inputs/sensors.
#define MAX_NUM_SENSORS_IN_PRESET
Maximum permitted number of inputs/sensors.
#define MAX_EVAL_FREQ_HZ
Up to which frequency should the evaluation be accurate.
void getRSH(int N, float *dirs_deg, int nDirs, float *Y)
Computes real-valued spherical harmonics [1] for each given direction on the unit sphere.
void getMaxREweights(int order, int diagMtxFlag, float *a_n)
Computes the weights required to manipulate a hyper-cardioid beam-pattern, such that it has maximum e...
void cylModalCoeffs(int order, double *kr, int nBands, ARRAY_CONSTRUCTION_TYPES arrayType, double_complex *b_N)
Calculates the modal coefficients for open/rigid cylindrical arrays.
void evaluateSHTfilters(int order, float_complex *M_array2SH, int nSensors, int nBands, float_complex *H_array, int nDirs, float_complex *Y_grid, float *cSH, float *lSH)
Generates some objective measures, which evaluate the performance of spatial encoding filters.
void sphModalCoeffs(int order, double *kr, int nBands, ARRAY_CONSTRUCTION_TYPES arrayType, double dirCoeff, double_complex *b_N)
Calculates the modal coefficients for open/rigid spherical arrays.
float sphArrayAliasLim(float r, float c, int maxN)
Returns a simple estimate of the spatial aliasing limit (the kR = maxN rule)
void sphArrayNoiseThreshold(int maxN, int Nsensors, float r, float c, ARRAY_CONSTRUCTION_TYPES arrayType, double dirCoeff, float maxG_db, float *f_lim)
Computes the frequencies (per order), at which the noise of a SHT of a SMA exceeds a specified maximu...
void simulateCylArray(int order, double *kr, int nBands, float *sensor_dirs_rad, int N_sensors, float *src_dirs_deg, int N_srcs, ARRAY_CONSTRUCTION_TYPES arrayType, float_complex *H_array)
Simulates a cylindrical microphone array, returning the transfer functions for each (plane wave) sour...
void simulateSphArray(int order, double *kr, double *kR, int nBands, float *sensor_dirs_rad, int N_sensors, float *src_dirs_deg, int N_srcs, ARRAY_CONSTRUCTION_TYPES arrayType, double dirCoeff, float_complex *H_array)
Simulates a spherical microphone array, returning the transfer functions for each (plane wave) source...
void sphDiffCohMtxTheory(int order, float *sensor_dirs_rad, int N_sensors, ARRAY_CONSTRUCTION_TYPES arrayType, double dirCoeff, double *kr, int nBands, double *M_diffcoh)
Calculates the theoretical diffuse coherence matrix for a spherical array.
void sphScattererModalCoeffs(int order, double *kr, double *kR, int nBands, double_complex *b_N)
Calculates the modal coefficients for a rigid spherical scatterer with omni-directional sensors.
void sphScattererDirModalCoeffs(int order, double *kr, double *kR, int nBands, double dirCoeff, double_complex *b_N)
Calculates the modal coefficients for a rigid spherical scatterer with directional sensors.
@ ARRAY_CONSTRUCTION_RIGID_DIRECTIONAL
Rigid baffle, directional sensors.
@ ARRAY_CONSTRUCTION_RIGID
Rigid baffle, omni-directional sensors.
@ ARRAY_CONSTRUCTION_OPEN_DIRECTIONAL
Open array, directional sensors.
@ ARRAY_CONSTRUCTION_OPEN
Open array, omni-directional sensors.
#define saf_print_error(message)
Macro to print a error message along with the filename and line number.
const float __Aalto_Hydrophone_coords_rad[4][2]
Sensor array coordinates for the custom hydrophone array made at Aalto University [1].
#define saf_assert(x, message)
Macro to make an assertion, along with a string explaining its purpose.
#define SAF_PI
pi constant (single precision)
const float __Eigenmike64_coords_rad[64][2]
Sensor array coordinates for the Eigenmike64.
const float __Sennheiser_Ambeo_coords_rad[4][2]
Sensor array coordinates for the Sennheiser Ambeo.
const float __Eigenmike32_coords_rad[32][2]
Sensor array coordinates for the Eigenmike32.
#define SAF_MAX(a, b)
Returns the maximum of the two values.
const float __default_SENSORcoords128_deg[128][2]
Default sensor array coordinates.
#define SAF_PId
pi constant (double precision)
const float __geosphere_ico_9_0_dirs_deg[812][2]
Directions [azimuth, Elevation] in degrees, for ico geosphere, degree: 9.
void utility_spinv(void *const hWork, const float *inM, const int dim1, const int dim2, float *outM)
General matrix pseudo-inverse (the svd way): single precision, i.e.
const float __Sound_field_SPS200_coords_rad[4][2]
Sensor array coordinates for the Sound-field SPS200.
#define SAF_MIN(a, b)
Returns the minimum of the two values.
const float __Zylia1D_coords_rad[19][2]
Sensor array coordinates for the Zylia mic.
const float __Zoom_H3VR_coords_rad[4][2]
Sensor array coordinates for the Zoom H3VR.
const float __Core_Sound_TetraMic_coords_rad[4][2]
Sensor array coordinates for the Core Sound TetraMic.
const float __DTU_mic_coords_rad[52][2]
Sensor array coordinates for the custom 52-sensor array built at the Technical University of Denmark ...
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
void * calloc1d(size_t dim1, size_t data_size)
1-D calloc (same as calloc, but with error checking)
Contains variables for describing the microphone/hydrophone array.
_Atomic_FLOAT32 r
radius of sensors
_Atomic_ARRAY2SH_WEIGHT_TYPES weightType
see ARRAY2SH_WEIGHT_TYPES
_Atomic_ARRAY2SH_ARRAY_TYPES arrayType
see ARRAY2SH_ARRAY_TYPES
_Atomic_FLOAT32 R
radius of scatterer (only for rigid arrays)
_Atomic_INT32 Q
Current number of sensors.
_Atomic_INT32 newQ
New number of sensors (current value replaced by this after next re-init)
_Atomic_FLOAT32 sensorCoords_deg[MAX_NUM_SENSORS][2]
Sensor directions in degrees.
_Atomic_FLOAT32 sensorCoords_rad[MAX_NUM_SENSORS][2]
Sensor directions in radians.
Main structure for array2sh.
_Atomic_FLOAT32 progressBar0_1
Current (re)initialisation progress, between [0..1].
_Atomic_FLOAT32 regPar
regularisation upper gain limit, dB;
float freqVector[HYBRID_BANDS]
frequency vector
double_complex * bN
Temp vector for the modal coefficients.
char * progressBarText
Current (re)initialisation step, string.
double_complex bN_inv[HYBRID_BANDS][MAX_SH_ORDER+1]
1/bN_modal
_Atomic_INT32 reinitSHTmatrixFLAG
0: do not reinit; 1: reinit;
void * hSTFT
filterbank handle
float ** bN_modal_dB
modal responses / no regulaisation; HYBRID_BANDS x (MAX_SH_ORDER +1)
void * arraySpecs
array configuration
_Atomic_INT32 enableDiffEQpastAliasing
0: disabled, 1: enabled
double_complex bN_modal[HYBRID_BANDS][MAX_SH_ORDER+1]
Current modal coeffients.
double_complex bN_inv_R[HYBRID_BANDS][MAX_NUM_SH_SIGNALS]
1/bN_modal with regularisation
float * cSH
spatial correlation; HYBRID_BANDS x 1
_Atomic_INT32 new_order
new encoding order (current value will be replaced by this after next re-init)
_Atomic_FLOAT32 c
speed of sound, m/s
_Atomic_ARRAY2SH_FILTER_TYPES filterType
encoding filter approach
_Atomic_ARRAY2SH_EVAL_STATUS evalStatus
see ARRAY2SH_EVAL_STATUS
float ** bN_inv_dB
modal responses / with regularisation; HYBRID_BANDS x (MAX_SH_ORDER +1)
float * lSH
level difference; HYBRID_BANDS x 1
_Atomic_INT32 order
current encoding order
float_complex W[HYBRID_BANDS][MAX_NUM_SH_SIGNALS][MAX_NUM_SENSORS]
Encoding weights.