forked from Archive/PX4-Autopilot
Merge pull request #321 from dagar/pr-ekf_formatting
EKF trivial code style cleanup
This commit is contained in:
commit
fac292fef9
|
@ -150,8 +150,7 @@ void Ekf::fuseAirspeed()
|
||||||
if (_tas_test_ratio > 1.0f) {
|
if (_tas_test_ratio > 1.0f) {
|
||||||
_innov_check_fail_status.flags.reject_airspeed = true;
|
_innov_check_fail_status.flags.reject_airspeed = true;
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
_innov_check_fail_status.flags.reject_airspeed = false;
|
_innov_check_fail_status.flags.reject_airspeed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -968,11 +968,13 @@ void Ekf::checkForStuckRange()
|
||||||
_rng_stuck = false;
|
_rng_stuck = false;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (_range_sample_delayed.rng > _rng_check_max_val)
|
if (_range_sample_delayed.rng > _rng_check_max_val) {
|
||||||
_rng_check_max_val = _range_sample_delayed.rng;
|
_rng_check_max_val = _range_sample_delayed.rng;
|
||||||
|
}
|
||||||
|
|
||||||
if (_rng_check_min_val < 0.1f || _range_sample_delayed.rng < _rng_check_min_val)
|
if (_rng_check_min_val < 0.1f || _range_sample_delayed.rng < _rng_check_min_val) {
|
||||||
_rng_check_min_val = _range_sample_delayed.rng;
|
_rng_check_min_val = _range_sample_delayed.rng;
|
||||||
|
}
|
||||||
|
|
||||||
_range_data_ready = false;
|
_range_data_ready = false;
|
||||||
}
|
}
|
||||||
|
@ -989,6 +991,7 @@ void Ekf::controlAirDataFusion()
|
||||||
// If both airspeed and sideslip fusion have timed out and we are not using a drag observation model then we no longer have valid wind estimates
|
// If both airspeed and sideslip fusion have timed out and we are not using a drag observation model then we no longer have valid wind estimates
|
||||||
bool airspeed_timed_out = _time_last_imu - _time_last_arsp_fuse > 10e6;
|
bool airspeed_timed_out = _time_last_imu - _time_last_arsp_fuse > 10e6;
|
||||||
bool sideslip_timed_out = _time_last_imu - _time_last_beta_fuse > 10e6;
|
bool sideslip_timed_out = _time_last_imu - _time_last_beta_fuse > 10e6;
|
||||||
|
|
||||||
if (_control_status.flags.wind && airspeed_timed_out && sideslip_timed_out && !(_params.fusion_mode & MASK_USE_DRAG)) {
|
if (_control_status.flags.wind && airspeed_timed_out && sideslip_timed_out && !(_params.fusion_mode & MASK_USE_DRAG)) {
|
||||||
_control_status.flags.wind = false;
|
_control_status.flags.wind = false;
|
||||||
|
|
||||||
|
@ -1049,9 +1052,6 @@ void Ekf::controlBetaFusion()
|
||||||
|
|
||||||
fuseSideslip();
|
fuseSideslip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ekf::controlDragFusion()
|
void Ekf::controlDragFusion()
|
||||||
|
|
|
@ -733,9 +733,11 @@ void Ekf::fixCovarianceErrors()
|
||||||
const float minSafeStateVar = 1e-9f;
|
const float minSafeStateVar = 1e-9f;
|
||||||
float maxStateVar = minSafeStateVar;
|
float maxStateVar = minSafeStateVar;
|
||||||
bool resetRequired = false;
|
bool resetRequired = false;
|
||||||
|
|
||||||
for (uint8_t stateIndex = 13; stateIndex <= 15; stateIndex++) {
|
for (uint8_t stateIndex = 13; stateIndex <= 15; stateIndex++) {
|
||||||
if (P[stateIndex][stateIndex] > maxStateVar) {
|
if (P[stateIndex][stateIndex] > maxStateVar) {
|
||||||
maxStateVar = P[stateIndex][stateIndex];
|
maxStateVar = P[stateIndex][stateIndex];
|
||||||
|
|
||||||
} else if (P[stateIndex][stateIndex] < minSafeStateVar) {
|
} else if (P[stateIndex][stateIndex] < minSafeStateVar) {
|
||||||
resetRequired = true;
|
resetRequired = true;
|
||||||
}
|
}
|
||||||
|
@ -746,19 +748,24 @@ void Ekf::fixCovarianceErrors()
|
||||||
// Also limit variance to a maximum equivalent to a 1g uncertainty
|
// Also limit variance to a maximum equivalent to a 1g uncertainty
|
||||||
const float minStateVarTarget = 1E-8f;
|
const float minStateVarTarget = 1E-8f;
|
||||||
float minAllowedStateVar = fmaxf(0.01f * maxStateVar, minStateVarTarget);
|
float minAllowedStateVar = fmaxf(0.01f * maxStateVar, minStateVarTarget);
|
||||||
|
|
||||||
for (uint8_t stateIndex = 13; stateIndex <= 15; stateIndex++) {
|
for (uint8_t stateIndex = 13; stateIndex <= 15; stateIndex++) {
|
||||||
P[stateIndex][stateIndex] = math::constrain(P[stateIndex][stateIndex], minAllowedStateVar, sq(_gravity_mss * _dt_ekf_avg));
|
P[stateIndex][stateIndex] = math::constrain(P[stateIndex][stateIndex], minAllowedStateVar,
|
||||||
|
sq(_gravity_mss * _dt_ekf_avg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any one axis has fallen below the safe minimum, all delta velocity covariance terms must be reset to zero
|
// If any one axis has fallen below the safe minimum, all delta velocity covariance terms must be reset to zero
|
||||||
if (resetRequired) {
|
if (resetRequired) {
|
||||||
float delVelBiasVar[3];
|
float delVelBiasVar[3];
|
||||||
|
|
||||||
// store all delta velocity bias variances
|
// store all delta velocity bias variances
|
||||||
for (uint8_t stateIndex = 13; stateIndex <= 15; stateIndex++) {
|
for (uint8_t stateIndex = 13; stateIndex <= 15; stateIndex++) {
|
||||||
delVelBiasVar[stateIndex - 13] = P[stateIndex][stateIndex];
|
delVelBiasVar[stateIndex - 13] = P[stateIndex][stateIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset all delta velocity bias covariances
|
// reset all delta velocity bias covariances
|
||||||
zeroCols(P, 13, 15);
|
zeroCols(P, 13, 15);
|
||||||
|
|
||||||
// restore all delta velocity bias variances
|
// restore all delta velocity bias variances
|
||||||
for (uint8_t stateIndex = 13; stateIndex <= 15; stateIndex++) {
|
for (uint8_t stateIndex = 13; stateIndex <= 15; stateIndex++) {
|
||||||
P[stateIndex][stateIndex] = delVelBiasVar[stateIndex - 13];
|
P[stateIndex][stateIndex] = delVelBiasVar[stateIndex - 13];
|
||||||
|
@ -769,6 +776,7 @@ void Ekf::fixCovarianceErrors()
|
||||||
// calculate accel bias term aligned with the gravity vector
|
// calculate accel bias term aligned with the gravity vector
|
||||||
float dVel_bias_lim = 0.9f * _params.acc_bias_lim * _dt_ekf_avg;
|
float dVel_bias_lim = 0.9f * _params.acc_bias_lim * _dt_ekf_avg;
|
||||||
float down_dvel_bias = 0.0f;
|
float down_dvel_bias = 0.0f;
|
||||||
|
|
||||||
for (uint8_t axis_index = 0; axis_index < 3; axis_index++) {
|
for (uint8_t axis_index = 0; axis_index < 3; axis_index++) {
|
||||||
down_dvel_bias += _state.accel_bias(axis_index) * _R_to_earth(2, axis_index);
|
down_dvel_bias += _state.accel_bias(axis_index) * _R_to_earth(2, axis_index);
|
||||||
}
|
}
|
||||||
|
@ -893,5 +901,4 @@ void Ekf::resetWindCovariance()
|
||||||
P[23][23] = sq(1.0f);
|
P[23][23] = sq(1.0f);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,9 +150,11 @@ void Ekf::fuseDrag()
|
||||||
float drag_sign;
|
float drag_sign;
|
||||||
if (rel_wind(axis_index) >= 0.0f) {
|
if (rel_wind(axis_index) >= 0.0f) {
|
||||||
drag_sign = 1.0f;
|
drag_sign = 1.0f;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
drag_sign = -1.0f;
|
drag_sign = -1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float predAccel = -BC_inv_x * 0.5f * rho * sq(rel_wind(axis_index)) * drag_sign;
|
float predAccel = -BC_inv_x * 0.5f * rho * sq(rel_wind(axis_index)) * drag_sign;
|
||||||
_drag_innov[axis_index] = predAccel - mea_acc;
|
_drag_innov[axis_index] = predAccel - mea_acc;
|
||||||
_drag_test_ratio[axis_index] = sq(_drag_innov[axis_index]) / (25.0f * _drag_innov_var[axis_index]);
|
_drag_test_ratio[axis_index] = sq(_drag_innov[axis_index]) / (25.0f * _drag_innov_var[axis_index]);
|
||||||
|
@ -222,9 +224,11 @@ void Ekf::fuseDrag()
|
||||||
float drag_sign;
|
float drag_sign;
|
||||||
if (rel_wind(axis_index) >= 0.0f) {
|
if (rel_wind(axis_index) >= 0.0f) {
|
||||||
drag_sign = 1.0f;
|
drag_sign = 1.0f;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
drag_sign = -1.0f;
|
drag_sign = -1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float predAccel = -BC_inv_y * 0.5f * rho * sq(rel_wind(axis_index)) * drag_sign;
|
float predAccel = -BC_inv_y * 0.5f * rho * sq(rel_wind(axis_index)) * drag_sign;
|
||||||
_drag_innov[axis_index] = predAccel - mea_acc;
|
_drag_innov[axis_index] = predAccel - mea_acc;
|
||||||
_drag_test_ratio[axis_index] = sq(_drag_innov[axis_index]) / (25.0f * _drag_innov_var[axis_index]);
|
_drag_test_ratio[axis_index] = sq(_drag_innov[axis_index]) / (25.0f * _drag_innov_var[axis_index]);
|
||||||
|
|
16
EKF/ekf.cpp
16
EKF/ekf.cpp
|
@ -43,21 +43,6 @@
|
||||||
#include "ekf.h"
|
#include "ekf.h"
|
||||||
#include "mathlib.h"
|
#include "mathlib.h"
|
||||||
|
|
||||||
#ifndef __PX4_QURT
|
|
||||||
#if defined(__cplusplus) && !defined(__PX4_NUTTX)
|
|
||||||
#include <cmath>
|
|
||||||
#define ISFINITE(x) std::isfinite(x)
|
|
||||||
#else
|
|
||||||
#define ISFINITE(x) isfinite(x)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__PX4_QURT)
|
|
||||||
// Missing math.h defines
|
|
||||||
#define ISFINITE(x) __builtin_isfinite(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
bool Ekf::init(uint64_t timestamp)
|
bool Ekf::init(uint64_t timestamp)
|
||||||
{
|
{
|
||||||
bool ret = initialise_interface(timestamp);
|
bool ret = initialise_interface(timestamp);
|
||||||
|
@ -617,6 +602,7 @@ void Ekf::calculateOutputStates()
|
||||||
unsigned index = _output_vert_buffer.get_oldest_index();
|
unsigned index = _output_vert_buffer.get_oldest_index();
|
||||||
unsigned index_next;
|
unsigned index_next;
|
||||||
unsigned size = _output_vert_buffer.get_length();
|
unsigned size = _output_vert_buffer.get_length();
|
||||||
|
|
||||||
for (unsigned counter = 0; counter < (size - 1); counter++) {
|
for (unsigned counter = 0; counter < (size - 1); counter++) {
|
||||||
index_next = (index + 1) % size;
|
index_next = (index + 1) % size;
|
||||||
current_state = _output_vert_buffer.get_from_index(index);
|
current_state = _output_vert_buffer.get_from_index(index);
|
||||||
|
|
14
EKF/geo.cpp
14
EKF/geo.cpp
|
@ -42,23 +42,15 @@
|
||||||
* @author Anton Babushkin <anton.babushkin@me.com>
|
* @author Anton Babushkin <anton.babushkin@me.com>
|
||||||
*/
|
*/
|
||||||
#ifdef POSIX_SHARED
|
#ifdef POSIX_SHARED
|
||||||
//#include <unistd.h>
|
|
||||||
//#include <pthread.h>
|
#include "ecl.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#ifndef __PX4_QURT
|
|
||||||
#if defined(__cplusplus) && !defined(__PX4_NUTTX)
|
|
||||||
#include <cmath>
|
|
||||||
#define ISFINITE(x) std::isfinite(x)
|
|
||||||
#else
|
|
||||||
#define ISFINITE(x) isfinite(x)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014 MAV GEO Library (MAVGEO). All rights reserved.
|
* Copyright (c) 2014 MAV GEO Library (MAVGEO). All rights reserved.
|
||||||
|
|
|
@ -84,9 +84,11 @@ void Ekf::fuseSideslip()
|
||||||
|
|
||||||
// intermediate variable from algebraic optimisation
|
// intermediate variable from algebraic optimisation
|
||||||
SH_BETA[0] = (vn - vwn)*(sq(q0) + sq(q1) - sq(q2) - sq(q3)) - vd*(2.0f*q0*q2 - 2.0f*q1*q3) + (ve - vwe)*(2.0f*q0*q3 + 2.0f*q1*q2);
|
SH_BETA[0] = (vn - vwn)*(sq(q0) + sq(q1) - sq(q2) - sq(q3)) - vd*(2.0f*q0*q2 - 2.0f*q1*q3) + (ve - vwe)*(2.0f*q0*q3 + 2.0f*q1*q2);
|
||||||
|
|
||||||
if (fabsf(SH_BETA[0]) <= 1e-9f) {
|
if (fabsf(SH_BETA[0]) <= 1e-9f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SH_BETA[1] = (ve - vwe)*(sq(q0) - sq(q1) + sq(q2) - sq(q3)) + vd*(2.0f*q0*q1 + 2.0f*q2*q3) - (vn - vwn)*(2.0f*q0*q3 - 2.0f*q1*q2);
|
SH_BETA[1] = (ve - vwe)*(sq(q0) - sq(q1) + sq(q2) - sq(q3)) + vd*(2.0f*q0*q1 + 2.0f*q2*q3) - (vn - vwn)*(2.0f*q0*q3 - 2.0f*q1*q2);
|
||||||
SH_BETA[2] = vn - vwn;
|
SH_BETA[2] = vn - vwn;
|
||||||
SH_BETA[3] = ve - vwe;
|
SH_BETA[3] = ve - vwe;
|
||||||
|
@ -122,8 +124,10 @@ void Ekf::fuseSideslip()
|
||||||
if (_beta_innov_var >= R_BETA) {
|
if (_beta_innov_var >= R_BETA) {
|
||||||
SK_BETA[0] = 1.0f / _beta_innov_var;
|
SK_BETA[0] = 1.0f / _beta_innov_var;
|
||||||
_fault_status.flags.bad_sideslip = false;
|
_fault_status.flags.bad_sideslip = false;
|
||||||
|
|
||||||
} else { // Reset the estimator
|
} else { // Reset the estimator
|
||||||
_fault_status.flags.bad_sideslip = true;
|
_fault_status.flags.bad_sideslip = true;
|
||||||
|
|
||||||
// if we are getting aiding from other sources, warn and reset the wind states and covariances only
|
// if we are getting aiding from other sources, warn and reset the wind states and covariances only
|
||||||
if (update_wind_only) {
|
if (update_wind_only) {
|
||||||
resetWindStates();
|
resetWindStates();
|
||||||
|
@ -134,10 +138,11 @@ void Ekf::fuseSideslip()
|
||||||
initialiseCovariance();
|
initialiseCovariance();
|
||||||
_state.wind_vel.setZero();
|
_state.wind_vel.setZero();
|
||||||
ECL_ERR("EKF synthetic sideslip fusion badly conditioned - full covariance reset");
|
ECL_ERR("EKF synthetic sideslip fusion badly conditioned - full covariance reset");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SK_BETA[1] = SH_BETA[5]*(SH_BETA[12] - 2.0f*q1*q2) + SH_BETA[1]*SH_BETA[4]*SH_BETA[7];
|
SK_BETA[1] = SH_BETA[5]*(SH_BETA[12] - 2.0f*q1*q2) + SH_BETA[1]*SH_BETA[4]*SH_BETA[7];
|
||||||
SK_BETA[2] = SH_BETA[6] - SH_BETA[1]*SH_BETA[4]*(SH_BETA[12] + 2.0f*q1*q2);
|
SK_BETA[2] = SH_BETA[6] - SH_BETA[1]*SH_BETA[4]*(SH_BETA[12] + 2.0f*q1*q2);
|
||||||
SK_BETA[3] = SH_BETA[5]*(2.0f*q0*q1 + 2.0f*q2*q3) + SH_BETA[1]*SH_BETA[4]*(2.0f*q0*q2 - 2.0f*q1*q3);
|
SK_BETA[3] = SH_BETA[5]*(2.0f*q0*q1 + 2.0f*q2*q3) + SH_BETA[1]*SH_BETA[4]*(2.0f*q0*q2 - 2.0f*q1*q3);
|
||||||
|
@ -188,6 +193,7 @@ void Ekf::fuseSideslip()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Kfusion[22] = SK_BETA[0]*(P[22][0]*SK_BETA[5] + P[22][1]*SK_BETA[4] - P[22][4]*SK_BETA[1] + P[22][5]*SK_BETA[2] + P[22][2]*SK_BETA[6] + P[22][6]*SK_BETA[3] - P[22][3]*SK_BETA[7] + P[22][22]*SK_BETA[1] - P[22][23]*SK_BETA[2]);
|
Kfusion[22] = SK_BETA[0]*(P[22][0]*SK_BETA[5] + P[22][1]*SK_BETA[4] - P[22][4]*SK_BETA[1] + P[22][5]*SK_BETA[2] + P[22][2]*SK_BETA[6] + P[22][6]*SK_BETA[3] - P[22][3]*SK_BETA[7] + P[22][22]*SK_BETA[1] - P[22][23]*SK_BETA[2]);
|
||||||
Kfusion[23] = SK_BETA[0]*(P[23][0]*SK_BETA[5] + P[23][1]*SK_BETA[4] - P[23][4]*SK_BETA[1] + P[23][5]*SK_BETA[2] + P[23][2]*SK_BETA[6] + P[23][6]*SK_BETA[3] - P[23][3]*SK_BETA[7] + P[23][22]*SK_BETA[1] - P[23][23]*SK_BETA[2]);
|
Kfusion[23] = SK_BETA[0]*(P[23][0]*SK_BETA[5] + P[23][1]*SK_BETA[4] - P[23][4]*SK_BETA[1] + P[23][5]*SK_BETA[2] + P[23][2]*SK_BETA[6] + P[23][6]*SK_BETA[3] - P[23][3]*SK_BETA[7] + P[23][22]*SK_BETA[1] - P[23][23]*SK_BETA[2]);
|
||||||
|
|
||||||
|
@ -204,7 +210,6 @@ void Ekf::fuseSideslip()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_innov_check_fail_status.flags.reject_sideslip = false;
|
_innov_check_fail_status.flags.reject_sideslip = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// synthetic sideslip measurement sample has passed check so record it
|
// synthetic sideslip measurement sample has passed check so record it
|
||||||
|
@ -215,8 +220,8 @@ void Ekf::fuseSideslip()
|
||||||
// then calculate P - KHP
|
// then calculate P - KHP
|
||||||
float KHP[_k_num_states][_k_num_states];
|
float KHP[_k_num_states][_k_num_states];
|
||||||
float KH[9];
|
float KH[9];
|
||||||
for (unsigned row = 0; row < _k_num_states; row++) {
|
|
||||||
|
|
||||||
|
for (unsigned row = 0; row < _k_num_states; row++) {
|
||||||
KH[0] = Kfusion[row] * H_BETA[0];
|
KH[0] = Kfusion[row] * H_BETA[0];
|
||||||
KH[1] = Kfusion[row] * H_BETA[1];
|
KH[1] = Kfusion[row] * H_BETA[1];
|
||||||
KH[2] = Kfusion[row] * H_BETA[2];
|
KH[2] = Kfusion[row] * H_BETA[2];
|
||||||
|
@ -245,6 +250,7 @@ void Ekf::fuseSideslip()
|
||||||
// the covariance marix is unhealthy and must be corrected
|
// the covariance marix is unhealthy and must be corrected
|
||||||
bool healthy = true;
|
bool healthy = true;
|
||||||
_fault_status.flags.bad_sideslip = false;
|
_fault_status.flags.bad_sideslip = false;
|
||||||
|
|
||||||
for (int i = 0; i < _k_num_states; i++) {
|
for (int i = 0; i < _k_num_states; i++) {
|
||||||
if (P[i][i] < KHP[i][i]) {
|
if (P[i][i] < KHP[i][i]) {
|
||||||
// zero rows and columns
|
// zero rows and columns
|
||||||
|
@ -256,7 +262,6 @@ void Ekf::fuseSideslip()
|
||||||
|
|
||||||
// update individual measurement health status
|
// update individual measurement health status
|
||||||
_fault_status.flags.bad_sideslip = true;
|
_fault_status.flags.bad_sideslip = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +279,6 @@ void Ekf::fuseSideslip()
|
||||||
|
|
||||||
// apply the state corrections
|
// apply the state corrections
|
||||||
fuse(Kfusion, _beta_innov);
|
fuse(Kfusion, _beta_innov);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
ecl.h
14
ecl.h
|
@ -56,3 +56,17 @@
|
||||||
#define ECL_ERR printf
|
#define ECL_ERR printf
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __PX4_QURT
|
||||||
|
#if defined(__cplusplus) && !defined(__PX4_NUTTX)
|
||||||
|
#include <cmath>
|
||||||
|
#define ISFINITE(x) std::isfinite(x)
|
||||||
|
#else
|
||||||
|
#define ISFINITE(x) isfinite(x)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__PX4_QURT)
|
||||||
|
// Missing math.h defines
|
||||||
|
#define ISFINITE(x) __builtin_isfinite(x)
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue