Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

Committer:
uci1
Date:
Wed Jun 05 17:29:31 2019 +0000
Revision:
125:ce4045184366
Parent:
84:80b15993944e
Added SnRateListner proto-class, publishing this version of the code in order to enable exporting of most recent features.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
uci1 84:80b15993944e 1 #ifndef SN_SnSigProcUtils
uci1 84:80b15993944e 2 #define SN_SnSigProcUtils
uci1 84:80b15993944e 3
uci1 84:80b15993944e 4 #include <cmath>
uci1 84:80b15993944e 5 #include <stdint.h>
uci1 84:80b15993944e 6
uci1 84:80b15993944e 7 #include "SnConstants.h"
uci1 84:80b15993944e 8 #include "SnSigProcDataTable.h"
uci1 84:80b15993944e 9
uci1 84:80b15993944e 10 struct SnSigProcUtils {
uci1 84:80b15993944e 11
uci1 84:80b15993944e 12 static const double kPi;
uci1 84:80b15993944e 13 static const double kTwoPi;
uci1 84:80b15993944e 14
uci1 84:80b15993944e 15
uci1 84:80b15993944e 16 template<typename Num_t, typename Res_t>
uci1 84:80b15993944e 17 static
uci1 84:80b15993944e 18 void GetArraySumAndMaxSingleLoop(const Num_t* const data, const uint32_t n,
uci1 84:80b15993944e 19 Res_t& sum, Res_t& max) {
uci1 84:80b15993944e 20 const Num_t* d = data;
uci1 84:80b15993944e 21 max = static_cast<Res_t>(*d);
uci1 84:80b15993944e 22 sum = static_cast<Res_t>(*d);
uci1 84:80b15993944e 23 ++d; // skip past element 0
uci1 84:80b15993944e 24 for (uint32_t i=1; i<n; ++i, ++d) {
uci1 84:80b15993944e 25 sum += static_cast<Res_t>(*d);
uci1 84:80b15993944e 26 if (*d > max) {
uci1 84:80b15993944e 27 max = static_cast<Res_t>(*d);
uci1 84:80b15993944e 28 }
uci1 84:80b15993944e 29 }
uci1 84:80b15993944e 30 }
uci1 84:80b15993944e 31
uci1 84:80b15993944e 32 template<typename Dst_t, typename Src_t>
uci1 84:80b15993944e 33 static
uci1 84:80b15993944e 34 void MemCpyOrLoopCpy(Dst_t* const dst, const Src_t* const src,
uci1 84:80b15993944e 35 const uint32_t n) {
uci1 84:80b15993944e 36 #ifdef DEBUG_
uci1 84:80b15993944e 37 printf("MemCpyOrLoopCpy : loop\r\n");
uci1 84:80b15993944e 38 #endif
uci1 84:80b15993944e 39 Dst_t* d = dst;
uci1 84:80b15993944e 40 const Src_t* s = src;
uci1 84:80b15993944e 41 for (uint32_t i=0; i<n; ++i, ++d, ++s) {
uci1 84:80b15993944e 42 *d = static_cast<Dst_t>(*s);
uci1 84:80b15993944e 43 }
uci1 84:80b15993944e 44 }
uci1 84:80b15993944e 45
uci1 84:80b15993944e 46
uci1 84:80b15993944e 47 template<typename Same_t>
uci1 84:80b15993944e 48 static
uci1 84:80b15993944e 49 void MemCpyOrLoopCpy(Same_t* const dst, const Same_t* const src,
uci1 84:80b15993944e 50 const uint32_t n) {
uci1 84:80b15993944e 51 // can only memcpy if the types are the same
uci1 84:80b15993944e 52 #ifdef DEBUG_
uci1 84:80b15993944e 53 printf("MemCpyOrLoopCpy : memcpy\r\n");
uci1 84:80b15993944e 54 #endif
uci1 84:80b15993944e 55 memcpy(dst, src, sizeof(Same_t)*n);
uci1 84:80b15993944e 56 }
uci1 84:80b15993944e 57
uci1 84:80b15993944e 58 // the number of samples is a template parameter rather than
uci1 84:80b15993944e 59 // an input parameter so that we can be sure to use the proper
uci1 84:80b15993944e 60 // lookup tables, and that we should be somewhat safe against
uci1 84:80b15993944e 61 // using the wrong tables if the number of samples changes in the
uci1 84:80b15993944e 62 // future, as the code should no longer compile.
uci1 84:80b15993944e 63 template<uint32_t nn, typename Num_t>
uci1 84:80b15993944e 64 static
uci1 84:80b15993944e 65 bool DiscreteCpxFFT(Num_t* const data,
uci1 84:80b15993944e 66 const bool inverse) {
uci1 84:80b15993944e 67 // replace the data in the 'data' array by its discrete, complex-valued FFT
uci1 84:80b15993944e 68 //
uci1 84:80b15993944e 69 // if inverse is true, will do the inverse FFT
uci1 84:80b15993944e 70 // (unlike the function provided in NumRecC, the inverse FFT will
uci1 84:80b15993944e 71 // be provided already be normalized)
uci1 84:80b15993944e 72 // so calling DiscreteCpxFFT inverse on the result of
uci1 84:80b15993944e 73 // DiscreteCpxFFT forward will yield the original data (within
uci1 84:80b15993944e 74 // numerical accuracy)
uci1 84:80b15993944e 75 //
uci1 84:80b15993944e 76 // See RealFFT for notes on normalization. However, unlike RealFFT,
uci1 84:80b15993944e 77 // the factors of 2 and special bin treatments are not necessary
uci1 84:80b15993944e 78 // for the complex FFT, since both positive and negative
uci1 84:80b15993944e 79 // frequencies are stored in their own bins.
uci1 84:80b15993944e 80 //
uci1 84:80b15993944e 81 // NOTE: "data" must be of length 2*nn!! since the calculation is done
uci1 84:80b15993944e 82 // in place. the time domain data should be in the first half of "data".
uci1 84:80b15993944e 83 // nn must be a power of two
uci1 84:80b15993944e 84 // the fft is organized like: [ real_0, img_0, real_1, img_1, ... ]
uci1 84:80b15993944e 85 //
uci1 84:80b15993944e 86 // NUM REC C - 12.2, pg 507-508
uci1 84:80b15993944e 87 //
uci1 84:80b15993944e 88 // return true iff FFT succeeded
uci1 84:80b15993944e 89
uci1 84:80b15993944e 90 if ( ((nn-1)&nn)!=0 ) {
uci1 84:80b15993944e 91 #ifdef DEBUG
uci1 84:80b15993944e 92 printf("<DiscreteCpxFFT>: nn (=%u) must be a power of 2.",nn);
uci1 84:80b15993944e 93 return false;
uci1 84:80b15993944e 94 #endif
uci1 84:80b15993944e 95 } else {
uci1 84:80b15993944e 96
uci1 84:80b15993944e 97 static const uint32_t n = nn<<1; // nn * 2
uci1 84:80b15993944e 98 Num_t tempr,tempi;
uci1 84:80b15993944e 99 uint32_t m;
uci1 84:80b15993944e 100 uint32_t i,j=1;
uci1 84:80b15993944e 101 Num_t* di=data, * di1=data+1, * dj, * dj1;
uci1 84:80b15993944e 102 #ifdef USE_DFFT_LUTS
uci1 84:80b15993944e 103 const typename SnSigProcDataTable<n>::DfftDivideIndicies_t* kdi =
uci1 84:80b15993944e 104 SnSigProcDataTable<n>::kDfftDivideIndicies;
uci1 84:80b15993944e 105 #endif
uci1 84:80b15993944e 106 for (i=1; i<n; i+=2, di+=2, di1+=2) {
uci1 84:80b15993944e 107 if (j > i) {
uci1 84:80b15993944e 108 dj = data + j - 1;
uci1 84:80b15993944e 109 dj1 = dj + 1;
uci1 84:80b15993944e 110 tempr = *dj; *dj = *di; *di = tempr;
uci1 84:80b15993944e 111 tempr = *dj1; *dj1 = *di1; *di1 = tempr;
uci1 84:80b15993944e 112 }
uci1 84:80b15993944e 113 #ifdef USE_DFFT_LUTS
uci1 84:80b15993944e 114 j = *kdi++;
uci1 84:80b15993944e 115 m = *kdi++;
uci1 84:80b15993944e 116 #else
uci1 84:80b15993944e 117 m = nn;
uci1 84:80b15993944e 118 while (m>1 && j>m) {
uci1 84:80b15993944e 119 j -= m;
uci1 84:80b15993944e 120 m >>= 1;
uci1 84:80b15993944e 121 }
uci1 84:80b15993944e 122 j += m;
uci1 84:80b15993944e 123 #endif
uci1 84:80b15993944e 124 }
uci1 84:80b15993944e 125
uci1 84:80b15993944e 126 #ifdef USE_DFFT_LUTS
uci1 84:80b15993944e 127 double wr, wi;
uci1 84:80b15993944e 128 const typename SnSigProcDataTable<n>::DfftTwidleFactor_t* ktf =
uci1 84:80b15993944e 129 SnSigProcDataTable<n>::kDfftTwidleFactors;
uci1 84:80b15993944e 130 #else
uci1 84:80b15993944e 131 double wtemp, wr, wpr, wpi, wi, theta;
uci1 84:80b15993944e 132 const int8_t isign = inverse ? -1 : 1;
uci1 84:80b15993944e 133 #endif
uci1 84:80b15993944e 134 uint32_t mmax=2, istep;
uci1 84:80b15993944e 135 while (n > mmax) {
uci1 84:80b15993944e 136 istep = mmax<<1;
uci1 84:80b15993944e 137 #ifndef USE_DFFT_LUTS // if not defined!
uci1 84:80b15993944e 138 theta = isign * (kTwoPi / mmax);
uci1 84:80b15993944e 139 wtemp = std::sin(0.5*theta);
uci1 84:80b15993944e 140 wpr = -2.0 * wtemp * wtemp;
uci1 84:80b15993944e 141 wpi = std::sin(theta);
uci1 84:80b15993944e 142 wr = 1.0;
uci1 84:80b15993944e 143 wi = 0.0;
uci1 84:80b15993944e 144 #endif
uci1 84:80b15993944e 145 for (m=1; m<mmax; m+=2) {
uci1 84:80b15993944e 146 #ifdef USE_DFFT_LUTS
uci1 84:80b15993944e 147 wr = *ktf++;
uci1 84:80b15993944e 148 wi = *ktf++;
uci1 84:80b15993944e 149 if (inverse) {
uci1 84:80b15993944e 150 wi = -wi;
uci1 84:80b15993944e 151 }
uci1 84:80b15993944e 152 #endif
uci1 84:80b15993944e 153 for (i=m; i<=n; i+=istep) {
uci1 84:80b15993944e 154 j = i + mmax;
uci1 84:80b15993944e 155 dj = data + j - 1;
uci1 84:80b15993944e 156 dj1 = dj+1;
uci1 84:80b15993944e 157 di = data + i - 1;
uci1 84:80b15993944e 158 di1 = di+1;
uci1 84:80b15993944e 159 tempr = wr * (*dj) - wi*(*dj1);
uci1 84:80b15993944e 160 tempi = wr * (*dj1) + wi*(*dj);
uci1 84:80b15993944e 161 *dj = *di - tempr;
uci1 84:80b15993944e 162 *dj1 = *di1 - tempi;
uci1 84:80b15993944e 163 *di += tempr;
uci1 84:80b15993944e 164 *di1 += tempi;
uci1 84:80b15993944e 165 }
uci1 84:80b15993944e 166 #ifndef USE_DFFT_LUTS // if not defined!
uci1 84:80b15993944e 167 wtemp = wr;
uci1 84:80b15993944e 168 wr = wtemp*wpr - wi*wpi + wr;
uci1 84:80b15993944e 169 wi = wi*wpr + wtemp*wpi + wi;
uci1 84:80b15993944e 170 #endif
uci1 84:80b15993944e 171 }
uci1 84:80b15993944e 172 mmax = istep;
uci1 84:80b15993944e 173 }
uci1 84:80b15993944e 174 if (inverse) {
uci1 84:80b15993944e 175 // scale amplitude back
uci1 84:80b15993944e 176 di = data;
uci1 84:80b15993944e 177 static const Num_t tn = 2.0/static_cast<Num_t>(n);
uci1 84:80b15993944e 178 for (i=0; i<n; ++i, ++di) {
uci1 84:80b15993944e 179 *di *= tn;
uci1 84:80b15993944e 180 }
uci1 84:80b15993944e 181 }
uci1 84:80b15993944e 182 }
uci1 84:80b15993944e 183
uci1 84:80b15993944e 184 return true;
uci1 84:80b15993944e 185 }
uci1 84:80b15993944e 186
uci1 84:80b15993944e 187 // the number of samples is a template parameter rather than
uci1 84:80b15993944e 188 // an input parameter so that we can be sure to use the proper
uci1 84:80b15993944e 189 // lookup tables, and that we should be somewhat safe against
uci1 84:80b15993944e 190 // using the wrong tables if the number of samples changes in the
uci1 84:80b15993944e 191 // future, as the code should no longer compile.
uci1 84:80b15993944e 192 template<uint32_t n, typename Num_t>
uci1 84:80b15993944e 193 static
uci1 84:80b15993944e 194 bool RealFFT(Num_t* const data,
uci1 84:80b15993944e 195 const bool inverse) {
uci1 84:80b15993944e 196 // replace the real-valued data with the positive frequency half of its
uci1 84:80b15993944e 197 // complex fourier transform
uci1 84:80b15993944e 198 //
uci1 84:80b15993944e 199 // the real valued first & last components of the complex transform
uci1 84:80b15993944e 200 // are stored in data[0] and data[1], respectively
uci1 84:80b15993944e 201 //
uci1 84:80b15993944e 202 // n must be a power of 2
uci1 84:80b15993944e 203 //
uci1 84:80b15993944e 204 // data goes from [0..n-1]
uci1 84:80b15993944e 205 //
uci1 84:80b15993944e 206 // Note on the normalization convention used:
uci1 84:80b15993944e 207 // The 2/n normalization is applied only on the inverse FFT.
uci1 84:80b15993944e 208 // * To normalize the *amplitude* of frequencies in the forward
uci1 84:80b15993944e 209 // FFT, multiply by 2/n in bins [2..n-1] (which store two both
uci1 84:80b15993944e 210 // the pos and neg frequencies) and 1/n in bins [0..1]. For
uci1 84:80b15993944e 211 // example, if you have in the time domain (200*sine_50MHz +
uci1 84:80b15993944e 212 // 300*sine_230MHz) and you want to see a spike at 50MHz with
uci1 84:80b15993944e 213 // amplitude 200 and a spike at 230MHz with amplitude 300, you
uci1 84:80b15993944e 214 // should multiply bins 0 and 1 by 1/n and the other bins by 2/n.
uci1 84:80b15993944e 215 // * To normalize the *total power* of the forward FFT, multiply
uci1 84:80b15993944e 216 // by 2/sqrt(n) for bins [2..n-1] (which store two both
uci1 84:80b15993944e 217 // the pos and neg frequencies) and 1/sqrt(n) in bins [0..1].
uci1 84:80b15993944e 218 // This is the normalization chosen by NewGraphFromRealFFT when its
uci1 84:80b15993944e 219 // "normalize" parameter is true.
uci1 84:80b15993944e 220 //
uci1 84:80b15993944e 221 // if inverse is true, will perform the inverse FFT
uci1 84:80b15993944e 222 // (unlike the function provided in NumRecC, the inverse FFT will
uci1 84:80b15993944e 223 // be provided already be mulitplied by 2/n) -- so taking the inverse
uci1 84:80b15993944e 224 // FFT of the result of the forward FFT will yield directly the original
uci1 84:80b15993944e 225 // data (within numerical accuracy).
uci1 84:80b15993944e 226 //
uci1 84:80b15993944e 227 // NUM REC C - 12.3, pg 513-514
uci1 84:80b15993944e 228 //
uci1 84:80b15993944e 229 // return true iff the FFT succeeded
uci1 84:80b15993944e 230
uci1 84:80b15993944e 231 if ( ((n-1)&n)!=0 ) {
uci1 84:80b15993944e 232 #ifdef DEBUG
uci1 84:80b15993944e 233 printf("<RealFFT>: n (=%u) must be a power of 2.",n);
uci1 84:80b15993944e 234 #endif
uci1 84:80b15993944e 235 return false;
uci1 84:80b15993944e 236 } else {
uci1 84:80b15993944e 237
uci1 84:80b15993944e 238 double theta = kPi / static_cast<double>(n>>1);
uci1 84:80b15993944e 239 float c1=0.5, c2;
uci1 84:80b15993944e 240 if (inverse) {
uci1 84:80b15993944e 241 c2 = 0.5;
uci1 84:80b15993944e 242 theta = -theta; // set up for inverse tranform
uci1 84:80b15993944e 243 } else {
uci1 84:80b15993944e 244 c2 = -0.5;
uci1 84:80b15993944e 245 DiscreteCpxFFT<(n/2)>(data,false); // forward FFT
uci1 84:80b15993944e 246 }
uci1 84:80b15993944e 247
uci1 84:80b15993944e 248 #ifdef USE_DFFT_LUTS
uci1 84:80b15993944e 249 typename SnSigProcDataTable<n>::RealDfftTwidleFactor_t
uci1 84:80b15993944e 250 wr, wi;
uci1 84:80b15993944e 251 const typename SnSigProcDataTable<n>::RealDfftTwidleFactor_t
uci1 84:80b15993944e 252 * krtf = SnSigProcDataTable<n>::kRealDfftTwidleFactor;
uci1 84:80b15993944e 253 #else
uci1 84:80b15993944e 254 double wtemp = std::sin(0.5*theta);
uci1 84:80b15993944e 255 const double wpr = -2.0*wtemp*wtemp;
uci1 84:80b15993944e 256 const double wpi = std::sin(theta);
uci1 84:80b15993944e 257 double wr = 1.0+wpr;
uci1 84:80b15993944e 258 double wi = wpi;
uci1 84:80b15993944e 259 #endif
uci1 84:80b15993944e 260 float h1r, h1i, h2r, h2i;
uci1 84:80b15993944e 261 const uint32_t n4 = n>>2; // n/4
uci1 84:80b15993944e 262 uint32_t i;
uci1 84:80b15993944e 263 Num_t* d1 = data+2, * d2 = d1+1,
uci1 84:80b15993944e 264 * d3 = data+n-2, * d4 = d3+1;
uci1 84:80b15993944e 265 for (i=1; i<n4; ++i, d1+=2, d2+=2, d3-=2, d4-=2) {
uci1 84:80b15993944e 266 #ifdef USE_DFFT_LUTS
uci1 84:80b15993944e 267 wr = *krtf++;
uci1 84:80b15993944e 268 wi = *krtf++;
uci1 84:80b15993944e 269 if (inverse) {
uci1 84:80b15993944e 270 wi = -wi;
uci1 84:80b15993944e 271 }
uci1 84:80b15993944e 272 #endif
uci1 84:80b15993944e 273 h1r = c1 * ((*d1)+(*d3));
uci1 84:80b15993944e 274 h1i = c1 * ((*d2)-(*d4));
uci1 84:80b15993944e 275 h2r = -c2 * ((*d2)+(*d4));
uci1 84:80b15993944e 276 h2i = c2 * ((*d1)-(*d3));
uci1 84:80b15993944e 277 *d1 = h1r + wr*h2r - wi*h2i;
uci1 84:80b15993944e 278 *d2 = h1i + wr*h2i + wi*h2r;
uci1 84:80b15993944e 279 *d3 = h1r - wr*h2r + wi*h2i;
uci1 84:80b15993944e 280 *d4 = -h1i + wr*h2i + wi*h2r;
uci1 84:80b15993944e 281 #ifndef USE_DFFT_LUTS // if not defined!
uci1 84:80b15993944e 282 wtemp = wr;
uci1 84:80b15993944e 283 wr = wtemp*wpr - wi*wpi + wr;
uci1 84:80b15993944e 284 wi = wi*wpr + wtemp*wpi + wi;
uci1 84:80b15993944e 285 #endif
uci1 84:80b15993944e 286 }
uci1 84:80b15993944e 287
uci1 84:80b15993944e 288 // now fill in the beginning and end of the array
uci1 84:80b15993944e 289 if (inverse) {
uci1 84:80b15993944e 290 h1r = *data;
uci1 84:80b15993944e 291 d1 = data+1;
uci1 84:80b15993944e 292 *data = c1*(h1r + (*d1));
uci1 84:80b15993944e 293 *d1 = c1*(h1r - (*d1));
uci1 84:80b15993944e 294 DiscreteCpxFFT<(n/2)>(data,inverse); // inverse tranform
uci1 84:80b15993944e 295 } else {
uci1 84:80b15993944e 296 h1r = *data;
uci1 84:80b15993944e 297 d1 = data+1;
uci1 84:80b15993944e 298 *data = h1r + (*d1);
uci1 84:80b15993944e 299 *d1 = h1r - (*d1);
uci1 84:80b15993944e 300 }
uci1 84:80b15993944e 301 }
uci1 84:80b15993944e 302 return true;
uci1 84:80b15993944e 303 }
uci1 84:80b15993944e 304
uci1 84:80b15993944e 305 template<typename Num_t>
uci1 84:80b15993944e 306 static
uci1 84:80b15993944e 307 uint32_t ReplaceRfftWithSpectrum(Num_t* const rfft,
uci1 84:80b15993944e 308 const uint32_t n,
uci1 84:80b15993944e 309 const bool doSqrt) {
uci1 84:80b15993944e 310 // rfft should contain the result of RealFFT and n is the number
uci1 84:80b15993944e 311 // of samples.
uci1 84:80b15993944e 312 // this routine will replace the first half of the array
uci1 84:80b15993944e 313 // with the "spectrum" (frequency magnitude) at each freq bin.
uci1 84:80b15993944e 314 // valid freq bins are from [0, (n/2)+1]
uci1 84:80b15993944e 315 //
uci1 84:80b15993944e 316 // return the number of freq bins filled, or else 0 on error
uci1 84:80b15993944e 317
uci1 84:80b15993944e 318 if (rfft!=0) {
uci1 84:80b15993944e 319 //const uint32_t hn = n>>1; // n/2
uci1 84:80b15993944e 320 //uint32_t j=0;
uci1 84:80b15993944e 321 // set the first freq bin
uci1 84:80b15993944e 322 rfft[0] = (doSqrt) ? std::abs(rfft[0])
uci1 84:80b15993944e 323 : (rfft[0]*rfft[0]);
uci1 84:80b15993944e 324 // store the last freq bin
uci1 84:80b15993944e 325 const Num_t hibin =
uci1 84:80b15993944e 326 (doSqrt) ? std::abs(rfft[1])
uci1 84:80b15993944e 327 : (rfft[1]*rfft[1]);
uci1 84:80b15993944e 328 // loop over other freqs
uci1 84:80b15993944e 329 const Num_t* fe=rfft+2; // evens
uci1 84:80b15993944e 330 const Num_t* fo=fe+1; // odds
uci1 84:80b15993944e 331 Num_t* fbin=rfft+1; // current freq bin
uci1 84:80b15993944e 332 for (uint32_t i=2; i<n; i+=2, fe+=2, fo+=2, ++fbin) {
uci1 84:80b15993944e 333 *fbin = ( ((*fe)*(*fe)) + ((*fo)*(*fo)) );
uci1 84:80b15993944e 334 if (doSqrt) {
uci1 84:80b15993944e 335 *fbin = std::sqrt(static_cast<float>(*fbin));
uci1 84:80b15993944e 336 }
uci1 84:80b15993944e 337 }
uci1 84:80b15993944e 338 // set the last freq bin
uci1 84:80b15993944e 339 *fbin = hibin;
uci1 84:80b15993944e 340
uci1 84:80b15993944e 341 return (fbin-rfft+1);
uci1 84:80b15993944e 342 }
uci1 84:80b15993944e 343 return 0;
uci1 84:80b15993944e 344 }
uci1 84:80b15993944e 345
uci1 84:80b15993944e 346 };
uci1 84:80b15993944e 347
uci1 84:80b15993944e 348 #endif // SN_SnSigProcUtils