Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: platform_drivers LTC26X6 AD77681
cn0540_adi_fft.c
00001 /****************************************************************************** 00002 *Copyright (c)2020 Analog Devices, Inc. 00003 * 00004 * Licensed under the 2020-04-27-CN0540EC License(the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * 00007 ****************************************************************************/ 00008 00009 #include "cn0540_adi_fft.h" 00010 #include "cn0540_windowing.h" 00011 #include "stdio.h" 00012 #include "stdlib.h" 00013 #include <math.h> 00014 #include <stdbool.h> 00015 00016 static arm_cfft_radix4_instance_f32 S; 00017 00018 /** 00019 * Initialize the FFT structure 00020 * @param **fft_entry_init - the FFT data structure 00021 * @param **fft_meas - the FFT measurements structure 00022 */ 00023 int32_t FFT_init_params(struct fft_entry **fft_entry_init, struct fft_measurements **fft_meas) 00024 { 00025 struct fft_entry *fft_data_init; 00026 struct fft_measurements *fft_meas_init; 00027 00028 fft_data_init = (struct fft_entry *)malloc(sizeof(*fft_data_init)); 00029 if (!fft_data_init) { 00030 return -1; 00031 } 00032 fft_meas_init = (struct fft_measurements *)malloc(sizeof(*fft_meas_init)); 00033 if (!fft_meas_init) { 00034 return -1; 00035 } 00036 fft_data_init->window = BLACKMAN_HARRIS_7TERM; 00037 fft_data_init->vref = (float)(4096); 00038 fft_data_init->sample_rate = 32000; 00039 fft_data_init->mclk = 16384; 00040 fft_data_init->fft_length = 4096; 00041 fft_data_init->bin_width = 0.0; 00042 fft_data_init->fft_done = false; 00043 00044 *fft_entry_init = fft_data_init; 00045 00046 fft_meas_init->fundamental = 0.0; 00047 fft_meas_init->pk_spurious_noise = 0.0; 00048 fft_meas_init->pk_spurious_freq = 0; 00049 fft_meas_init->THD = 0.0; 00050 fft_meas_init->SNR = 0.0; 00051 fft_meas_init->DR = 0.0; 00052 fft_meas_init->SINAD = 0.0; 00053 fft_meas_init->SFDR_dbc = 0.0; 00054 fft_meas_init->SFDR_dbfs = 0.0; 00055 fft_meas_init->ENOB = 0.0; 00056 fft_meas_init->RMS_noise = 0.0; 00057 fft_meas_init->average_bin_noise = 0.0; 00058 fft_meas_init->max_amplitude = 0.0; 00059 fft_meas_init->min_amplitude = 0.0; 00060 fft_meas_init->pk_pk_amplitude = 0.0; 00061 fft_meas_init->DC = 0.0; 00062 fft_meas_init->transition_noise = 0.0; 00063 fft_meas_init->max_amplitude_LSB = 0; 00064 fft_meas_init->min_amplitude_LSB = 0; 00065 fft_meas_init->pk_pk_amplitude_LSB = 0; 00066 fft_meas_init->DC_LSB = 0; 00067 fft_meas_init->transition_noise_LSB = 0.0; 00068 00069 for (uint8_t i = 0; i < 7; i++) { 00070 fft_meas_init->harmonics_mag_dbfs[i] = 0.0; 00071 fft_meas_init->harmonics_freq[i] = 0; 00072 fft_meas_init->harmonics_power[i] = 0.0; 00073 } 00074 00075 *fft_meas = fft_meas_init; 00076 00077 return 0; 00078 } 00079 00080 /** 00081 * Initialize the FFT module 00082 * The funciton has to be called, everytime when user wants to change the number of samples 00083 * @param sample_count - desired FFT samples 00084 * @param *fft_data - fft_data structure 00085 */ 00086 void FFT_init(uint16_t sample_count, struct fft_entry *fft_data) 00087 { 00088 arm_cfft_radix4_init_f32(&S, sample_count, 0, 1); 00089 fft_data->fft_length = sample_count / 2; 00090 } 00091 00092 /** 00093 * Update reference voltage and Master clock 00094 * The funciton has to be called, everytime when user wants to change Vref or Mclk 00095 * @param referemce - The reference voltage in mV 00096 * @param master_clock - The master clock frequnecy in kHz 00097 * @param sampling_rate - The samplingrate frequnecy in kHz 00098 * @param *fft_data - fft_data structure 00099 */ 00100 void update_FFT_enviroment(uint16_t reference, uint16_t master_clock, uint16_t sampling_rate, struct fft_entry *fft_data) 00101 { 00102 fft_data->vref = ((float)(reference)) / ((float)(1000.0)); // Convert reference voltage to V 00103 fft_data->mclk = master_clock; // MCLK in kHz 00104 fft_data->sample_rate = sampling_rate; // Sampling rate 00105 } 00106 00107 00108 00109 00110 /** 00111 * Perform the FFT 00112 * @param *data - pointer to sampled data 00113 * @param *fft_data - fft_data structure 00114 * @param *fft_meas - fft_meas structure 00115 * @param sample_rate - sample rate based on MCLK, MCLK_DIV and Digital filter settings 00116 */ 00117 void perform_FFT(uint32_t *data, struct fft_entry *fft_data, struct fft_measurements *fft_meas, uint32_t sample_rate) 00118 { 00119 uint32_t i; 00120 int32_t shifted_data = 0; 00121 double coeffs_sum = 0.0; 00122 00123 fft_data->fft_done = false; 00124 fft_data->sample_rate = sample_rate; // get sample rate 00125 fft_data->bin_width = (float)(fft_data->sample_rate) / ((float)(fft_data->fft_length)*2); // get bin width 00126 00127 00128 //Converting RAW adc data to codes 00129 for(i = 0 ; i < fft_data->fft_length * 2 ; i++) { 00130 if (data[i] & 0x800000) 00131 shifted_data = (int32_t)((0xFF << 24) | data[i]); 00132 else 00133 shifted_data = (int32_t)((0x00 << 24) | data[i]); 00134 00135 fft_data->codes[i] = shifted_data; // Codes in range 0 +/- ZERO SCALE 00136 fft_data->zero_scale_codes[i] = shifted_data + ADC_ZERO_SCALE; // Codes shifted up by ZERO SCALE - range ZERO SCALE +/- ZERO SCALE 00137 } 00138 // Find max, min, pk-pk amplitude, DC offset, Tranition noise 00139 FFT_waveform_stat(fft_data, fft_meas); 00140 00141 // Converting codes without DC offset to "volts" without respect to Vref voltage 00142 for (i = 0; i < fft_data->fft_length * 4; i++) { 00143 // Filling array for FFT, conversion to voltage withour respect to Vref voltage 00144 fft_data->fft_input[i] = ((((float)(fft_data->codes[i / 2])) / ADC_ZERO_SCALE)); 00145 00146 // Voltage array with respect to full scale voltage, Vpp 00147 fft_data->voltage[i / 2] = (float)((2*fft_data->vref / ADC_ZERO_SCALE) * fft_data->codes[i / 2]); 00148 00149 // Imaginary part 00150 fft_data->fft_input[++i] = 0; 00151 } 00152 // Apply windowing 00153 FFT_windowing(fft_data, &coeffs_sum); 00154 //perform FFT, passing the input array, complex FFT values will be stored to the iput array 00155 arm_cfft_radix4_f32(&S, fft_data->fft_input); 00156 //transform from complex FFT to magnitude 00157 arm_cmplx_mag_f32(fft_data->fft_input, fft_data->fft_magnitude, fft_data->fft_length); 00158 // Convert FFT magnitude to dB for plot 00159 FFT_maginutde_do_dB(fft_data, coeffs_sum); 00160 //Calculate THD 00161 FFT_calculate_THD(fft_data, fft_meas); 00162 // Calculate noise and its parameters from FFT points 00163 FFT_calculate_noise(fft_data, fft_meas); 00164 // FFT finish flag 00165 fft_data->fft_done = true; 00166 } 00167 00168 /** 00169 * Windowing function 00170 * 7-term Blackman-Harris and Rectangular widow for now, prepared for more windowing functions if needed 00171 * You can use precalculated coeficients for 4096 sample length 00172 * @param *sample - pointer to sample 00173 * @param sample_length - 2 * FFT_length, because working with samples, not with FFT yet 00174 * @param *sum - pointer to sum of all the coeffs 00175 * 00176 */ 00177 void static FFT_windowing(struct fft_entry *fft_data, double *sum) 00178 { 00179 uint8_t j; 00180 uint16_t i; 00181 double term = 0.0; 00182 const double sample_count = (double)((fft_data->fft_length * 2) - 1); 00183 00184 for (i = 0; i < fft_data->fft_length * 4; i++) 00185 { 00186 switch (fft_data->window) { // Switch prepard for other windowing functions 00187 case BLACKMAN_HARRIS_7TERM: 00188 if (fft_data->fft_length == 2048) // For 4096 samples, precalculated coefficients are used 00189 term = Seven_Term_Blackman_Harris_4096[i / 2]; 00190 else { // 7-term BH windowing formula 00191 for (j = 0; j < 7; j++) 00192 term += seven_term_BH_coefs[j] * cos((double)((2.0 * PI * j * (i / 2))) / sample_count); 00193 } 00194 break; 00195 case RECTANGULAR: // No window, all terms = 1 00196 term = 1; 00197 break; 00198 default: 00199 break; 00200 } 00201 *sum += term; // Getting sum of all terms, which will be used for amplitude correction 00202 fft_data->fft_input[i] *= (float)(term); // Multiplying each (real) sample by windowing term 00203 term = 0.0; 00204 i++; // +1, to consider only real (not imaginary) samples 00205 } 00206 } 00207 00208 00209 /** 00210 * Transfer magnitude to dB 00211 * @param *fft_data - fft_data structure 00212 * @param sum - sum of all windowing coeffs 00213 */ 00214 void static FFT_maginutde_do_dB(struct fft_entry *fft_data, double sum) 00215 { 00216 uint16_t i; 00217 float correction = 0; 00218 00219 // Getting sum of coeffs 00220 // If rectangular window is choosen = no windowing, sum of coeffs is number of samples 00221 const float coeff_sum = ((fft_data->fft_length == 2048) && 00222 (fft_data->window == BLACKMAN_HARRIS_7TERM)) ? ((float)(Seven_Term_Blackman_Harris_4096_sum)) : 00223 ((fft_data->window == RECTANGULAR) ? ((float)(fft_data->fft_length * 2.0)) : (float)(sum)); 00224 00225 for (i = 0; i < fft_data->fft_length; i++) { 00226 // Apply a correction factor 00227 // Divide magnigude by a sum of the windowing function coefficients 00228 // Multiple by 2 because of power spread over spectrum below and above the Nyquist frequency 00229 correction = (fft_data->fft_magnitude[i] * 2.0) / coeff_sum; 00230 00231 // FFT magnitude with windowing correction 00232 fft_data->fft_magnitude_corrected[i] = correction; 00233 00234 //Convert to dB without respect to Vref 00235 fft_data->fft_dB[i] = 20.0 * (log10f(correction)); 00236 } 00237 } 00238 00239 /** 00240 * THD Calculation with support of harmonics folding to 1-st nyquist zone 00241 * @param *fft_data - fft_data structure 00242 * @param *fft_meas - fft_meas structure 00243 */ 00244 void static FFT_calculate_THD(struct fft_entry *fft_data, struct fft_measurements *fft_meas) 00245 { 00246 const uint16_t first_nyquist_zone = fft_data->fft_length; 00247 uint16_t i, j, k = 0, fund_freq = 0, harmonic_position; 00248 int8_t m, nyquist_zone; 00249 float mag_helper = -200.0, freq_helper, sum = 0.0, fund_mag = -200.0; 00250 float fund_pow_bins[21], harm_pow_bins[5][7]; 00251 00252 // Looking for the fundamental frequency and amplitude 00253 for(i = DC_BINS ; i < fft_data->fft_length ; i++) { // Not counting DC bins 00254 if (fft_data->fft_dB[i] > fund_mag) { 00255 fund_mag = fft_data->fft_dB[i]; 00256 fund_freq = i; 00257 } 00258 } 00259 00260 fft_meas->harmonics_freq[0] = fund_freq; // Fundamental frequency bin 00261 fft_meas->harmonics_mag_dbfs[0] = fund_mag; // Fundamental magnitude in dBFS 00262 fft_meas->fundamental = dbfs_to_volts(fft_data->vref, fund_mag); // Fundamental magnitude in V 00263 00264 for(i = 1 ; i < 6 ; i++) { 00265 if (fft_meas->harmonics_freq[0] * (i + 1) < first_nyquist_zone) // Checking if 2nd harmonic is outside of the first nyquist zone 00266 harmonic_position = fft_meas->harmonics_freq[0] * (i + 1); 00267 else { 00268 nyquist_zone = 1 + (fft_meas->harmonics_freq[0] * (i + 1) / first_nyquist_zone); // Determine the nyquist zone 00269 if(nyquist_zone % 2) // Odd nyquist zones: 3, 5, 7... 00270 harmonic_position = first_nyquist_zone - (first_nyquist_zone * nyquist_zone - fft_meas->harmonics_freq[0] * (i + 1)); 00271 else // Even nyquist zones: 2, 4, 6... 00272 harmonic_position = first_nyquist_zone * nyquist_zone - fft_meas->harmonics_freq[0] * (i + 1); 00273 } 00274 // Extend searching range by 3 bins around expected position of the harmonic 00275 for(m = -HARM_BINS ; m <= HARM_BINS ; m++) { 00276 if (fft_data->fft_dB[harmonic_position + m] > mag_helper) { 00277 mag_helper = fft_data->fft_dB[harmonic_position + m]; 00278 freq_helper = (harmonic_position + m); 00279 } 00280 } 00281 00282 fft_meas->harmonics_freq[i] = freq_helper; 00283 fft_meas->harmonics_mag_dbfs[i] = mag_helper; 00284 mag_helper = -200.0; 00285 } 00286 // Power leakage of the fundamental 00287 for(i = fft_meas->harmonics_freq[0] - FUND_BINS ; i <= fft_meas->harmonics_freq[0] + FUND_BINS ; i++) { 00288 sum += powf(((fft_data->fft_magnitude_corrected[i] / (2.0*SQRT_2))), 2.0); 00289 fund_pow_bins[k] = fft_data->fft_magnitude_corrected[i]; 00290 k++; 00291 } 00292 // Finishing the RSS of power-leaked fundamental 00293 sum = sqrt(sum); 00294 fft_meas->harmonics_power[0] = sum * 2.0 * SQRT_2; 00295 sum = 0.0; 00296 k = 0; 00297 // Power leakage of the harmonics 00298 for(j = 1 ; j <= 5 ; j++) { 00299 for (i = fft_meas->harmonics_freq[j] - HARM_BINS; i <= fft_meas->harmonics_freq[j] + HARM_BINS; i++) { 00300 sum += powf(((fft_data->fft_magnitude_corrected[i] / (2.0*SQRT_2))), 2.0); 00301 harm_pow_bins[j - 1][k] = fft_data->fft_magnitude_corrected[i]; 00302 k++; 00303 } 00304 // Finishing the RSS of power-leaked harmonics 00305 k = 0; 00306 sum = sqrt(sum); 00307 fft_meas->harmonics_power[j] = sum * 2.0 * SQRT_2; 00308 sum = 0.0; 00309 } 00310 // The THD formula 00311 fft_meas->THD = sqrtf(powf(fft_meas->harmonics_power[1], 2.0) + powf(fft_meas->harmonics_power[2], 2.0) + powf(fft_meas->harmonics_power[3], 2.0) + powf(fft_meas->harmonics_power[4], 2.0) + powf(fft_meas->harmonics_power[5], 2.0)) / fft_meas->harmonics_power[0]; 00312 // Back from volts to dB 00313 fft_meas->THD = 20.0 * log10f(fft_meas->THD); 00314 } 00315 00316 /** 00317 * Calculate amplitudes: min, max, pk-pk amplitude and DC part 00318 * @param *fft_data - fft_data structure 00319 * @param *fft_meas - fft_meas structure 00320 */ 00321 void static FFT_waveform_stat(struct fft_entry *fft_data, struct fft_measurements *fft_meas) 00322 { 00323 uint16_t i; 00324 int16_t max_position, min_position; 00325 int32_t max = -ADC_ZERO_SCALE, min = ADC_ZERO_SCALE, offset_correction; 00326 int64_t sum = 0; 00327 double deviation = 0.0, mean; 00328 00329 // summ of all coeffs, to find the Mean value 00330 for(i = 0; i < fft_data->fft_length * 2; i++) 00331 sum += fft_data->codes[i]; 00332 00333 // Calculating mean value = DC offset 00334 mean = (sum / (fft_data->fft_length * 2)); 00335 00336 // DC part in LSBs 00337 fft_meas->DC_LSB = (int32_t)(mean) + ADC_ZERO_SCALE; 00338 offset_correction = (int32_t)(mean); 00339 00340 // Min, Max amplitudes + Deviation 00341 for (i = 0; i < fft_data->fft_length * 2; i++) { // Working with codes = fft_length * 2 00342 // Calculating the Deviation for Transition noise 00343 deviation += pow(fft_data->codes[i] - mean, 2.0); 00344 00345 // Looking for MAX value 00346 if (fft_data->codes[i] > max) { 00347 max = fft_data->codes[i]; 00348 max_position = i; 00349 } 00350 // Looking for MIN value 00351 if (fft_data->codes[i] < min) { 00352 min = fft_data->codes[i]; 00353 min_position = i; 00354 } 00355 } 00356 // Amplitudes in Volts 00357 fft_meas->max_amplitude = (2.0 * fft_data->vref * fft_data->codes[max_position]) / ADC_FULL_SCALE; 00358 fft_meas->min_amplitude = (2.0 * fft_data->vref * fft_data->codes[min_position]) / ADC_FULL_SCALE; 00359 fft_meas->pk_pk_amplitude = fft_meas->max_amplitude - fft_meas->min_amplitude; 00360 fft_meas->DC = (2.0 * fft_data->vref * ((float)(((int32_t)(fft_meas->DC_LSB) - ADC_ZERO_SCALE)))) / ADC_FULL_SCALE; 00361 00362 // Amplitudes in LSBs 00363 fft_meas->max_amplitude_LSB = fft_data->codes[max_position] + ADC_ZERO_SCALE; 00364 fft_meas->min_amplitude_LSB = fft_data->codes[min_position] + ADC_ZERO_SCALE; 00365 fft_meas->pk_pk_amplitude_LSB = fft_meas->max_amplitude_LSB - fft_meas->min_amplitude_LSB; 00366 00367 // Transition noise 00368 deviation = (sqrt(deviation / (fft_data->fft_length * 2.0))); 00369 fft_meas->transition_noise_LSB = (uint32_t)(deviation); 00370 fft_meas->transition_noise = (2.0 * fft_data->vref * fft_meas->transition_noise_LSB) / ADC_FULL_SCALE; 00371 00372 // RMS noise 00373 fft_meas->RMS_noise = fft_meas->transition_noise; 00374 00375 // Applying mean value to each sample = removing DC offset 00376 for(i = 0 ; i < fft_data->fft_length * 2 ; i++) 00377 fft_data->codes[i] -= offset_correction; 00378 00379 } 00380 00381 /** 00382 * Calculate the RMS noise from the FFT plot 00383 * @param *fft_data - fft_data structure 00384 * @param *fft_meas - fft_meas structure 00385 */ 00386 void static FFT_calculate_noise(struct fft_entry *fft_data, struct fft_measurements *fft_meas) 00387 { 00388 const float LW_DR_correction_const = 4.48; // Magic constant from the LabView FFT core correcting only dynamic range 00389 uint16_t i, j; 00390 float biggest_spur = -300; 00391 double RSS = 0.0, mean = 0.0; 00392 00393 // Initalizing pk_spurious variables 00394 fft_meas->pk_spurious_noise = -200.0; 00395 fft_meas->pk_spurious_freq = 0; 00396 00397 for (i = 0; i < DC_BINS; i++) // Ignoring DC bins 00398 fft_data->noise_bins[i] = 0.0; 00399 for (i = DC_BINS; i < fft_data->fft_length; i++) { 00400 // Ignoring spread near the fundamental 00401 if ((i <= fft_meas->harmonics_freq[0] + FUND_BINS) && (i >= fft_meas->harmonics_freq[0] - FUND_BINS)) 00402 fft_data->noise_bins[i] = 0.0; 00403 00404 else if((i <= fft_meas->harmonics_freq[1] + HARM_BINS) && (i >= fft_meas->harmonics_freq[1] - HARM_BINS)) // Ignoring spread near harmonics 00405 fft_data->noise_bins[i] = 0.0; 00406 00407 else if((i <= fft_meas->harmonics_freq[2] + HARM_BINS) && (i >= fft_meas->harmonics_freq[2] - HARM_BINS)) 00408 fft_data->noise_bins[i] = 0.0; 00409 00410 else if((i <= fft_meas->harmonics_freq[3] + HARM_BINS) && (i >= fft_meas->harmonics_freq[3] - HARM_BINS)) 00411 fft_data->noise_bins[i] = 0.0; 00412 00413 else if((i <= fft_meas->harmonics_freq[4] + HARM_BINS) && (i >= fft_meas->harmonics_freq[4] - HARM_BINS)) 00414 fft_data->noise_bins[i] = 0.0; 00415 00416 else if((i <= fft_meas->harmonics_freq[5] + HARM_BINS) && (i >= fft_meas->harmonics_freq[5] - HARM_BINS)) 00417 fft_data->noise_bins[i] = 0.0; 00418 00419 else { 00420 // Root Sum Square = RSS for noise calculations 00421 fft_data->noise_bins[i] = fft_data->fft_magnitude_corrected[i]; 00422 RSS += pow(((double)(fft_data->fft_magnitude_corrected[i] / (2.0*SQRT_2))), 2.0); 00423 00424 // Average bin noise 00425 mean += fft_data->fft_magnitude_corrected[i]; 00426 00427 // Peak spurious amplitude 00428 if(fft_data->fft_magnitude_corrected[i] > fft_meas->pk_spurious_noise) { 00429 fft_meas->pk_spurious_noise = fft_data->fft_magnitude_corrected[i]; 00430 fft_meas->pk_spurious_freq = i; 00431 } 00432 00433 } 00434 } 00435 mean /= (double)(fft_data->fft_length); 00436 00437 // RSS of FFT spectrum without DC, Fund. and Harmonics 00438 RSS = sqrt(RSS); 00439 RSS = RSS * 2.0 * SQRT_2; 00440 00441 // Peak spurious amplitude = Highest amplitude excluding DC, the Fundamental and the Harmonics 00442 fft_meas->pk_spurious_noise = 20.0 * log10f(1.0 / fft_meas->pk_spurious_noise); 00443 00444 // Looking for the biggest spur among harmonics 00445 for(i = 1 ; i < 6 ; i++) { 00446 if (fft_meas->harmonics_mag_dbfs[i] > biggest_spur) 00447 biggest_spur = fft_meas->harmonics_mag_dbfs[i]; 00448 } 00449 // Looking for the biggest spur among harmonics and pk_spurious_noise 00450 if(biggest_spur > fft_meas->pk_spurious_noise) 00451 biggest_spur = fft_meas->pk_spurious_noise; 00452 00453 // Spurious Free Dynamic Range SFDR related to the carrer = biggest spur - the Fundamental, [dBc] - Decibels related to the carrier 00454 fft_meas->SFDR_dbc = biggest_spur - fft_meas->harmonics_mag_dbfs[0]; 00455 00456 // Spurious Free Dynamic Range SFDR related to the full-scale = biggest spur - full-scale [dBFS], where full-scale is 0 dBFS 00457 fft_meas->SFDR_dbfs = biggest_spur; 00458 00459 // Average bin noise = Mean value of FFT spectrum excluding DC, the Fundamental and the Harmonics 00460 fft_meas->average_bin_noise = (float)(20.0 * log10(mean)); 00461 00462 // DR = 1 / RSS of FFT spectrum without DC, Fund. and Harmonics + Magic constant from the Labview FFT core 00463 fft_meas->DR = (20.0 * log10f(1.0 / (float)(RSS))) + LW_DR_correction_const; 00464 00465 // SNR = Power of the fundamental / RSS of FFT spectrum without DC, Fund. and Harmonics 00466 fft_meas->SNR = 20.0 * log10f((fft_meas->harmonics_power[0]) / (RSS)); 00467 00468 // SINAD 00469 fft_meas->SINAD = -10.0 * log10f(powf(10.0, (fabs(fft_meas->SNR))*(-1.0) / 10.0) + powf(10.0, fabs(fft_meas->THD)*(-1.0) / 10.0)); 00470 00471 // ENOB - Effective number of bits 00472 fft_meas->ENOB = (fft_meas->SINAD - 1.67 + fabs(fft_meas->harmonics_mag_dbfs[0])) / 6.02; 00473 } 00474 00475 /** 00476 * Convert dBFS to volts in Pk-Pk 00477 * @param vref - reference voltage in volts 00478 * @param *fft_meas - fft_meas structure 00479 */ 00480 float static dbfs_to_volts(float vref, float value) 00481 { 00482 return ( 2 * vref * powf(10.0, value / 20.0) ); 00483 }
Generated on Sun Jul 17 2022 08:53:29 by
1.7.2