From 7553f24ddfabab761ba4564871b6b9e9af75c419 Mon Sep 17 00:00:00 2001
From: xiyehu2 <xiyehu2@illinois.edu>
Date: Thu, 19 Oct 2023 18:16:08 -0500
Subject: [PATCH] working implementation with basic functionalities

---
 Cpp/lib/waveform.cpp | 126 +++++++++++++++++++++++++++++++++++--------
 Cpp/lib/waveform.h   |  21 +++++++-
 2 files changed, 123 insertions(+), 24 deletions(-)

diff --git a/Cpp/lib/waveform.cpp b/Cpp/lib/waveform.cpp
index 54000bc..8f5422e 100644
--- a/Cpp/lib/waveform.cpp
+++ b/Cpp/lib/waveform.cpp
@@ -152,19 +152,21 @@ void ArrayWaveform::ArrayParam::printParam() {
     std::cout << "amplitudes:" << "\n" << this->amplitudes << "\n";
 }
 
-EigenVectorXi16 ArrayWaveform::getStaticWaveform(const ArrayParam& param) {
-    auto minSampleLen = 2 * param.samplingRate
-        / std::gcd(param.samplingRate, param.freqResolution);
-    Eigen::VectorXd t = Eigen::VectorXd::LinSpaced(
-        minSampleLen,
-        0,
-        minSampleLen - 1
-    ) / param.samplingRate;
-    Eigen::MatrixXd wfmMatrix = Eigen::sin(
-        ((param.freqTones * t.transpose() * M_PI * 2).array().colwise()
-        + param.phases.array())
-    ).array().colwise() * param.amplitudes.array();
-    return wfmMatrix.colwise().sum().cast<int16_t>();
+ulong ArrayWaveform::getMinSampleLen(
+    ulong samplingRate,
+    ulong freqResolution
+) {
+    return 2 * samplingRate / std::gcd(samplingRate, freqResolution);
+}
+
+ulong ArrayWaveform::getSampleLen(
+    double tau,
+    ulong samplingRate,
+    ulong freqResolution
+) {
+    ulong sampleLen = ulong(tau * samplingRate);
+    ulong minLen = getMinSampleLen(samplingRate, freqResolution);
+    return sampleLen % minLen == 0 ? sampleLen : (sampleLen / minLen + 1) * minLen;
 }
 
 double ArrayWaveform::setStaticSegment(
@@ -173,11 +175,11 @@ double ArrayWaveform::setStaticSegment(
     double initPhase,
     double amp
 ) {
-    Eigen::Ref<Eigen::ArrayXd> t = timeSeries.array();
-    t -= t(0);
-    double last = 2*M_PI * f * (t(t.size() - 1) + t(1)) + initPhase;
-    timeSeries.array() = amp * Eigen::sin(2*M_PI * f * t + initPhase);
-    return last;
+  Eigen::Ref<Eigen::ArrayXd> t = timeSeries.array();
+  t -= t(0);
+  double nextPhase = 2 * M_PI * f * (t(t.size() - 1) + t(1)) + initPhase;
+  timeSeries.array() = amp * Eigen::sin(2 * M_PI * f * t + initPhase);
+  return nextPhase;
 }
 
 double ArrayWaveform::setMovingSegment(
@@ -195,21 +197,101 @@ double ArrayWaveform::setMovingSegment(
     unsigned int midIdx = int(sampleLen / 2.0);
     Eigen::Ref<Eigen::ArrayXd> segl = timeSeries(Eigen::seq(0, midIdx));
     Eigen::Ref<Eigen::ArrayXd> segr = timeSeries(Eigen::seq(midIdx+1, sampleLen-1));
-    segr -= segl(0) + tau / 2;
+    segr -= segl(0) + tau / 2;  // it may seem more intuitive to use
+                                // segr -= segr(0) here, but doing so
+                                // will cause phase jump
     segl -= segl(0);
     segl = initPhase
         + 2 * M_PI * fInit * segl
         + accel / 6 * Eigen::pow(segl,3);
-    // segr.array() -= tau / 2;
     segr = segl(segl.size()-1)
         + (
             2 * M_PI * fInit + accel / 2 * std::pow((tau / 2),2)
         ) * segr
         + accel / 2 * tau / 2 * Eigen::pow(segr, 2)
         - accel / 6 * Eigen::pow(segr, 3);
-    double last = segr(segr.size() - 1) + dt * 2*M_PI * fFinal;
+    double nextPhase = segr(segr.size() - 1) + dt * 2*M_PI * fFinal;
     timeSeries = amp * Eigen::sin(timeSeries.array());
-    return last;
+    return nextPhase;
+}
+
+EigenVectorXi16 ArrayWaveform::getStaticWaveform(const ArrayParam& param) {
+    auto minSampleLen = 2 * param.samplingRate
+        / std::gcd(param.samplingRate, param.freqResolution);
+    Eigen::VectorXd t = Eigen::VectorXd::LinSpaced(
+        minSampleLen,
+        0,
+        minSampleLen - 1
+    ) / param.samplingRate;
+    Eigen::MatrixXd wfmMatrix = Eigen::sin(
+        ((param.freqTones * t.transpose() * M_PI * 2).array().colwise()
+        + param.phases.array())
+    ).array().colwise() * param.amplitudes.array();
+    return wfmMatrix.colwise().sum().cast<int16_t>();
+}
+
+EigenVectorXi16 ArrayWaveform::getTrickWaveform(
+    const ArrayParam& param,
+    std::set<int> siteIndex,
+    double df,
+    double tauMove,
+    double tauStay
+) {
+    if ((tauMove == 0 and tauStay == 0)
+        or siteIndex.empty()) {
+        return getStaticWaveform(param);
+    }
+    if (tauMove != 0 and tauStay != 0) {
+        tauStay = std::ceil((tauMove + tauStay) * df) / df - tauMove;
+    } else if (tauMove != 0) {
+        tauMove = std::ceil(tauMove * df) / df;
+    } else {
+        tauStay = std::ceil(tauStay * df) / df;
+    }
+    auto tauTotal = tauMove * 2 + tauStay;
+    ulong sampleLen = getSampleLen(tauTotal, param.samplingRate, param.freqResolution);
+    ulong moveLen = tauMove * param.samplingRate;
+    ulong stayLen = tauStay * param.samplingRate;
+    auto idxSeg0 = moveLen;
+    auto idxSeg1 = moveLen + stayLen;
+    auto idxSeg2 = moveLen + stayLen + moveLen;
+    auto t = Eigen::ArrayXd::LinSpaced(sampleLen, 0, sampleLen - 1) / param.samplingRate;
+    Eigen::MatrixXd wfmMat(sampleLen, param.freqTones.size()); // site wfm stored column by column
+    for (auto i = 0; i < param.freqTones.size(); i++) {
+        wfmMat.col(i) = t;
+        Eigen::Ref<Eigen::ArrayXd> siteWfm = wfmMat.col(i);
+        auto fInit = param.freqTones[i];
+        auto fFinal = fInit + df;
+        auto phi = param.phases[i];
+        auto amp = param.amplitudes[i];
+        if (siteIndex.contains(i)) {
+            if (tauMove != 0) {
+                phi = setMovingSegment(
+                    siteWfm(Eigen::seq(0, idxSeg0 - 1)),
+                    fInit, fFinal, phi, amp
+                );
+            }
+            if (tauStay != 0) {
+                phi = setStaticSegment(
+                    siteWfm(Eigen::seq(idxSeg0, idxSeg1 - 1)),
+                    fFinal, phi, amp
+                );
+            }
+            if (tauMove != 0) {
+                phi = setMovingSegment(
+                    siteWfm(Eigen::seq(idxSeg1, idxSeg2 - 1)),
+                    fFinal, fInit, phi, amp
+                );
+            }
+            setStaticSegment(
+                siteWfm(Eigen::seq(idxSeg2, siteWfm.size() - 1)),
+                fInit, phi, amp
+            );
+        } else {
+            setStaticSegment(siteWfm, fInit, phi, amp);
+        }
+    }
+    return wfmMat.rowwise().sum().cast<int16_t> ();
 }
 
 void ArrayWaveform::saveCSV(std::string fileName, EigenVectorXi16 wfm) {
diff --git a/Cpp/lib/waveform.h b/Cpp/lib/waveform.h
index 6c88232..b923d3b 100644
--- a/Cpp/lib/waveform.h
+++ b/Cpp/lib/waveform.h
@@ -1,6 +1,7 @@
 #pragma once
 #include <Eigen/Dense>
 #include <string>
+#include <set>
 typedef Eigen::Vector<int16_t, Eigen::Dynamic> EigenVectorXi16;
 
 namespace ArrayWaveform {
@@ -35,8 +36,14 @@ namespace ArrayWaveform {
         void loadParam(std::string fileName);
         void printParam();
     };
-    
-    EigenVectorXi16 getStaticWaveform(const ArrayParam& param);
+
+    ulong getMinSampleLen(ulong samplingRate, ulong freqResolution);
+    ulong getSampleLen(
+        double tau,
+        ulong samplingRate,
+        ulong freqResolution
+    );
+
     double setStaticSegment(
         Eigen::Ref<Eigen::VectorXd> timeSeries,
         double f,
@@ -50,6 +57,16 @@ namespace ArrayWaveform {
         double initPhase,
         double amp
     );
+
+    EigenVectorXi16 getStaticWaveform(const ArrayParam& param);
+    EigenVectorXi16 getTrickWaveform(
+        const ArrayParam& param,
+        std::set<int> siteIndex,
+        double df,
+        double tauMove=0,
+        double tauStay=0
+    );
+
     void saveCSV(std::string fileName, EigenVectorXi16 wfm);
 };
 
-- 
GitLab