fully implemented AvSweepPowerSpectra
This commit is contained in:
parent
6cdc182b57
commit
4cd390871a
@ -158,7 +158,8 @@ ccube AvPowerSpectra::get_est() const
|
|||||||
|
|
||||||
AvSweepPowerSpectra::AvSweepPowerSpectra(const us nfft, const Window::WindowType w,
|
AvSweepPowerSpectra::AvSweepPowerSpectra(const us nfft, const Window::WindowType w,
|
||||||
const d overlap_percentage,
|
const d overlap_percentage,
|
||||||
const d time_constant_times_fs)
|
const d time_constant_times_fs,
|
||||||
|
const vd *A)
|
||||||
: _nfft(nfft), _ps(nfft, w)
|
: _nfft(nfft), _ps(nfft, w)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -167,6 +168,14 @@ AvSweepPowerSpectra::AvSweepPowerSpectra(const us nfft, const Window::WindowType
|
|||||||
{
|
{
|
||||||
throw rte("Overlap percentage should be >= 0 and < 100");
|
throw rte("Overlap percentage should be >= 0 and < 100");
|
||||||
}
|
}
|
||||||
|
if(A == nullptr) {
|
||||||
|
_A = vd(nfft, arma::fill::ones);
|
||||||
|
} else {
|
||||||
|
if(A->n_elem != (nfft / 2 + 1)) {
|
||||||
|
throw rte("Invalid length given for amplitude coefficients");
|
||||||
|
}
|
||||||
|
_A = arma::square(*A);
|
||||||
|
}
|
||||||
|
|
||||||
_overlap_keep = (nfft * overlap_percentage) / 100;
|
_overlap_keep = (nfft * overlap_percentage) / 100;
|
||||||
DEBUGTRACE_PRINT(_overlap_keep);
|
DEBUGTRACE_PRINT(_overlap_keep);
|
||||||
@ -235,25 +244,24 @@ ccube AvSweepPowerSpectra::compute(const dmat &timedata)
|
|||||||
_n_averages = vd(nfreq, arma::fill::zeros);
|
_n_averages = vd(nfreq, arma::fill::zeros);
|
||||||
}
|
}
|
||||||
|
|
||||||
// d threshold = arma::mean(arma::real(temp.slice(0).col(0)));
|
vd corr_pow = arma::real(temp.slice(0).col(0)) / _A;
|
||||||
d threshold = 1e-13;
|
|
||||||
|
d threshold = pow(10.0, log10(arma::max(corr_pow)*arma::median(corr_pow))/2.0);
|
||||||
|
// d threshold = 1e-13;
|
||||||
|
|
||||||
for (us f=0; f < nfreq; f++)
|
for (us f=0; f < nfreq; f++)
|
||||||
{
|
{
|
||||||
if (real(temp(f, 0, 0)) > threshold)
|
if (real(temp(f, 0, 0)) / _A(f) > threshold)
|
||||||
{
|
{
|
||||||
_n_averages[f]++;
|
_n_averages[f]++;
|
||||||
if (_n_averages[f] == 1)
|
if (_n_averages[f] == 1)
|
||||||
{
|
{
|
||||||
_est.row(f) = temp.row(f);
|
_est.row(f) = temp.row(f);
|
||||||
// _est.subcube(f, 0, 0, f, ncols - 1, ncols - 1) = temp.subcube(f, 0, 0, f, ncols - 1, ncols - 1);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_est.row(f) = (static_cast<d>(_n_averages[f] - 1) / _n_averages[f]) * _est.row(f) +
|
_est.row(f) = (static_cast<d>(_n_averages[f] - 1) / _n_averages[f]) * _est.row(f) +
|
||||||
temp.row(f) / _n_averages[f];
|
temp.row(f) / _n_averages[f];
|
||||||
// _est.subcube(f, 0, 0, f, ncols - 1, ncols - 1) = (static_cast<d>(_n_averages[f] - 1) / _n_averages[f]) * _est.subcube(f, 0, 0, f, ncols - 1, ncols - 1) +
|
|
||||||
// temp.subcube(f, 0, 0, f, ncols - 1, ncols - 1) / _n_averages[f];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,3 +292,8 @@ ccube AvSweepPowerSpectra::get_est() const
|
|||||||
{
|
{
|
||||||
return _est;
|
return _est;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vd AvSweepPowerSpectra::get_A() const
|
||||||
|
{
|
||||||
|
return _A;
|
||||||
|
}
|
||||||
|
@ -186,6 +186,7 @@ class AvSweepPowerSpectra {
|
|||||||
d _alpha; // Only valid in case of 'Leaking'
|
d _alpha; // Only valid in case of 'Leaking'
|
||||||
us _nfft;
|
us _nfft;
|
||||||
vd _n_averages { 1, arma::fill::zeros}; // Only valid in case of 'Averaging'
|
vd _n_averages { 1, arma::fill::zeros}; // Only valid in case of 'Averaging'
|
||||||
|
vd _A; // squared amplitude envelope
|
||||||
|
|
||||||
PowerSpectra _ps;
|
PowerSpectra _ps;
|
||||||
/**
|
/**
|
||||||
@ -225,10 +226,12 @@ public:
|
|||||||
AvSweepPowerSpectra(const us nfft = 2048,
|
AvSweepPowerSpectra(const us nfft = 2048,
|
||||||
const Window::WindowType w = Window::WindowType::Hann,
|
const Window::WindowType w = Window::WindowType::Hann,
|
||||||
const d overlap_percentage = 50.,
|
const d overlap_percentage = 50.,
|
||||||
const d fs_tau = -1);
|
const d fs_tau = -1,
|
||||||
|
const vd *A = nullptr); // amplitude envelope
|
||||||
|
|
||||||
AvSweepPowerSpectra(const AvSweepPowerSpectra &) = delete;
|
AvSweepPowerSpectra(const AvSweepPowerSpectra &) = default;
|
||||||
AvSweepPowerSpectra &operator=(const AvSweepPowerSpectra &) = delete;
|
AvSweepPowerSpectra &operator=(const AvSweepPowerSpectra &) = default;
|
||||||
|
AvSweepPowerSpectra (AvSweepPowerSpectra&& ) = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reset to empty state. Clears the time buffer and sets estimator to
|
* @brief Reset to empty state. Clears the time buffer and sets estimator to
|
||||||
@ -260,6 +263,8 @@ public:
|
|||||||
* */
|
* */
|
||||||
ccube get_est() const;
|
ccube get_est() const;
|
||||||
|
|
||||||
|
vd get_A() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The overlap is rounded to a certain amount of time samples. This
|
* @brief The overlap is rounded to a certain amount of time samples. This
|
||||||
* function returns that value.
|
* function returns that value.
|
||||||
|
@ -29,27 +29,28 @@ using rte = std::runtime_error;
|
|||||||
* @param m The Python module to add classes and methods to
|
* @param m The Python module to add classes and methods to
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void init_dsp(py::module &m) {
|
void init_dsp(py::module &m)
|
||||||
|
{
|
||||||
py::class_<Fft> fft(m, "Fft");
|
py::class_<Fft> fft(m, "Fft");
|
||||||
fft.def(py::init<us>());
|
fft.def(py::init<us>());
|
||||||
fft.def("fft", [](Fft &f, dpyarray dat) {
|
fft.def("fft", [](Fft &f, dpyarray dat)
|
||||||
|
{
|
||||||
if (dat.ndim() == 1) {
|
if (dat.ndim() == 1) {
|
||||||
return ColToNpy<c>(f.fft(NpyToCol<d, false>(dat)));
|
return ColToNpy<c>(f.fft(NpyToCol<d, false>(dat)));
|
||||||
} else if (dat.ndim() == 2) {
|
} else if (dat.ndim() == 2) {
|
||||||
return MatToNpy<c>(f.fft(NpyToMat<d, false>(dat)));
|
return MatToNpy<c>(f.fft(NpyToMat<d, false>(dat)));
|
||||||
} else {
|
} else {
|
||||||
throw rte("Invalid dimensions of array");
|
throw rte("Invalid dimensions of array");
|
||||||
}
|
} });
|
||||||
});
|
fft.def("ifft", [](Fft &f, cpyarray dat)
|
||||||
fft.def("ifft", [](Fft &f, cpyarray dat) {
|
{
|
||||||
if (dat.ndim() == 1) {
|
if (dat.ndim() == 1) {
|
||||||
return ColToNpy<d>(f.ifft(NpyToCol<c, false>(dat)));
|
return ColToNpy<d>(f.ifft(NpyToCol<c, false>(dat)));
|
||||||
} else if (dat.ndim() == 2) {
|
} else if (dat.ndim() == 2) {
|
||||||
return MatToNpy<d>(f.ifft(NpyToMat<c, false>(dat)));
|
return MatToNpy<d>(f.ifft(NpyToMat<c, false>(dat)));
|
||||||
} else {
|
} else {
|
||||||
throw rte("Invalid dimensions of array");
|
throw rte("Invalid dimensions of array");
|
||||||
}
|
} });
|
||||||
});
|
|
||||||
|
|
||||||
fft.def_static("load_fft_wisdom", &Fft::load_fft_wisdom);
|
fft.def_static("load_fft_wisdom", &Fft::load_fft_wisdom);
|
||||||
fft.def_static("store_fft_wisdom", &Fft::store_fft_wisdom);
|
fft.def_static("store_fft_wisdom", &Fft::store_fft_wisdom);
|
||||||
@ -71,41 +72,39 @@ void init_dsp(py::module &m) {
|
|||||||
/// SeriesBiquad
|
/// SeriesBiquad
|
||||||
py::class_<SeriesBiquad, std::shared_ptr<SeriesBiquad>> sbq(m, "SeriesBiquad",
|
py::class_<SeriesBiquad, std::shared_ptr<SeriesBiquad>> sbq(m, "SeriesBiquad",
|
||||||
filter);
|
filter);
|
||||||
sbq.def(py::init([](dpyarray filter) {
|
sbq.def(py::init([](dpyarray filter)
|
||||||
return std::make_shared<SeriesBiquad>(NpyToCol<d, false>(filter));
|
{ return std::make_shared<SeriesBiquad>(NpyToCol<d, false>(filter)); }));
|
||||||
}));
|
sbq.def("filter", [](SeriesBiquad &s, dpyarray input)
|
||||||
sbq.def("filter", [](SeriesBiquad &s, dpyarray input) {
|
{
|
||||||
vd res = NpyToCol<d, true>(input);
|
vd res = NpyToCol<d, true>(input);
|
||||||
s.filter(res);
|
s.filter(res);
|
||||||
return ColToNpy<d>(res);
|
return ColToNpy<d>(res); });
|
||||||
});
|
|
||||||
|
|
||||||
/// BiquadBank
|
/// BiquadBank
|
||||||
py::class_<BiquadBank, Filter, std::shared_ptr<BiquadBank>> bqb(m,
|
py::class_<BiquadBank, Filter, std::shared_ptr<BiquadBank>> bqb(m,
|
||||||
"BiquadBank");
|
"BiquadBank");
|
||||||
bqb.def(py::init([](dpyarray coefs) {
|
bqb.def(py::init([](dpyarray coefs)
|
||||||
return std::make_shared<BiquadBank>(NpyToMat<d, false>(coefs));
|
{ return std::make_shared<BiquadBank>(NpyToMat<d, false>(coefs)); }));
|
||||||
}));
|
bqb.def(py::init([](dpyarray coefs, dpyarray gains)
|
||||||
bqb.def(py::init([](dpyarray coefs, dpyarray gains) {
|
{
|
||||||
vd gains_arma = NpyToMat<d, false>(gains);
|
vd gains_arma = NpyToMat<d, false>(gains);
|
||||||
return std::make_shared<BiquadBank>(NpyToMat<d, false>(coefs), &gains_arma);
|
return std::make_shared<BiquadBank>(NpyToMat<d, false>(coefs), &gains_arma); }));
|
||||||
}));
|
|
||||||
|
|
||||||
bqb.def("setGains",
|
bqb.def("setGains",
|
||||||
[](BiquadBank &b, dpyarray gains) { b.setGains(NpyToCol(gains)); });
|
[](BiquadBank &b, dpyarray gains)
|
||||||
bqb.def("filter", [](BiquadBank &b, dpyarray input) {
|
{ b.setGains(NpyToCol(gains)); });
|
||||||
|
bqb.def("filter", [](BiquadBank &b, dpyarray input)
|
||||||
|
{
|
||||||
// Yes, a copy here
|
// Yes, a copy here
|
||||||
vd inout = NpyToCol<d, true>(input);
|
vd inout = NpyToCol<d, true>(input);
|
||||||
b.filter(inout);
|
b.filter(inout);
|
||||||
return ColToNpy(inout);
|
return ColToNpy(inout); });
|
||||||
});
|
|
||||||
|
|
||||||
/// PowerSpectra
|
/// PowerSpectra
|
||||||
py::class_<PowerSpectra> ps(m, "PowerSpectra");
|
py::class_<PowerSpectra> ps(m, "PowerSpectra");
|
||||||
ps.def(py::init<const us, const Window::WindowType>());
|
ps.def(py::init<const us, const Window::WindowType>());
|
||||||
ps.def("compute", [](PowerSpectra &ps, dpyarray input) {
|
ps.def("compute", [](PowerSpectra &ps, dpyarray input)
|
||||||
return CubeToNpy<c>(ps.compute(NpyToMat<d, false>(input)));
|
{ return CubeToNpy<c>(ps.compute(NpyToMat<d, false>(input))); });
|
||||||
});
|
|
||||||
|
|
||||||
/// AvPowerSpectra
|
/// AvPowerSpectra
|
||||||
py::class_<AvPowerSpectra> aps(m, "AvPowerSpectra");
|
py::class_<AvPowerSpectra> aps(m, "AvPowerSpectra");
|
||||||
@ -114,7 +113,8 @@ void init_dsp(py::module &m) {
|
|||||||
py::arg("windowType") = Window::WindowType::Hann,
|
py::arg("windowType") = Window::WindowType::Hann,
|
||||||
py::arg("overlap_percentage") = 50.0, py::arg("time_constant") = -1);
|
py::arg("overlap_percentage") = 50.0, py::arg("time_constant") = -1);
|
||||||
|
|
||||||
aps.def("compute", [](AvPowerSpectra &aps, dpyarray timedata) {
|
aps.def("compute", [](AvPowerSpectra &aps, dpyarray timedata)
|
||||||
|
{
|
||||||
std::optional<ccube> res;
|
std::optional<ccube> res;
|
||||||
dmat timedata_mat = NpyToMat<d, false>(timedata);
|
dmat timedata_mat = NpyToMat<d, false>(timedata);
|
||||||
{
|
{
|
||||||
@ -122,22 +122,36 @@ void init_dsp(py::module &m) {
|
|||||||
res = aps.compute(timedata_mat);
|
res = aps.compute(timedata_mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CubeToNpy<c>(res.value_or(ccube(0, 0, 0)));
|
return CubeToNpy<c>(res.value_or(ccube(0, 0, 0))); });
|
||||||
});
|
aps.def("get_est", [](const AvPowerSpectra &ps)
|
||||||
aps.def("get_est", [](const AvPowerSpectra &ps) {
|
{
|
||||||
ccube est = ps.get_est();
|
ccube est = ps.get_est();
|
||||||
return CubeToNpy<c>(est);
|
return CubeToNpy<c>(est); });
|
||||||
});
|
|
||||||
|
|
||||||
/// AvSweepPowerSpectra
|
/// AvSweepPowerSpectra
|
||||||
py::class_<AvSweepPowerSpectra> asps(m, "AvSweepPowerSpectra");
|
py::class_<AvSweepPowerSpectra, std::unique_ptr<AvSweepPowerSpectra>> asps(m, "AvSweepPowerSpectra");
|
||||||
asps.def(py::init<const us, const Window::WindowType, const d, const d>(),
|
asps.def(py::init([](const us nfft,
|
||||||
py::arg("nfft") = 2048,
|
const Window::WindowType windowtype,
|
||||||
py::arg("windowType") = Window::WindowType::Hann,
|
const d overlap_percentage,
|
||||||
py::arg("overlap_percentage") = 50.0,
|
const d time_constant,
|
||||||
py::arg("time_constant") = -1);
|
const dpyarray A)
|
||||||
|
{
|
||||||
|
std::unique_ptr<vd> theA = std::make_unique<vd>(NpyToCol<d, false>(A));
|
||||||
|
|
||||||
asps.def("compute", [](AvSweepPowerSpectra &asps, dpyarray timedata) {
|
return std::make_unique<AvSweepPowerSpectra>(
|
||||||
|
nfft,
|
||||||
|
windowtype,
|
||||||
|
overlap_percentage,
|
||||||
|
time_constant,
|
||||||
|
theA.get());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
asps.def("compute", [](AvSweepPowerSpectra &asps, dpyarray timedata)
|
||||||
|
{
|
||||||
std::optional<ccube> res;
|
std::optional<ccube> res;
|
||||||
dmat timedata_mat = NpyToMat<d, false>(timedata);
|
dmat timedata_mat = NpyToMat<d, false>(timedata);
|
||||||
{
|
{
|
||||||
@ -145,44 +159,60 @@ void init_dsp(py::module &m) {
|
|||||||
res = asps.compute(timedata_mat);
|
res = asps.compute(timedata_mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CubeToNpy<c>(res.value_or(ccube(0, 0, 0)));
|
return CubeToNpy<c>(res.value_or(ccube(0, 0, 0))); });
|
||||||
});
|
asps.def("get_est", [](const AvSweepPowerSpectra &sps)
|
||||||
asps.def("get_est", [](const AvSweepPowerSpectra &sps) {
|
{
|
||||||
ccube est = sps.get_est();
|
ccube est = sps.get_est();
|
||||||
return CubeToNpy<c>(est);
|
return CubeToNpy<c>(est); });
|
||||||
});
|
|
||||||
|
asps.def("get_A", [](const AvSweepPowerSpectra &sps)
|
||||||
|
{
|
||||||
|
vd A = sps.get_A();
|
||||||
|
return ColToNpy<d>(A); });
|
||||||
|
|
||||||
py::class_<SLM> slm(m, "cppSLM");
|
py::class_<SLM> slm(m, "cppSLM");
|
||||||
|
|
||||||
slm.def_static("fromBiquads", [](const d fs, const d Lref, const us ds,
|
slm.def_static("fromBiquads", [](const d fs, const d Lref, const us ds,
|
||||||
const d tau, dpyarray bandpass) {
|
const d tau, dpyarray bandpass)
|
||||||
return SLM::fromBiquads(fs, Lref, ds, tau, NpyToMat<d, false>(bandpass));
|
{
|
||||||
});
|
return SLM::fromBiquads(fs, Lref, ds, tau, NpyToMat<d, false>(bandpass)); });
|
||||||
|
|
||||||
slm.def_static("fromBiquads", [](const d fs, const d Lref, const us ds,
|
slm.def_static("fromBiquads", [](const d fs, const d Lref, const us ds,
|
||||||
const d tau, dpyarray prefilter,
|
const d tau, dpyarray prefilter,
|
||||||
py::array_t<d> bandpass) {
|
py::array_t<d> bandpass)
|
||||||
|
{
|
||||||
return SLM::fromBiquads(fs, Lref, ds, tau, NpyToCol<d, false>(prefilter),
|
return SLM::fromBiquads(fs, Lref, ds, tau, NpyToCol<d, false>(prefilter),
|
||||||
NpyToMat<d, false>(bandpass));
|
NpyToMat<d, false>(bandpass)); });
|
||||||
});
|
|
||||||
|
|
||||||
slm.def("run", [](SLM &slm, dpyarray in) {
|
slm.def("run", [](SLM &slm, dpyarray in)
|
||||||
return MatToNpy<d>(slm.run(NpyToCol<d, false>(in)));
|
{
|
||||||
});
|
return MatToNpy<d>(slm.run(NpyToCol<d, false>(in))); });
|
||||||
slm.def("Pm", [](const SLM &slm) { return ColToNpy<d>(slm.Pm); });
|
slm.def("Pm", [](const SLM &slm)
|
||||||
slm.def("Pmax", [](const SLM &slm) { return ColToNpy<d>(slm.Pmax); });
|
{
|
||||||
slm.def("Ppeak", [](const SLM &slm) { return ColToNpy<d>(slm.Ppeak); });
|
return ColToNpy<d>(slm.Pm); });
|
||||||
|
slm.def("Pmax", [](const SLM &slm)
|
||||||
|
{
|
||||||
|
return ColToNpy<d>(slm.Pmax); });
|
||||||
|
slm.def("Ppeak", [](const SLM &slm)
|
||||||
|
{
|
||||||
|
return ColToNpy<d>(slm.Ppeak); });
|
||||||
|
|
||||||
slm.def("Leq", [](const SLM &slm) { return ColToNpy<d>(slm.Leq()); });
|
slm.def("Leq", [](const SLM &slm)
|
||||||
slm.def("Lmax", [](const SLM &slm) { return ColToNpy<d>(slm.Lmax()); });
|
{
|
||||||
slm.def("Lpeak", [](const SLM &slm) { return ColToNpy<d>(slm.Lpeak()); });
|
return ColToNpy<d>(slm.Leq()); });
|
||||||
|
slm.def("Lmax", [](const SLM &slm)
|
||||||
|
{
|
||||||
|
return ColToNpy<d>(slm.Lmax()); });
|
||||||
|
slm.def("Lpeak", [](const SLM &slm)
|
||||||
|
{
|
||||||
|
return ColToNpy<d>(slm.Lpeak()); });
|
||||||
slm.def_static("suggestedDownSamplingFac", &SLM::suggestedDownSamplingFac);
|
slm.def_static("suggestedDownSamplingFac", &SLM::suggestedDownSamplingFac);
|
||||||
|
|
||||||
// Frequency smoother
|
// Frequency smoother
|
||||||
m.def("freqSmooth", [](dpyarray freq, dpyarray X, unsigned w) {
|
m.def("freqSmooth", [](dpyarray freq, dpyarray X, unsigned w)
|
||||||
|
{
|
||||||
vd freqa = NpyToCol<d, false>(freq);
|
vd freqa = NpyToCol<d, false>(freq);
|
||||||
vd Xa = NpyToCol<d, false>(X);
|
vd Xa = NpyToCol<d, false>(X);
|
||||||
return ColToNpy(freqSmooth(freqa, Xa, w));
|
return ColToNpy(freqSmooth(freqa, Xa, w)); });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@ -19,6 +19,9 @@ from .lasp_cpp import Window, DaqChannel, AvPowerSpectra, AvSweepPowerSpectra
|
|||||||
from typing import List
|
from typing import List
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from .lasp_config import ones
|
from .lasp_config import ones
|
||||||
|
|
||||||
|
from scipy.interpolate import CubicSpline
|
||||||
|
|
||||||
"""!
|
"""!
|
||||||
Author: J.A. de Jong - ASCEE
|
Author: J.A. de Jong - ASCEE
|
||||||
|
|
||||||
@ -842,10 +845,15 @@ class Measurement:
|
|||||||
|
|
||||||
nchannels = len(channels)
|
nchannels = len(channels)
|
||||||
|
|
||||||
# aps = AvPowerSpectra(nfft, window, overlap)
|
|
||||||
aps = AvSweepPowerSpectra(nfft, window, overlap)
|
|
||||||
freq = getFreq(self.samplerate, nfft)
|
freq = getFreq(self.samplerate, nfft)
|
||||||
|
|
||||||
|
if self._siggen['Type'] == 'Sweep':
|
||||||
|
iA = CubicSpline(self._siggen['Data']['fA'], self._siggen['Data']['A'])
|
||||||
|
|
||||||
|
aps = AvSweepPowerSpectra(nfft, window, overlap, -1, iA(freq))
|
||||||
|
else:
|
||||||
|
aps = AvPowerSpectra(nfft, window, overlap)
|
||||||
|
|
||||||
for data in self.iterData(channels, **kwargs):
|
for data in self.iterData(channels, **kwargs):
|
||||||
CS = aps.compute(data)
|
CS = aps.compute(data)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user