|
@@ -0,0 +1,105 @@
|
|
|
+#include "./lock-in.h"
|
|
|
+#include <cmath>
|
|
|
+
|
|
|
+namespace mri {
|
|
|
+ // ********************************************************************** //
|
|
|
+ // ********************************************************************** //
|
|
|
+ // ********************************************************************** //
|
|
|
+ void LockIn::Analyse(const std::vector<double> &signal,double period_ms,
|
|
|
+ const std::vector<double> ×teps,
|
|
|
+ int samples_per_period,
|
|
|
+ std::vector<double> &avg_sin,
|
|
|
+ std::vector<double> &avg_cos) {
|
|
|
+ period_ms_=period_ms;
|
|
|
+ total_samples_ = signal.size();
|
|
|
+ // Stage 1: Multiply
|
|
|
+ GenerateSinCos(timesteps);
|
|
|
+ std::vector<double> mul_sin, mul_cos;
|
|
|
+ mul_sin.resize(total_samples_);
|
|
|
+ mul_cos.resize(total_samples_);
|
|
|
+ for (unsigned long i = 0; i < total_samples_; ++i) {
|
|
|
+ mul_sin[i] = signal[i]*lockin_sin_[i];
|
|
|
+ mul_cos[i] = signal[i]*lockin_cos_[i];
|
|
|
+ }
|
|
|
+ // Stage 2: Low-pas filter:
|
|
|
+ //y[n] = a0 x[n] + b1 y[n-1]
|
|
|
+ // a0 = 1-x
|
|
|
+ // b1 = x
|
|
|
+ // x = exp (-1/samples)
|
|
|
+ /// a0 = (1-x)^4
|
|
|
+ // b1 = 4x
|
|
|
+ // b2 = -6 x^2
|
|
|
+ // b3 = 4 x^3
|
|
|
+ // b4 = - x^4
|
|
|
+ double x = std::exp(-1.0/(samples_per_period*2));
|
|
|
+ std::vector<double> mag_sin, mag_cos;
|
|
|
+ mag_sin.resize(total_samples_);
|
|
|
+ mag_cos.resize(total_samples_);
|
|
|
+ avg_sin.resize(total_samples_);
|
|
|
+ avg_cos.resize(total_samples_);
|
|
|
+ double mean_sin = 0.0, mean_cos = 0.0;
|
|
|
+ for (int i = 0; i < samples_per_period; ++i){
|
|
|
+ mag_sin[i] = mul_sin[i];
|
|
|
+ mag_cos[i] = mul_cos[i];
|
|
|
+ avg_sin[i] = mul_sin[i];
|
|
|
+ avg_cos[i] = mul_cos[i];
|
|
|
+ mean_sin += mul_sin[i];
|
|
|
+ mean_cos += mul_cos[i];
|
|
|
+ }
|
|
|
+ mean_sin /= samples_per_period;
|
|
|
+ mean_cos /= samples_per_period;
|
|
|
+ avg_sin[samples_per_period] = mean_sin;
|
|
|
+ avg_cos[samples_per_period] = mean_cos;
|
|
|
+ //First order low-pass
|
|
|
+ double a0 = 1-x, b1 = x;
|
|
|
+ for (unsigned long n = samples_per_period+1; n<total_samples_; ++n) {
|
|
|
+ mag_sin[n] = a0*mul_sin[n] + b1*mag_sin[n-1];
|
|
|
+ mag_cos[n] = a0*mul_cos[n] + b1*mag_cos[n-1];
|
|
|
+ avg_sin[n] = avg_sin[n-1]
|
|
|
+ + (mul_sin[n] - mul_sin[n-samples_per_period])/samples_per_period;
|
|
|
+ avg_cos[n] = avg_cos[n-1]
|
|
|
+ + (mul_cos[n] - mul_cos[n-samples_per_period])/samples_per_period;
|
|
|
+ }
|
|
|
+ // // Forth order low-pass
|
|
|
+ // double a0 = pow2(pow2(1-x)), b1 = 4*x, b2 = -6*pow2(x), b3 = 4*x*x*x, b4 = - pow2(pow2(x));
|
|
|
+ // for (unsigned long n = 1; n<total_samples_; ++n) {
|
|
|
+ // mag_sin[n] = a0*mul_sin[n] + b1*mag_sin[n-1]
|
|
|
+ // + b2*mag_sin[n-2] + b3*mag_sin[n-3] + b4*mag_sin[n-4];
|
|
|
+ // mag_cos[n] = a0*mul_cos[n] + b1*mag_cos[n-1]
|
|
|
+ // + b2*mag_cos[n-2] + b3*mag_cos[n-3] + b4*mag_cos[n-4];
|
|
|
+ // }
|
|
|
+
|
|
|
+ // Stage 3: Evaluate magnitude and phase
|
|
|
+ std::vector<double> out_magnitude, out_phase;
|
|
|
+ out_magnitude.resize(total_samples_);
|
|
|
+ out_phase.resize(total_samples_);
|
|
|
+ for (unsigned long i = 0; i<total_samples_; ++i) {
|
|
|
+ out_magnitude[i] = std::sqrt(
|
|
|
+ pow2(avg_sin[i]) +
|
|
|
+ pow2(avg_cos[i])
|
|
|
+ );
|
|
|
+ out_phase[i] = std::atan(avg_sin[i]/avg_cos[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ };
|
|
|
+ // ********************************************************************** //
|
|
|
+ // ********************************************************************** //
|
|
|
+ // ********************************************************************** //
|
|
|
+ void LockIn::GenerateSinCos(const std::vector<double> ×teps) {
|
|
|
+ omega_ = 2.0*PI_/period_ms_;
|
|
|
+ lockin_sin_.resize(total_samples_);
|
|
|
+ lockin_cos_.resize(total_samples_);
|
|
|
+ for (unsigned long i = 0; i < total_samples_; ++i) {
|
|
|
+ double time = timesteps[i];
|
|
|
+ lockin_sin_[i] = std::sin(omega_*time);
|
|
|
+ lockin_cos_[i] = std::cos(omega_*time);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ };
|
|
|
+ // ********************************************************************** //
|
|
|
+ // ********************************************************************** //
|
|
|
+ // ********************************************************************** //
|
|
|
+
|
|
|
+} // end of namespace mri
|