neuro_toolbox
statistics.hpp
Go to the documentation of this file.
1 #ifndef STATISTICS
2 #define STATISTICS
3 
4 #include "config.hpp"
5 
6 namespace NTB
7 {
8  template <typename T>
9  std::vector<T> flatten(const std::vector<std::vector<T>> &vec)
10  {
16  std::size_t total_size = 0;
17  for (const auto &sub : vec)
18  total_size += sub.size();
19  std::vector<T> result;
20  result.reserve(total_size);
21  for (const auto &sub : vec)
22  result.insert(result.end(), sub.begin(), sub.end());
23  return result;
24  }
25 
26  std::vector<double> angle_arr(const fftw_complex *z,
27  const int n,
28  bool deg = false)
29  {
35  constexpr int REAL = 0;
36  constexpr int IMAG = 1;
37  constexpr double coeff = 180.0 / M_PI;
38 
39  std::vector<double> angle_z(n);
40  for (int i = 0; i < n; i++)
41  {
42  std::complex<double> z0(z[i][REAL], z[i][IMAG]);
43  if (deg)
44  angle_z[i] = std::arg(z0) * coeff;
45  else
46  angle_z[i] = std::arg(z0);
47  }
48 
49  return angle_z;
50  }
51 
52  template <typename T>
53  inline double average(const std::vector<T> &vec,
54  const int index = 0)
55  {
63  return accumulate(vec.begin() + index,
64  vec.end(), 0.0) /
65  (vec.size() - index);
66  }
67 
68  void hilbert_transform(const std::vector<double> &in_vec,
69  fftw_complex *out_array)
70  {
79  constexpr int REAL = 0;
80  constexpr int IMAG = 1;
81 
82  // copy data into the complex array
83  int N = in_vec.size();
84  for (int i = 0; i < N; i++)
85  {
86  out_array[i][REAL] = in_vec[i];
87  out_array[i][IMAG] = 0;
88  }
89  // create a DFT plan and execute it
90  fftw_plan plan = fftw_plan_dft_1d(N,
91  out_array,
92  out_array,
93  FFTW_FORWARD,
94  FFTW_ESTIMATE);
95  fftw_execute(plan);
96  fftw_destroy_plan(plan);
97  int hN = N >> 1; // half of the length(N/2);
98  int numRem = hN; // the number of remaining elements
99 
100  // multiply the appropriate values by 2
101  // those that sould be multiplied by 1 are left intact because they wouldn't change
102  for (int i = 1; i < hN; i++)
103  {
104  out_array[i][REAL] *= 2;
105  out_array[i][IMAG] *= 2;
106  }
107 
108  // if the length is even, the number of remaining elements decreases by 1
109  if (N % 2 == 0)
110  numRem--;
111 
112  // if it is odd and greater than 1, the middle value must be multiplied by 2
113  else if (N > 1)
114  {
115  out_array[hN][REAL] *= 2;
116  out_array[hN][IMAG] *= 2;
117  }
118  // set the remaining values to 0
119  // multiply by 0 gives 0 so we don't care about multiplication
120  memset(&out_array[hN + 1][REAL], 0, numRem * sizeof(fftw_complex));
121 
122  // create an IDFT plan and execute it
123  plan = fftw_plan_dft_1d(N, out_array, out_array, FFTW_BACKWARD, FFTW_ESTIMATE);
124  fftw_execute(plan);
125  // dom some cleaning
126  fftw_destroy_plan(plan);
127  fftw_cleanup();
128 
129  // scale the IDFT output
130  for (int i = 0; i < N; i++)
131  {
132  out_array[i][REAL] /= N;
133  out_array[i][IMAG] /= N;
134  }
135  }
136 
137  std::vector<double> unwrap(const std::vector<double> &in_vec)
138  {
149  int len = in_vec.size();
150  std::vector<double> out_vec(len);
151  out_vec[0] = in_vec[0];
152  for (size_t i = 1; i < len; i++)
153  {
154  double d = in_vec[i] - in_vec[i - 1];
155  d = d > M_PI ? d - 2 * M_PI : (d < -M_PI ? d + 2 * M_PI : d);
156  out_vec[i] = out_vec[i - 1] + d;
157  }
158  return out_vec;
159  }
160 
161  double calculate_phase_difference(const std::vector<double> &x)
162  {
163  int n = x.size();
164  double sum = 0.0;
165  for (int i = 1; i < n; i++)
166  {
167  sum += abs(x[i] - x[0]);
168  }
169  double result = sum / (n - 1.0);
170  return result;
171  }
172 
173  double calculate_phase_synchrony(const std::vector<std::vector<double>> &voltages)
174  {
175  int n = voltages.size();
176  int nstep = voltages[0].size();
177  std::vector<double> delta_phi(nstep);
178  std::vector<std::vector<double>> inst_phase(n, std::vector<double>(nstep));
179 
180  for (int i = 0; i < n; i++)
181  {
182  fftw_complex z[nstep];
183  hilbert_transform(voltages[i], z);
184  std::vector<double> angle_z = angle_arr(z, nstep);
185  // inst_phase[i] = unwrap(angle_z);
186  for (int j = 0; j < nstep; j++)
187  inst_phase[i][j] = fmod(angle_z[j], (2.0 * M_PI));
188  }
189 
190  for (int j = 0; j < nstep; j++)
191  {
192  std::vector<double> x(n);
193  for (int i = 0; i < n; i++)
194  x[i] = inst_phase[i][j];
195  delta_phi[j] = calculate_phase_difference(x);
196  }
197  double result = average(delta_phi, 0);
198 
199  return result;
200  }
201 } // namespace NTB
202 
203 #endif // !STATISTICS
std::vector< T > flatten(const std::vector< std::vector< T >> &vec)
Definition: statistics.hpp:9
void hilbert_transform(const std::vector< double > &in_vec, fftw_complex *out_array)
Definition: statistics.hpp:68
double average(const std::vector< T > &vec, const int index=0)
Definition: statistics.hpp:53
std::vector< double > unwrap(const std::vector< double > &in_vec)
Definition: statistics.hpp:137
Definition: IO.hpp:6
std::vector< double > angle_arr(const fftw_complex *z, const int n, bool deg=false)
Definition: statistics.hpp:26
double calculate_phase_synchrony(const std::vector< std::vector< double >> &voltages)
Definition: statistics.hpp:173
double calculate_phase_difference(const std::vector< double > &x)
Definition: statistics.hpp:161