|
|
|
@ -93,6 +93,7 @@ GyroFFT::~GyroFFT()
@@ -93,6 +93,7 @@ GyroFFT::~GyroFFT()
|
|
|
|
|
perf_free(_cycle_perf); |
|
|
|
|
perf_free(_cycle_interval_perf); |
|
|
|
|
perf_free(_fft_perf); |
|
|
|
|
perf_free(_gyro_generation_gap_perf); |
|
|
|
|
perf_free(_gyro_fifo_generation_gap_perf); |
|
|
|
|
|
|
|
|
|
delete _gyro_data_buffer_x; |
|
|
|
@ -106,7 +107,7 @@ GyroFFT::~GyroFFT()
@@ -106,7 +107,7 @@ GyroFFT::~GyroFFT()
|
|
|
|
|
bool GyroFFT::init() |
|
|
|
|
{ |
|
|
|
|
if (!SensorSelectionUpdate(true)) { |
|
|
|
|
PX4_WARN("sensor_gyro_fifo callback registration failed!"); |
|
|
|
|
PX4_WARN("sensor_gyro callback registration failed!"); |
|
|
|
|
ScheduleDelayed(500_ms); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -120,28 +121,31 @@ bool GyroFFT::SensorSelectionUpdate(bool force)
@@ -120,28 +121,31 @@ bool GyroFFT::SensorSelectionUpdate(bool force)
|
|
|
|
|
_sensor_selection_sub.copy(&sensor_selection); |
|
|
|
|
|
|
|
|
|
if ((sensor_selection.gyro_device_id != 0) && (_selected_sensor_device_id != sensor_selection.gyro_device_id)) { |
|
|
|
|
// prefer sensor_gyro_fifo if available
|
|
|
|
|
for (uint8_t i = 0; i < MAX_SENSOR_COUNT; i++) { |
|
|
|
|
uORB::SubscriptionData<sensor_gyro_fifo_s> sensor_gyro_fifo_sub{ORB_ID(sensor_gyro_fifo), i}; |
|
|
|
|
|
|
|
|
|
if (sensor_gyro_fifo_sub.get().device_id == sensor_selection.gyro_device_id) { |
|
|
|
|
if (_sensor_gyro_fifo_sub.ChangeInstance(i) && _sensor_gyro_fifo_sub.registerCallback()) { |
|
|
|
|
_sensor_gyro_sub.unregisterCallback(); |
|
|
|
|
_sensor_gyro_fifo_sub.set_required_updates(sensor_gyro_fifo_s::ORB_QUEUE_LENGTH - 1); |
|
|
|
|
_selected_sensor_device_id = sensor_selection.gyro_device_id; |
|
|
|
|
_gyro_fifo = true; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// find corresponding vehicle_imu_status instance
|
|
|
|
|
for (uint8_t imu_status = 0; imu_status < MAX_SENSOR_COUNT; imu_status++) { |
|
|
|
|
uORB::Subscription imu_status_sub{ORB_ID(vehicle_imu_status), imu_status}; |
|
|
|
|
vehicle_imu_status_s vehicle_imu_status; |
|
|
|
|
|
|
|
|
|
if (imu_status_sub.copy(&vehicle_imu_status)) { |
|
|
|
|
if (vehicle_imu_status.gyro_device_id == sensor_selection.gyro_device_id) { |
|
|
|
|
_vehicle_imu_status_sub.ChangeInstance(imu_status); |
|
|
|
|
_selected_sensor_device_id = sensor_selection.gyro_device_id; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PX4_WARN("unable to find IMU status for gyro %d", sensor_selection.gyro_device_id); |
|
|
|
|
// otherwise use sensor_gyro
|
|
|
|
|
for (uint8_t i = 0; i < MAX_SENSOR_COUNT; i++) { |
|
|
|
|
uORB::SubscriptionData<sensor_gyro_s> sensor_gyro_sub{ORB_ID(sensor_gyro), i}; |
|
|
|
|
|
|
|
|
|
if (sensor_gyro_sub.get().device_id == sensor_selection.gyro_device_id) { |
|
|
|
|
if (_sensor_gyro_sub.ChangeInstance(i) && _sensor_gyro_sub.registerCallback()) { |
|
|
|
|
_sensor_gyro_fifo_sub.unregisterCallback(); |
|
|
|
|
_sensor_gyro_sub.set_required_updates(sensor_gyro_s::ORB_QUEUE_LENGTH - 1); |
|
|
|
|
_selected_sensor_device_id = sensor_selection.gyro_device_id; |
|
|
|
|
_gyro_fifo = false; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -154,16 +158,38 @@ bool GyroFFT::SensorSelectionUpdate(bool force)
@@ -154,16 +158,38 @@ bool GyroFFT::SensorSelectionUpdate(bool force)
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void GyroFFT::VehicleIMUStatusUpdate() |
|
|
|
|
void GyroFFT::VehicleIMUStatusUpdate(bool force) |
|
|
|
|
{ |
|
|
|
|
vehicle_imu_status_s vehicle_imu_status; |
|
|
|
|
if (_vehicle_imu_status_sub.updated() || force) { |
|
|
|
|
vehicle_imu_status_s vehicle_imu_status; |
|
|
|
|
|
|
|
|
|
if (_vehicle_imu_status_sub.copy(&vehicle_imu_status)) { |
|
|
|
|
// find corresponding vehicle_imu_status instance if the device_id doesn't match
|
|
|
|
|
if (vehicle_imu_status.gyro_device_id != _selected_sensor_device_id) { |
|
|
|
|
|
|
|
|
|
for (uint8_t imu_status = 0; imu_status < MAX_SENSOR_COUNT; imu_status++) { |
|
|
|
|
uORB::Subscription imu_status_sub{ORB_ID(vehicle_imu_status), imu_status}; |
|
|
|
|
|
|
|
|
|
if (imu_status_sub.copy(&vehicle_imu_status)) { |
|
|
|
|
if (vehicle_imu_status.gyro_device_id == _selected_sensor_device_id) { |
|
|
|
|
_vehicle_imu_status_sub.ChangeInstance(imu_status); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// update gyro sample rate
|
|
|
|
|
if ((vehicle_imu_status.gyro_device_id == _selected_sensor_device_id) && (vehicle_imu_status.gyro_rate_hz > 0)) { |
|
|
|
|
if (_gyro_fifo) { |
|
|
|
|
_gyro_sample_rate_hz = vehicle_imu_status.gyro_raw_rate_hz; |
|
|
|
|
|
|
|
|
|
if (_vehicle_imu_status_sub.update(&vehicle_imu_status)) { |
|
|
|
|
if ((vehicle_imu_status.gyro_device_id == _selected_sensor_device_id) |
|
|
|
|
&& (vehicle_imu_status.gyro_rate_hz > 0) |
|
|
|
|
&& (fabsf(vehicle_imu_status.gyro_rate_hz - _gyro_sample_rate_hz) > 1.f)) { |
|
|
|
|
} else { |
|
|
|
|
_gyro_sample_rate_hz = vehicle_imu_status.gyro_rate_hz; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_gyro_sample_rate_hz = vehicle_imu_status.gyro_raw_rate_hz; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -207,6 +233,7 @@ float GyroFFT::EstimatePeakFrequency(q15_t fft[], uint8_t peak_index)
@@ -207,6 +233,7 @@ float GyroFFT::EstimatePeakFrequency(q15_t fft[], uint8_t peak_index)
|
|
|
|
|
void GyroFFT::Run() |
|
|
|
|
{ |
|
|
|
|
if (should_exit()) { |
|
|
|
|
_sensor_gyro_sub.unregisterCallback(); |
|
|
|
|
_sensor_gyro_fifo_sub.unregisterCallback(); |
|
|
|
|
exit_and_cleanup(); |
|
|
|
|
return; |
|
|
|
@ -227,149 +254,176 @@ void GyroFFT::Run()
@@ -227,149 +254,176 @@ void GyroFFT::Run()
|
|
|
|
|
updateParams(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SensorSelectionUpdate(); |
|
|
|
|
VehicleIMUStatusUpdate(); |
|
|
|
|
const bool selection_updated = SensorSelectionUpdate(); |
|
|
|
|
VehicleIMUStatusUpdate(selection_updated); |
|
|
|
|
|
|
|
|
|
const float resolution_hz = _gyro_sample_rate_hz / _imu_gyro_fft_len; |
|
|
|
|
if (_gyro_fifo) { |
|
|
|
|
// run on sensor gyro fifo updates
|
|
|
|
|
sensor_gyro_fifo_s sensor_gyro_fifo; |
|
|
|
|
|
|
|
|
|
bool publish = false; |
|
|
|
|
bool fft_updated = false; |
|
|
|
|
while (_sensor_gyro_fifo_sub.update(&sensor_gyro_fifo)) { |
|
|
|
|
if (_sensor_gyro_fifo_sub.get_last_generation() != _gyro_last_generation + 1) { |
|
|
|
|
// force reset if we've missed a sample
|
|
|
|
|
_fft_buffer_index[0] = 0; |
|
|
|
|
_fft_buffer_index[1] = 0; |
|
|
|
|
_fft_buffer_index[2] = 0; |
|
|
|
|
|
|
|
|
|
perf_count(_gyro_fifo_generation_gap_perf); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// run on sensor gyro fifo updates
|
|
|
|
|
sensor_gyro_fifo_s sensor_gyro_fifo; |
|
|
|
|
_gyro_last_generation = _sensor_gyro_fifo_sub.get_last_generation(); |
|
|
|
|
|
|
|
|
|
while (_sensor_gyro_fifo_sub.update(&sensor_gyro_fifo)) { |
|
|
|
|
if (fabsf(sensor_gyro_fifo.scale - _fifo_last_scale) > FLT_EPSILON) { |
|
|
|
|
// force reset if scale has changed
|
|
|
|
|
_fft_buffer_index[0] = 0; |
|
|
|
|
_fft_buffer_index[1] = 0; |
|
|
|
|
_fft_buffer_index[2] = 0; |
|
|
|
|
|
|
|
|
|
if (_sensor_gyro_fifo_sub.get_last_generation() != _gyro_last_generation + 1) { |
|
|
|
|
// force reset if we've missed a sample
|
|
|
|
|
_fft_buffer_index[0] = 0; |
|
|
|
|
_fft_buffer_index[1] = 0; |
|
|
|
|
_fft_buffer_index[2] = 0; |
|
|
|
|
_fifo_last_scale = sensor_gyro_fifo.scale; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
perf_count(_gyro_fifo_generation_gap_perf); |
|
|
|
|
int16_t *input[] {sensor_gyro_fifo.x, sensor_gyro_fifo.y, sensor_gyro_fifo.z}; |
|
|
|
|
Update(sensor_gyro_fifo.timestamp_sample, input, sensor_gyro_fifo.samples); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (fabsf(sensor_gyro_fifo.scale - _fifo_last_scale) > FLT_EPSILON) { |
|
|
|
|
// force reset if scale has changed
|
|
|
|
|
_fft_buffer_index[0] = 0; |
|
|
|
|
_fft_buffer_index[1] = 0; |
|
|
|
|
_fft_buffer_index[2] = 0; |
|
|
|
|
} else { |
|
|
|
|
// run on sensor gyro fifo updates
|
|
|
|
|
sensor_gyro_s sensor_gyro; |
|
|
|
|
|
|
|
|
|
_fifo_last_scale = sensor_gyro_fifo.scale; |
|
|
|
|
} |
|
|
|
|
while (_sensor_gyro_sub.update(&sensor_gyro)) { |
|
|
|
|
if (_sensor_gyro_sub.get_last_generation() != _gyro_last_generation + 1) { |
|
|
|
|
// force reset if we've missed a sample
|
|
|
|
|
_fft_buffer_index[0] = 0; |
|
|
|
|
_fft_buffer_index[1] = 0; |
|
|
|
|
_fft_buffer_index[2] = 0; |
|
|
|
|
|
|
|
|
|
_gyro_last_generation = _sensor_gyro_fifo_sub.get_last_generation(); |
|
|
|
|
perf_count(_gyro_generation_gap_perf); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const int N = sensor_gyro_fifo.samples; |
|
|
|
|
_gyro_last_generation = _sensor_gyro_sub.get_last_generation(); |
|
|
|
|
|
|
|
|
|
for (int axis = 0; axis < 3; axis++) { |
|
|
|
|
int16_t *input[] {sensor_gyro_fifo.x, sensor_gyro_fifo.y, sensor_gyro_fifo.z}; |
|
|
|
|
q15_t *gyro_data_buffer[] {_gyro_data_buffer_x, _gyro_data_buffer_y, _gyro_data_buffer_z}; |
|
|
|
|
const float gyro_scale = math::radians(1000.f); // arbitrary scaling float32 rad/s -> raw int16
|
|
|
|
|
int16_t gyro_x[1] {(int16_t)roundf(sensor_gyro.x * gyro_scale)}; |
|
|
|
|
int16_t gyro_y[1] {(int16_t)roundf(sensor_gyro.y * gyro_scale)}; |
|
|
|
|
int16_t gyro_z[1] {(int16_t)roundf(sensor_gyro.z * gyro_scale)}; |
|
|
|
|
|
|
|
|
|
int &buffer_index = _fft_buffer_index[axis]; |
|
|
|
|
int16_t *input[] {gyro_x, gyro_y, gyro_z}; |
|
|
|
|
Update(sensor_gyro.timestamp_sample, input, 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (int n = 0; n < N; n++) { |
|
|
|
|
if (buffer_index < _imu_gyro_fft_len) { |
|
|
|
|
// convert int16_t -> q15_t (scaling isn't relevant)
|
|
|
|
|
gyro_data_buffer[axis][buffer_index] = input[axis][n] / 2; |
|
|
|
|
buffer_index++; |
|
|
|
|
} |
|
|
|
|
perf_end(_cycle_perf); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// if we have enough samples begin processing, but only one FFT per cycle
|
|
|
|
|
if ((buffer_index >= _imu_gyro_fft_len) && !fft_updated) { |
|
|
|
|
arm_mult_q15(gyro_data_buffer[axis], _hanning_window, _fft_input_buffer, _imu_gyro_fft_len); |
|
|
|
|
void GyroFFT::Update(const hrt_abstime ×tamp_sample, int16_t *input[], uint8_t N) |
|
|
|
|
{ |
|
|
|
|
bool publish = false; |
|
|
|
|
bool fft_updated = false; |
|
|
|
|
const float resolution_hz = _gyro_sample_rate_hz / _imu_gyro_fft_len; |
|
|
|
|
q15_t *gyro_data_buffer[] {_gyro_data_buffer_x, _gyro_data_buffer_y, _gyro_data_buffer_z}; |
|
|
|
|
|
|
|
|
|
perf_begin(_fft_perf); |
|
|
|
|
arm_rfft_q15(&_rfft_q15, _fft_input_buffer, _fft_outupt_buffer); |
|
|
|
|
perf_end(_fft_perf); |
|
|
|
|
fft_updated = true; |
|
|
|
|
for (int axis = 0; axis < 3; axis++) { |
|
|
|
|
int &buffer_index = _fft_buffer_index[axis]; |
|
|
|
|
|
|
|
|
|
static constexpr uint16_t MIN_SNR = 10; // TODO:
|
|
|
|
|
for (int n = 0; n < N; n++) { |
|
|
|
|
if (buffer_index < _imu_gyro_fft_len) { |
|
|
|
|
// convert int16_t -> q15_t (scaling isn't relevant)
|
|
|
|
|
gyro_data_buffer[axis][buffer_index] = input[axis][n] / 2; |
|
|
|
|
buffer_index++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool peaks_detected = false; |
|
|
|
|
uint32_t peaks_magnitude[MAX_NUM_PEAKS] {}; |
|
|
|
|
uint8_t peak_index[MAX_NUM_PEAKS] {}; |
|
|
|
|
// if we have enough samples begin processing, but only one FFT per cycle
|
|
|
|
|
if ((buffer_index >= _imu_gyro_fft_len) && !fft_updated) { |
|
|
|
|
arm_mult_q15(gyro_data_buffer[axis], _hanning_window, _fft_input_buffer, _imu_gyro_fft_len); |
|
|
|
|
|
|
|
|
|
// start at 2 to skip DC
|
|
|
|
|
// output is ordered [real[0], imag[0], real[1], imag[1], real[2], imag[2] ... real[(N/2)-1], imag[(N/2)-1]
|
|
|
|
|
for (uint16_t bucket_index = 2; bucket_index < (_imu_gyro_fft_len / 2); bucket_index = bucket_index + 2) { |
|
|
|
|
const float freq_hz = (bucket_index / 2) * resolution_hz; |
|
|
|
|
perf_begin(_fft_perf); |
|
|
|
|
arm_rfft_q15(&_rfft_q15, _fft_input_buffer, _fft_outupt_buffer); |
|
|
|
|
perf_end(_fft_perf); |
|
|
|
|
fft_updated = true; |
|
|
|
|
|
|
|
|
|
if (freq_hz > _param_imu_gyro_fft_max.get()) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
static constexpr uint16_t MIN_SNR = 10; // TODO:
|
|
|
|
|
|
|
|
|
|
if (freq_hz >= _param_imu_gyro_fft_min.get()) { |
|
|
|
|
const int16_t real = _fft_outupt_buffer[bucket_index]; |
|
|
|
|
const int16_t complex = _fft_outupt_buffer[bucket_index + 1]; |
|
|
|
|
bool peaks_detected = false; |
|
|
|
|
uint32_t peaks_magnitude[MAX_NUM_PEAKS] {}; |
|
|
|
|
uint8_t peak_index[MAX_NUM_PEAKS] {}; |
|
|
|
|
|
|
|
|
|
const uint32_t fft_magnitude_squared = real * real + complex * complex; |
|
|
|
|
// start at 2 to skip DC
|
|
|
|
|
// output is ordered [real[0], imag[0], real[1], imag[1], real[2], imag[2] ... real[(N/2)-1], imag[(N/2)-1]
|
|
|
|
|
for (uint16_t bucket_index = 2; bucket_index < (_imu_gyro_fft_len / 2); bucket_index = bucket_index + 2) { |
|
|
|
|
const float freq_hz = (bucket_index / 2) * resolution_hz; |
|
|
|
|
|
|
|
|
|
if (fft_magnitude_squared > MIN_SNR) { |
|
|
|
|
for (int i = 0; i < MAX_NUM_PEAKS; i++) { |
|
|
|
|
if (fft_magnitude_squared > peaks_magnitude[i]) { |
|
|
|
|
peaks_magnitude[i] = fft_magnitude_squared; |
|
|
|
|
peak_index[i] = bucket_index; |
|
|
|
|
peaks_detected = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (freq_hz > _param_imu_gyro_fft_max.get()) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (freq_hz >= _param_imu_gyro_fft_min.get()) { |
|
|
|
|
const int16_t real = _fft_outupt_buffer[bucket_index]; |
|
|
|
|
const int16_t complex = _fft_outupt_buffer[bucket_index + 1]; |
|
|
|
|
|
|
|
|
|
const uint32_t fft_magnitude_squared = real * real + complex * complex; |
|
|
|
|
|
|
|
|
|
if (fft_magnitude_squared > MIN_SNR) { |
|
|
|
|
for (int i = 0; i < MAX_NUM_PEAKS; i++) { |
|
|
|
|
if (fft_magnitude_squared > peaks_magnitude[i]) { |
|
|
|
|
peaks_magnitude[i] = fft_magnitude_squared; |
|
|
|
|
peak_index[i] = bucket_index; |
|
|
|
|
peaks_detected = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (peaks_detected) { |
|
|
|
|
float *peak_frequencies[] {_sensor_gyro_fft.peak_frequencies_x, _sensor_gyro_fft.peak_frequencies_y, _sensor_gyro_fft.peak_frequencies_z}; |
|
|
|
|
uint32_t *peak_magnitude[] {_sensor_gyro_fft.peak_magnitude_x, _sensor_gyro_fft.peak_magnitude_y, _sensor_gyro_fft.peak_magnitude_z}; |
|
|
|
|
if (peaks_detected) { |
|
|
|
|
float *peak_frequencies[] {_sensor_gyro_fft.peak_frequencies_x, _sensor_gyro_fft.peak_frequencies_y, _sensor_gyro_fft.peak_frequencies_z}; |
|
|
|
|
uint32_t *peak_magnitude[] {_sensor_gyro_fft.peak_magnitude_x, _sensor_gyro_fft.peak_magnitude_y, _sensor_gyro_fft.peak_magnitude_z}; |
|
|
|
|
|
|
|
|
|
int num_peaks_found = 0; |
|
|
|
|
int num_peaks_found = 0; |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_NUM_PEAKS; i++) { |
|
|
|
|
if ((peak_index[i] > 0) && (peak_index[i] < _imu_gyro_fft_len) && (peaks_magnitude[i] > 0)) { |
|
|
|
|
const float freq = EstimatePeakFrequency(_fft_outupt_buffer, peak_index[i]); |
|
|
|
|
for (int i = 0; i < MAX_NUM_PEAKS; i++) { |
|
|
|
|
if ((peak_index[i] > 0) && (peak_index[i] < _imu_gyro_fft_len) && (peaks_magnitude[i] > 0)) { |
|
|
|
|
const float freq = EstimatePeakFrequency(_fft_outupt_buffer, peak_index[i]); |
|
|
|
|
|
|
|
|
|
if (freq >= _param_imu_gyro_fft_min.get() && freq <= _param_imu_gyro_fft_max.get()) { |
|
|
|
|
if (freq >= _param_imu_gyro_fft_min.get() && freq <= _param_imu_gyro_fft_max.get()) { |
|
|
|
|
|
|
|
|
|
if (fabsf(peak_frequencies[axis][num_peaks_found] - freq) > 0.1f) { |
|
|
|
|
publish = true; |
|
|
|
|
} |
|
|
|
|
if (fabsf(peak_frequencies[axis][num_peaks_found] - freq) > 0.1f) { |
|
|
|
|
publish = true; |
|
|
|
|
_sensor_gyro_fft.timestamp_sample = timestamp_sample; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
peak_frequencies[axis][num_peaks_found] = freq; |
|
|
|
|
peak_magnitude[axis][num_peaks_found] = peaks_magnitude[i]; |
|
|
|
|
peak_frequencies[axis][num_peaks_found] = freq; |
|
|
|
|
peak_magnitude[axis][num_peaks_found] = peaks_magnitude[i]; |
|
|
|
|
|
|
|
|
|
num_peaks_found++; |
|
|
|
|
} |
|
|
|
|
num_peaks_found++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// mark remaining slots empty
|
|
|
|
|
for (int i = num_peaks_found; i < MAX_NUM_PEAKS; i++) { |
|
|
|
|
peak_frequencies[axis][i] = NAN; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// reset
|
|
|
|
|
// shift buffer (3/4 overlap)
|
|
|
|
|
const int overlap_start = _imu_gyro_fft_len / 4; |
|
|
|
|
memmove(&gyro_data_buffer[axis][0], &gyro_data_buffer[axis][overlap_start], sizeof(q15_t) * overlap_start * 3); |
|
|
|
|
buffer_index = overlap_start * 3; |
|
|
|
|
// mark remaining slots empty
|
|
|
|
|
for (int i = num_peaks_found; i < MAX_NUM_PEAKS; i++) { |
|
|
|
|
peak_frequencies[axis][i] = NAN; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// reset
|
|
|
|
|
// shift buffer (3/4 overlap)
|
|
|
|
|
const int overlap_start = _imu_gyro_fft_len / 4; |
|
|
|
|
memmove(&gyro_data_buffer[axis][0], &gyro_data_buffer[axis][overlap_start], sizeof(q15_t) * overlap_start * 3); |
|
|
|
|
buffer_index = overlap_start * 3; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (publish) { |
|
|
|
|
_sensor_gyro_fft.device_id = sensor_gyro_fifo.device_id; |
|
|
|
|
_sensor_gyro_fft.sensor_sample_rate_hz = _gyro_sample_rate_hz; |
|
|
|
|
_sensor_gyro_fft.resolution_hz = resolution_hz; |
|
|
|
|
_sensor_gyro_fft.timestamp_sample = sensor_gyro_fifo.timestamp_sample; |
|
|
|
|
_sensor_gyro_fft.timestamp = hrt_absolute_time(); |
|
|
|
|
_sensor_gyro_fft_pub.publish(_sensor_gyro_fft); |
|
|
|
|
if (publish) { |
|
|
|
|
_sensor_gyro_fft.device_id = _selected_sensor_device_id; |
|
|
|
|
_sensor_gyro_fft.sensor_sample_rate_hz = _gyro_sample_rate_hz; |
|
|
|
|
_sensor_gyro_fft.resolution_hz = resolution_hz; |
|
|
|
|
_sensor_gyro_fft.timestamp = hrt_absolute_time(); |
|
|
|
|
_sensor_gyro_fft_pub.publish(_sensor_gyro_fft); |
|
|
|
|
|
|
|
|
|
publish = false; |
|
|
|
|
} |
|
|
|
|
publish = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
perf_end(_cycle_perf); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int GyroFFT::task_spawn(int argc, char *argv[]) |
|
|
|
|