/*---------------------------------------------------------------------------- * norm_corr - Find the normalized correlation between the target vector and * the filtered past excitation. *---------------------------------------------------------------------------- */ static void norm_corr( FLOAT exc[], /* input : excitation buffer */ FLOAT xn[], /* input : target vector */ FLOAT h[], /* input : imp response of synth and weighting flt */ int l_subfr, /* input : Length of frame to compute pitch */ int t_min, /* input : minimum value of searched range */ int t_max, /* input : maximum value of search range */ FLOAT corr_norm[] /* output: normalized correlation (correlation between target and filtered excitation divided by the square root of energy of filtered excitation) */ ) { int i, j, k; FLOAT excf[L_SUBFR]; /* filtered past excitation */ FLOAT alp, s, norm; k = -t_min; /* compute the filtered excitation for the first delay t_min */ convolve(&exc[k], h, excf, l_subfr); /* loop for every possible period */ for (i = t_min; i <= t_max; i++) { /* Compute 1/sqrt(energie of excf[]) */ alp = (F)0.01; for (j = 0; j < l_subfr; j++) alp += excf[j]*excf[j]; norm = inv_sqrt(alp); /* Compute correlation between xn[] and excf[] */ s = (F)0.0; for (j = 0; j < l_subfr; j++) s += xn[j]*excf[j]; /* Normalize correlation = correlation * (1/sqrt(energie)) */ corr_norm[i] = s*norm; /* modify the filtered excitation excf[] for the next iteration */ if (i != t_max) { k--; for (j = l_subfr-1; j > 0; j--) excf[j] = excf[j-1] + exc[k]*h[j]; excf[0] = exc[k]; } } return; }
static void ahrs_normalize_3(real_t *v0, real_t *v1, real_t *v2) { real_t recip_norm = inv_sqrt(*v0 * *v0 + *v1 * *v1 + *v2 * *v2); *v0 *= recip_norm; *v1 *= recip_norm; *v2 *= recip_norm; }
// Quaternion Normalization operator. Expects its 4-element arrays in wxyz order void quat_norm(float a[4]) { float n = a[1]*a[1] + a[2]*a[2] + a[3]*a[3] + a[0]*a[0]; if (n == 1.0f) return ; n = inv_sqrt(n); a[1]*=n; a[2]*=n; a[3]*=n; a[0]*=n; return; }
/*---------------------------------------------------------------------------- * lag_max - Find the lag that has maximum correlation *---------------------------------------------------------------------------- */ static int lag_max( /* output: lag found */ FLOAT signal[], /* input : Signal to compute the open loop pitch signal[-142:-1] should be known. */ int l_frame, /* input : Length of frame to compute pitch */ int lagmax, /* input : maximum lag */ int lagmin, /* input : minimum lag */ FLOAT *cor_max /* input : normalized correlation of selected lag */ ) { int i, j; FLOAT *p, *p1; FLOAT max, t0; int p_max; max = FLT_MIN_G729; for (i = lagmax; i >= lagmin; i--) { p = signal; p1 = &signal[-i]; t0 = (F)0.0; for (j=0; j<l_frame; j++) { t0 += *p++ * *p1++; } if (t0 >= max) { max = t0; p_max = i; } } /* compute energy */ t0 = (F)0.01; /* to avoid division by zero */ p = &signal[-p_max]; for(i=0; i<l_frame; i++, p++) { t0 += *p * *p; } t0 = inv_sqrt(t0); /* 1/sqrt(energy) */ *cor_max = max * t0; /* max/sqrt(energy) */ return(p_max); }
/*============================================================================= Function Name : cal_relative_target_atom_position Description : This calculates the direction in which the target nucleus is found. v is the projectile velocity vector, the IP vector is returned in p components. Inputs : float vx,float vy, float vz unsigned int azim_angle Outputs : float *px, float *py, float *pz Notes : This routine works similar to the rotation (DIRCOS) routine. It simply assumes a fixed scattering angle of 90 degrees and reverses the resulting vector. Adding the result multiplied with impact_par to the current projectile position leads to the target nucleus position. Function call: fromcorteo - float my_inv_sqrt (float val); float sqrtdf (double val). =============================================================================*/ void cal_relative_target_atom_position (double vx, double vy, double vz, double *px, double *py, double *pz, unsigned int iazim_angle) { float k, kinv; float k2 = 1.0f - vz * vz; /* random azimutal rotation angle components */ float cosomega = cos_azim_angle[iazim_angle]; float sinomega = sin_azim_angle[iazim_angle]; /* In the rotation routine, we would have to increase the azim-counter here, but since we want to have the same angle for target position and deflection, we must not change the index in this function! */ if (k2 < 0.000001) { /* extremely rare case */ *pz = 0; *py = cosomega; *px = sinomega; return; } /* usual case */ #ifndef SAFE_SQR_ROTATION kinv = inv_sqrt (k2); /* 1/sqrt() (approximate) */ k = k2 * kinv; /* so we get k and 1/k by a table lookup and a multiplication */ #else /* these two lines can be replaced by the following two lines but... */ k = sqrtdf (k2); /* ... using a sqrt() here makes the program 25% slower! */ kinv = 1.0f / k; #endif *px = -kinv * (vx * vz * cosomega + vy * sinomega); *py = -kinv * (vy * vz * cosomega - vx * sinomega); *pz = k * cosomega; #ifdef SAFE_ROTATION /* makes slower, but safer */ if (*px > 1) *px = 1; if (*px < -1) *px = -1; if (*py > 1) *py = 1; if (*py < -1) *py = -1; if (*pz > 1) *pz = 1; if (*pz < -1) *pz = -1; #endif return; }
void spatial_ahrs_update_imu(SpatialInfo *spatial_info, float gx, float gy, float gz, float ax, float ay, float az) { // Just a shorthand meant to make this a bit easier to work with, and transact // commits (eventually) float q0 = spatial_info->orientation_q[0]; float q1 = spatial_info->orientation_q[1]; float q2 = spatial_info->orientation_q[2]; float q3 = spatial_info->orientation_q[3]; float sample_rate_in_hz = 1000.0f / spatial_info->data_rate; float recipNorm; float s0, s1, s2, s3; float qDot1, qDot2, qDot3, qDot4; float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3; // Rate of change of quaternion from gyroscope qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz); qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy); qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx); qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx); // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { // Normalise accelerometer measurement recipNorm = inv_sqrt(ax * ax + ay * ay + az * az); ax *= recipNorm; ay *= recipNorm; az *= recipNorm; // Auxiliary variables to avoid repeated arithmetic _2q0 = 2.0f * q0; _2q1 = 2.0f * q1; _2q2 = 2.0f * q2; _2q3 = 2.0f * q3; _4q0 = 4.0f * q0; _4q1 = 4.0f * q1; _4q2 = 4.0f * q2; _8q1 = 8.0f * q1; _8q2 = 8.0f * q2; q0q0 = q0 * q0; q1q1 = q1 * q1; q2q2 = q2 * q2; q3q3 = q3 * q3; // Gradient decent algorithm corrective step s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay; s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * q1 - _2q0 * ay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az; s2 = 4.0f * q0q0 * q2 + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az; s3 = 4.0f * q1q1 * q3 - _2q1 * ax + 4.0f * q2q2 * q3 - _2q2 * ay; recipNorm = inv_sqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude s0 *= recipNorm; s1 *= recipNorm; s2 *= recipNorm; s3 *= recipNorm; // Apply feedback step qDot1 -= SPATIAL_AHRS_BETA * s0; qDot2 -= SPATIAL_AHRS_BETA * s1; qDot3 -= SPATIAL_AHRS_BETA * s2; qDot4 -= SPATIAL_AHRS_BETA * s3; } // Integrate rate of change of quaternion to yield quaternion q0 += qDot1 * (1.0f / sample_rate_in_hz); q1 += qDot2 * (1.0f / sample_rate_in_hz); q2 += qDot3 * (1.0f / sample_rate_in_hz); q3 += qDot4 * (1.0f / sample_rate_in_hz); // Normalise quaternion recipNorm = inv_sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); q0 *= recipNorm; q1 *= recipNorm; q2 *= recipNorm; q3 *= recipNorm; spatial_info->orientation_q[0] = q0; spatial_info->orientation_q[1] = q1; spatial_info->orientation_q[2] = q2; spatial_info->orientation_q[3] = q3; }
void spatial_ahrs_update(SpatialInfo *spatial_info, float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) { // Just a shorthand meant to make this a bit easier to work with, and transact // commits (eventually) float q0 = spatial_info->orientation_q[0]; float q1 = spatial_info->orientation_q[1]; float q2 = spatial_info->orientation_q[2]; float q3 = spatial_info->orientation_q[3]; float sample_rate_in_hz = 1000.0f / spatial_info->data_rate; float recipNorm; float s0, s1, s2, s3; float qDot1, qDot2, qDot3, qDot4; float hx, hy; float _2q0mx, _2q0my, _2q0mz, _2q1mx, _2bx, _2bz, _4bx, _4bz, _2q0, _2q1, _2q2, _2q3, _2q0q2, _2q2q3, q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3; // Rate of change of quaternion from gyroscope qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz); qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy); qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx); qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx); // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { // Normalise accelerometer measurement recipNorm = inv_sqrt(ax * ax + ay * ay + az * az); ax *= recipNorm; ay *= recipNorm; az *= recipNorm; // Normalise magnetometer measurement recipNorm = inv_sqrt(mx * mx + my * my + mz * mz); mx *= recipNorm; my *= recipNorm; mz *= recipNorm; // Auxiliary variables to avoid repeated arithmetic _2q0mx = 2.0f * q0 * mx; _2q0my = 2.0f * q0 * my; _2q0mz = 2.0f * q0 * mz; _2q1mx = 2.0f * q1 * mx; _2q0 = 2.0f * q0; _2q1 = 2.0f * q1; _2q2 = 2.0f * q2; _2q3 = 2.0f * q3; _2q0q2 = 2.0f * q0 * q2; _2q2q3 = 2.0f * q2 * q3; q0q0 = q0 * q0; q0q1 = q0 * q1; q0q2 = q0 * q2; q0q3 = q0 * q3; q1q1 = q1 * q1; q1q2 = q1 * q2; q1q3 = q1 * q3; q2q2 = q2 * q2; q2q3 = q2 * q3; q3q3 = q3 * q3; // Reference direction of Earth's magnetic field hx = mx * q0q0 - _2q0my * q3 + _2q0mz * q2 + mx * q1q1 + _2q1 * my * q2 + _2q1 * mz * q3 - mx * q2q2 - mx * q3q3; hy = _2q0mx * q3 + my * q0q0 - _2q0mz * q1 + _2q1mx * q2 - my * q1q1 + my * q2q2 + _2q2 * mz * q3 - my * q3q3; _2bx = sqrt(hx * hx + hy * hy); _2bz = -_2q0mx * q2 + _2q0my * q1 + mz * q0q0 + _2q1mx * q3 - mz * q1q1 + _2q2 * my * q3 - mz * q2q2 + mz * q3q3; _4bx = 2.0f * _2bx; _4bz = 2.0f * _2bz; // Gradient decent algorithm corrective step s0 = -_2q2 * (2.0f * q1q3 - _2q0q2 - ax) + _2q1 * (2.0f * q0q1 + _2q2q3 - ay) - _2bz * q2 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q3 + _2bz * q1) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q2 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); s1 = _2q3 * (2.0f * q1q3 - _2q0q2 - ax) + _2q0 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q1 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + _2bz * q3 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q2 + _2bz * q0) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q3 - _4bz * q1) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); s2 = -_2q0 * (2.0f * q1q3 - _2q0q2 - ax) + _2q3 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q2 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + (-_4bx * q2 - _2bz * q0) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q1 + _2bz * q3) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q0 - _4bz * q2) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); s3 = _2q1 * (2.0f * q1q3 - _2q0q2 - ax) + _2q2 * (2.0f * q0q1 + _2q2q3 - ay) + (-_4bx * q3 + _2bz * q1) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q0 + _2bz * q2) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q1 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); recipNorm = inv_sqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude s0 *= recipNorm; s1 *= recipNorm; s2 *= recipNorm; s3 *= recipNorm; // Apply feedback step qDot1 -= SPATIAL_AHRS_BETA * s0; qDot2 -= SPATIAL_AHRS_BETA * s1; qDot3 -= SPATIAL_AHRS_BETA * s2; qDot4 -= SPATIAL_AHRS_BETA * s3; } // Integrate rate of change of quaternion to yield quaternion q0 += qDot1 * (1.0f / sample_rate_in_hz); q1 += qDot2 * (1.0f / sample_rate_in_hz); q2 += qDot3 * (1.0f / sample_rate_in_hz); q3 += qDot4 * (1.0f / sample_rate_in_hz); // Normalise quaternion recipNorm = inv_sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); q0 *= recipNorm; q1 *= recipNorm; q2 *= recipNorm; q3 *= recipNorm; spatial_info->orientation_q[0] = q0; spatial_info->orientation_q[1] = q1; spatial_info->orientation_q[2] = q2; spatial_info->orientation_q[3] = q3; }