2022-06-29 10:25:32 +00:00
|
|
|
// lasp_siggen_impl.cpp
|
|
|
|
//
|
|
|
|
// Author: J.A. de Jong -ASCEE
|
|
|
|
//
|
|
|
|
// Description:
|
|
|
|
// Signal generators implementation
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
2022-10-06 19:48:57 +00:00
|
|
|
/* #define DEBUGTRACE_ENABLED */
|
2022-06-29 10:25:32 +00:00
|
|
|
#include "lasp_siggen_impl.h"
|
|
|
|
#include "debugtrace.hpp"
|
|
|
|
#include "lasp_mathtypes.h"
|
2022-10-21 21:12:47 +00:00
|
|
|
#include <cassert>
|
2022-06-29 10:25:32 +00:00
|
|
|
|
2022-09-22 19:02:41 +00:00
|
|
|
using rte = std::runtime_error;
|
|
|
|
|
2022-06-29 10:25:32 +00:00
|
|
|
DEBUGTRACE_VARIABLES;
|
|
|
|
|
|
|
|
/** The fixed number of Newton iterations t.b.d. for tuning the sweep start and
|
|
|
|
* stop frequency in logarithmic sweeps */
|
|
|
|
#define NITER_NEWTON 20
|
|
|
|
|
|
|
|
Noise::Noise(){DEBUGTRACE_ENTER}
|
|
|
|
|
|
|
|
vd Noise::genSignalUnscaled(us nframes) {
|
|
|
|
return arma::randn<vd>(nframes);
|
|
|
|
}
|
|
|
|
void Noise::resetImpl() {}
|
|
|
|
|
2022-10-21 21:12:47 +00:00
|
|
|
Sine::Sine(const d freq) : omg(2 * arma::datum::pi * freq) { DEBUGTRACE_ENTER; }
|
2022-06-29 10:25:32 +00:00
|
|
|
|
|
|
|
vd Sine::genSignalUnscaled(const us nframes) {
|
2022-09-22 19:02:41 +00:00
|
|
|
/* DEBUGTRACE_ENTER; */
|
2022-06-29 10:25:32 +00:00
|
|
|
const d pi = arma::datum::pi;
|
|
|
|
vd phase_vec =
|
2022-10-21 21:12:47 +00:00
|
|
|
arma::linspace(phase, phase + omg * (nframes - 1) / _fs, nframes);
|
2022-09-22 19:02:41 +00:00
|
|
|
phase += omg * nframes / _fs;
|
2022-06-29 10:25:32 +00:00
|
|
|
while (phase > 2 * arma::datum::pi) {
|
|
|
|
phase -= 2 * pi;
|
|
|
|
}
|
|
|
|
return arma::sin(phase_vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
vd Periodic::genSignalUnscaled(const us nframes) {
|
2022-09-22 19:02:41 +00:00
|
|
|
|
2022-06-29 10:25:32 +00:00
|
|
|
vd res(nframes);
|
2022-10-21 21:12:47 +00:00
|
|
|
if (_signal.size() == 0) {
|
2022-09-22 19:02:41 +00:00
|
|
|
throw rte("No signal defined while calling");
|
|
|
|
}
|
2022-10-21 21:12:47 +00:00
|
|
|
for (us i = 0; i < nframes; i++) {
|
2022-09-22 19:02:41 +00:00
|
|
|
res(i) = _signal[_cur_pos];
|
2022-06-29 10:25:32 +00:00
|
|
|
_cur_pos++;
|
|
|
|
_cur_pos %= _signal.size();
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sweep::Sweep(const d fl, const d fu, const d Ts, const d Tq, const us flags)
|
2022-10-21 21:12:47 +00:00
|
|
|
: fl_(fl), fu_(fu), Ts(Ts), Tq(Tq), flags(flags) {
|
|
|
|
if (fl <= 0 || fu < fl || Ts <= 0) {
|
|
|
|
throw rte("Invalid sweep parameters");
|
|
|
|
}
|
|
|
|
if ((flags & ForwardSweep) && (flags & BackwardSweep)) {
|
|
|
|
throw rte(
|
|
|
|
"Both forward and backward sweep flag set. Please only set either one "
|
|
|
|
"or none for a continuous sweep");
|
2022-06-29 10:25:32 +00:00
|
|
|
}
|
2022-10-21 21:12:47 +00:00
|
|
|
if ((flags & LinearSweep) && (flags & LogSweep)) {
|
|
|
|
throw rte(
|
|
|
|
"Both logsweep and linear sweep flag set. Please only set either one.");
|
|
|
|
}
|
|
|
|
if (!((flags & LinearSweep) || (flags & LogSweep))) {
|
|
|
|
throw rte("Either LinearSweep or LogSweep should be given as flag");
|
|
|
|
}
|
|
|
|
}
|
2022-06-29 10:25:32 +00:00
|
|
|
|
|
|
|
void Sweep::resetImpl() {
|
|
|
|
|
2022-09-22 19:02:41 +00:00
|
|
|
DEBUGTRACE_ENTER;
|
|
|
|
|
2022-06-29 10:25:32 +00:00
|
|
|
_cur_pos = 0;
|
|
|
|
|
|
|
|
bool forward_sweep = flags & ForwardSweep;
|
|
|
|
bool backward_sweep = flags & BackwardSweep;
|
|
|
|
|
2022-09-22 19:02:41 +00:00
|
|
|
const d Dt = 1 / _fs; // Deltat
|
2022-06-29 10:25:32 +00:00
|
|
|
|
|
|
|
// Estimate N, the number of samples in the sweep part (non-quiescent part):
|
2022-09-22 19:02:41 +00:00
|
|
|
const us Ns = (us)(Ts * _fs);
|
|
|
|
const us Nq = (us)(Tq * _fs);
|
2022-06-29 10:25:32 +00:00
|
|
|
const us N = Ns + Nq;
|
|
|
|
|
|
|
|
_signal = vd(N, arma::fill::zeros);
|
|
|
|
index = 0;
|
|
|
|
|
|
|
|
d fl, fu;
|
|
|
|
/* Swap fl and fu for a backward sweep */
|
|
|
|
if (backward_sweep) {
|
|
|
|
fu = fl_;
|
|
|
|
fl = fu_;
|
|
|
|
} else {
|
|
|
|
/* Case of continuous sweep, or forward sweep */
|
|
|
|
fl = fl_;
|
|
|
|
fu = fu_;
|
|
|
|
}
|
|
|
|
|
|
|
|
d phase = 0;
|
|
|
|
|
|
|
|
/* Linear sweep */
|
|
|
|
if (flags & LinearSweep) {
|
|
|
|
if (forward_sweep || backward_sweep) {
|
|
|
|
/* Forward or backward sweep */
|
|
|
|
/* TRACE(15, "Forward or backward sweep"); */
|
2022-10-27 13:00:17 +00:00
|
|
|
us K = (us)(Dt * (fl * Ns + 0.5 * (Ns - 1) * (fu - fl)));
|
|
|
|
d eps_num = ((d)K) / Dt - fl * Ns - 0.5 * (Ns - 1) * (fu - fl);
|
|
|
|
d eps = eps_num / (0.5 * (Ns - 1));
|
2022-06-29 10:25:32 +00:00
|
|
|
/* iVARTRACE(15, K); */
|
|
|
|
/* dVARTRACE(15, eps); */
|
|
|
|
|
|
|
|
for (us n = 0; n < Ns; n++) {
|
|
|
|
_signal(n) = d_sin(phase);
|
2022-10-27 13:00:17 +00:00
|
|
|
d fn = fl + ((d)n) / Ns * (fu + eps - fl);
|
2022-06-29 10:25:32 +00:00
|
|
|
phase += 2 * arma::datum::pi * Dt * fn;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Continous sweep */
|
|
|
|
/* TRACE(15, "continuous sweep"); */
|
|
|
|
|
|
|
|
/* iVARTRACE(17, N); */
|
|
|
|
/* dVARTRACE(17, fl); */
|
|
|
|
/* dVARTRACE(17, fu); */
|
|
|
|
|
|
|
|
const us Nf = Ns / 2;
|
|
|
|
const us Nb = Ns - Nf;
|
|
|
|
|
|
|
|
/* Phi halfway */
|
|
|
|
d phih = 2 * number_pi * Dt * (fl * Nf + 0.5 * (Nf - 1) * (fu - fl));
|
|
|
|
|
|
|
|
us K =
|
2022-10-21 21:12:47 +00:00
|
|
|
(us)(phih / (2 * number_pi) + Dt * (fu * Nb - (Nb - 1) * (fu - fl)));
|
2022-06-29 10:25:32 +00:00
|
|
|
|
|
|
|
d eps_num1 = (K - phih / (2 * number_pi)) / Dt;
|
|
|
|
d eps_num2 = -fu * Nb + (Nb - 1) * (fu - fl);
|
|
|
|
d eps = (eps_num1 + eps_num2) / (0.5 * (Nb + 1));
|
|
|
|
|
|
|
|
/* iVARTRACE(15, K); */
|
|
|
|
/* dVARTRACE(15, eps); */
|
|
|
|
d phase = 0;
|
|
|
|
|
|
|
|
for (us n = 0; n <= Ns; n++) {
|
|
|
|
/* iVARTRACE(17, n); */
|
|
|
|
if (n < N) {
|
|
|
|
_signal[n] = d_sin(phase);
|
|
|
|
}
|
|
|
|
|
|
|
|
d fn;
|
|
|
|
if (n <= Nf) {
|
|
|
|
fn = fl + ((d)n) / Nf * (fu - fl);
|
|
|
|
} else {
|
|
|
|
fn = fu - ((d)n - Nf) / Nb * (fu + eps - fl);
|
|
|
|
}
|
|
|
|
/* dbgassert(fn >= 0, "BUG"); */
|
|
|
|
|
|
|
|
phase += 2 * number_pi * Dt * fn;
|
|
|
|
}
|
|
|
|
/* This should be a very small number!! */
|
|
|
|
/* dVARTRACE(15, phase); */
|
|
|
|
}
|
|
|
|
} else if (flags & LogSweep) {
|
|
|
|
|
2022-09-22 19:02:41 +00:00
|
|
|
DEBUGTRACE_PRINT("Log sweep");
|
2022-06-29 10:25:32 +00:00
|
|
|
if (forward_sweep || backward_sweep) {
|
|
|
|
/* Forward or backward sweep */
|
|
|
|
DEBUGTRACE_PRINT("Forward or backward sweep");
|
|
|
|
d k1 = (fu / fl);
|
2022-10-27 13:00:17 +00:00
|
|
|
us K = (us)(Dt * fl * (k1 - 1) / (d_pow(k1, 1.0 / Ns) - 1));
|
2022-06-29 10:25:32 +00:00
|
|
|
d k = k1;
|
|
|
|
|
|
|
|
/* Iterate k to the right solution */
|
|
|
|
d E;
|
|
|
|
for (us iter = 0; iter < 10; iter++) {
|
2022-10-27 13:00:17 +00:00
|
|
|
E = 1 + K / (Dt * fl) * (d_pow(k, 1.0 / Ns) - 1) - k;
|
|
|
|
d dEdk = K / (Dt * fl) * d_pow(k, 1.0 / Ns) / (Ns * k) - 1;
|
2022-06-29 10:25:32 +00:00
|
|
|
k -= E / dEdk;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUGTRACE_PRINT(K);
|
2022-07-20 12:58:48 +00:00
|
|
|
DEBUGTRACE_PRINT(k1);
|
2022-06-29 10:25:32 +00:00
|
|
|
DEBUGTRACE_PRINT(k);
|
|
|
|
DEBUGTRACE_PRINT(E);
|
|
|
|
|
|
|
|
for (us n = 0; n < Ns; n++) {
|
|
|
|
_signal[n] = d_sin(phase);
|
2022-10-27 13:00:17 +00:00
|
|
|
d fn = fl * d_pow(k, ((d)n) / Ns);
|
2022-06-29 10:25:32 +00:00
|
|
|
phase += 2 * number_pi * Dt * fn;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
DEBUGTRACE_PRINT("Continuous sweep");
|
|
|
|
|
2022-10-27 13:00:17 +00:00
|
|
|
const us Nf = Ns / 2;
|
|
|
|
const us Nb = Ns - Nf;
|
2022-06-29 10:25:32 +00:00
|
|
|
const d k1 = (fu / fl);
|
|
|
|
const d phif1 =
|
2022-10-21 21:12:47 +00:00
|
|
|
2 * number_pi * Dt * fl * (k1 - 1) / (d_pow(k1, 1.0 / Nf) - 1);
|
2022-06-29 10:25:32 +00:00
|
|
|
const us K = (us)(phif1 / (2 * number_pi) +
|
2022-10-21 21:12:47 +00:00
|
|
|
Dt * fu * (1 / k1 - 1) / (d_pow(1 / k1, 1.0 / Nb) - 1));
|
2022-06-29 10:25:32 +00:00
|
|
|
|
|
|
|
d E;
|
|
|
|
d k = k1;
|
|
|
|
|
|
|
|
/* Newton iterations to converge k to the value such that the sweep is
|
|
|
|
* continuous */
|
|
|
|
for (us iter = 0; iter < NITER_NEWTON; iter++) {
|
|
|
|
E = (k - 1) / (d_pow(k, 1.0 / Nf) - 1) +
|
2022-10-21 21:12:47 +00:00
|
|
|
(k - 1) / (1 - d_pow(k, -1.0 / Nb)) - K / Dt / fl;
|
2022-06-29 10:25:32 +00:00
|
|
|
DEBUGTRACE_PRINT(E);
|
|
|
|
|
|
|
|
/* All parts of the derivative of above error E to k */
|
|
|
|
d dEdk1 = 1 / (d_pow(k, 1.0 / Nf) - 1);
|
|
|
|
d dEdk2 = (1 / k - 1) / (d_pow(k, -1.0 / Nb) - 1);
|
|
|
|
d dEdk3 = -1 / (k * (d_pow(k, -1.0 / Nb) - 1));
|
|
|
|
d dEdk4 = d_pow(k, -1.0 / Nb) * (1 / k - 1) /
|
2022-10-21 21:12:47 +00:00
|
|
|
(Nb * d_pow(d_pow(k, -1.0 / Nb) - 1, 2));
|
2022-06-29 10:25:32 +00:00
|
|
|
d dEdk5 = -d_pow(k, 1.0 / Nf) * (k - 1) /
|
2022-10-21 21:12:47 +00:00
|
|
|
(Nf * k * d_pow(d_pow(k, 1.0 / Nf) - 1, 2));
|
2022-06-29 10:25:32 +00:00
|
|
|
d dEdk = dEdk1 + dEdk2 + dEdk3 + dEdk4 + dEdk5;
|
|
|
|
|
|
|
|
/* Iterate! */
|
|
|
|
k -= E / dEdk;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUGTRACE_PRINT(K);
|
2022-07-20 12:58:48 +00:00
|
|
|
DEBUGTRACE_PRINT(k1);
|
2022-06-29 10:25:32 +00:00
|
|
|
DEBUGTRACE_PRINT(k);
|
|
|
|
DEBUGTRACE_PRINT(E);
|
|
|
|
|
|
|
|
for (us n = 0; n <= Ns; n++) {
|
|
|
|
/* iVARTRACE(17, n); */
|
|
|
|
if (n < Ns) {
|
|
|
|
_signal[n] = d_sin(phase);
|
|
|
|
}
|
|
|
|
|
|
|
|
d fn;
|
|
|
|
if (n <= Nf) {
|
|
|
|
fn = fl * d_pow(k, ((d)n) / Nf);
|
|
|
|
} else {
|
|
|
|
fn = fl * k * d_pow(1 / k, ((d)n - Nf) / Nb);
|
|
|
|
}
|
|
|
|
/* dbgassert(fn >= 0, "BUG"); */
|
|
|
|
|
|
|
|
phase += 2 * number_pi * Dt * fn;
|
|
|
|
while (phase > 2 * number_pi)
|
|
|
|
phase -= 2 * number_pi;
|
|
|
|
/* dVARTRACE(17, phase); */
|
|
|
|
}
|
|
|
|
/* This should be a very small number!! */
|
|
|
|
DEBUGTRACE_PRINT(phase);
|
|
|
|
}
|
2022-10-21 21:12:47 +00:00
|
|
|
} // End of log sweep
|
|
|
|
else {
|
|
|
|
// Either log or linear sweep had to be given as flags.
|
|
|
|
assert(false);
|
|
|
|
|
2022-06-29 10:25:32 +00:00
|
|
|
}
|
|
|
|
}
|