10 Commits

Author SHA1 Message Date
anderssandstrom
db67919b85 Update README.md 2020-04-24 15:43:02 +02:00
Anders Sandström
07385b261a Add description of RM_LIN conf. 2020-04-24 15:40:20 +02:00
Anders Sandström
375e5e7b21 Add wavefor record for preprocessed data array. 2020-04-24 15:08:20 +02:00
Anders Sandström
85b231537b Logic added but not tested. 2020-04-24 14:53:39 +02:00
Anders Sandström
24fd9bbb3d Add RM_LIN config. No real code yet. 2020-04-24 13:37:26 +02:00
Anders Sandström
4df1650541 Update from remote 2020-04-24 13:28:33 +02:00
Anders Sandström
0989b969ba Rename DC_REMOVE to RM_DC 2020-04-24 13:26:32 +02:00
anderssandstrom
c40fdcfabc Update README.md 2020-04-10 19:12:29 +02:00
anderssandstrom
4c8edccfb8 Update README.md 2020-04-10 19:11:38 +02:00
anderssandstrom
a136c5f4b2 Update README.md 2020-04-09 10:33:23 +02:00
6 changed files with 168 additions and 30 deletions

View File

@@ -10,6 +10,10 @@ Configuration is made through ecmccfg:
https://github.com/paulscherrerinstitute/ecmccfg (ot local ess fork https://github.com/icshwi/ecmccfg)
FFT:s are calculated with the kissfft lib:
https://github.com/mborgerding/kissfft
# Introduction
The main functionality of this plugin is to make FFT analysis of ecmc data. Most data in ecmc is accessible:
@@ -29,7 +33,7 @@ https://github.com/icshwi/ecmccfg/blob/master/scripts/loadPlugin.cmd
Example:
```
${SCRIPTEXEC} ${ecmccfg_DIR}loadPlugin.cmd, "PLUGIN_ID=0,FILE=libecmcPlugin_FFT.so,CONFIG='DBG_PRINT=1;SOURCE=ax1.actpos;', REPORT=1
${SCRIPTEXEC} ${ecmccfg_DIR}loadPlugin.cmd, "PLUGIN_ID=0,FILE=libecmcPlugin_FFT.so,CONFIG='DBG_PRINT=1;SOURCE=ax1.actpos;RM_LIN=1;', REPORT=1
dbLoadRecords(ecmcPluginFFT.template,"P=$(IOC):,INDEX=0, NELM=${FFT_NELM}")
```
This plugin supports multiple loading. For each load of the plugin a new FFT object will be created. In order to access these plugins, from plc:s or EPICS records, they can be accessed by an index. The first FFT plugin will have index 0. The next loaded FFT plugin will have index 1...
@@ -41,25 +45,26 @@ Note: If another plugin is loaded in between the loading of FFT plugins, it will
The different available configuration settings:
* SOURCE= source variable : Sets source variable for FFT (example: ec0.s1.AI_1). This config is mandatory.
* DBG_PRINT=1/0 : Enables/disables printouts from plugin, default = disabled.
* NFFT= nfft : Data points to collect, default = 4096.
* NFFT= nfft : Data points to collect, default = 4096.
* APPLY_SCALE=1/0 : Apply scale, default = enabled.
* DC_REMOVE=1/0 : Remove DC offset of input data (SOURCE), default = disabled.
* RM_DC=1/0 : Remove DC offset of input data (SOURCE), default = disabled.
* RM_LIN=1/0 : Remove linear component input data (SOURCE), default = disabled.
* ENABLE=1/0 : Enable data acq. and calcs (can be controlled over asyn), default = disabled.
* MODE=CONT/TRIGG : Continious or triggered mode, defaults to TRIGG
* RATE=rate in hz : fft data sample rate in hz (must be lower than ecmc rate and (ecmc_rate/fft_rate)=integer), default = ecmc rate.
Example configuration string:
```
"SOURCE=ax1.actpos;MODE=TRIGG;DBG_PRINT=1;ENABLE=1;"
"SOURCE=ax1.poserr;MODE=TRIGG;DBG_PRINT=1;ENABLE=1;"
```
#### SOURCE (mandatory)
The data source is defined by setting the SOURCE option in the plugin configuration string.
This configuration is mandatory.
Example: Axis 1 actpos
Example: Axis 1 actpos (See RM_LIN config below)
```
"DBG_PRINT=1;SOURCE=ax1.actpos;"
"DBG_PRINT=1;SOURCE=ax1.actpos;RM_LIN=1;"
```
Example: Ethercat slave 1 analog input ch1
@@ -71,7 +76,7 @@ Enable/disable printouts from plugin can be made bu setting the "DBG_PRINT" opti
Exmaple: Disable
```
"DBG_PRINT=0;SOURCE=ax1.actpos;"
"DBG_PRINT=0;SOURCE=ax1.poserr;"
```
#### NFFT (default: 4096)
@@ -81,29 +86,38 @@ Note: Must be a n² number..
Exmaple: 1024
```
"NFFT=1024;DBG_PRINT=0;SOURCE=ax1.actpos;"
"NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
#### APPLY_SCALE (default disabled)
Apply scaling in order to get correct amplitude of fft. Disabled as default (lower cpu usage).
Exmaple: Enable
```
"APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.actpos;"
"APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
### RM_DC
Remove DC of input signal. Default is disabled.
#### DC_REMOVE (default: disabled)
Remove DC of input signal by substracting average of input signal. This can be usefull if low frequencies are of intresst since the DC component normally distorts the spectrum near 0Hz.
Exmaple: Enable
Exmaple: Remove DC offset
```
"DC_REMOVE=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.actpos;"
"RM_DC=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
### RM_LIN
Remove linear component of input signal. Default is disabled.
The linear component is calculated by least square method.
Could be usefull for values that increase, like actual position.
Exmaple: Remove linear component
```
"RM_LIN=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
#### ENABLE (default: disabled)
Enable data acq. and FFT calcs. The default settings is disabled so needs to be enabled from plc or over asyn in order to start calculations.
Exmaple: Enable at startup by config
```
"ENABLE=1;DC_REMOVE=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.actpos;"
"ENABLE=1;RM_DC=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
Exmaple: Enable FFT index 0 from EPICS:
```
@@ -140,7 +154,7 @@ Triggered mode:
Exmaple: Mode triggered
```
"MODE=TRIGG;ENABLE=1;DC_REMOVE=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.actpos;"
"MODE=TRIGG;ENABLE=1;RM_DC=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
Exmaple: Mode from EPICS record
```
@@ -157,7 +171,7 @@ Note: only a lower and "integer" division of sample rate can be defined.
Exmaple: Rate = 100Hz
```
RATE=100;MODE=TRIGG;ENABLE=1;DC_REMOVE=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.actpos;"
RATE=100;MODE=TRIGG;ENABLE=1;RM_DC=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
## EPICS records
Each FFT plugin object will create a new asynportdriver-port named "PLUGIN.FFT<index>" (index is explaine above).
@@ -248,6 +262,12 @@ Epics records:
| :---: |
|**Figure 2** Resulting FFT amplitude. |
#### ecmc PLC code for example:
```
static.time:=ec_get_time()/1E9;
static.sineval:=sin(2*pi*${FREQ=5}*static.time);
```
## Plugin info
```
@@ -260,7 +280,7 @@ Plugin info:
SOURCE=<source> : Sets source variable for FFT (example: ec0.s1.AI_1).
NFFT=<nfft> : Data points to collect, default = 4096.
APPLY_SCALE=<1/0> : Apply scale, default = disabled.
DC_REMOVE=<1/0> : Remove DC offset of input data (SOURCE), default = disabled.
RM_DC=<1/0> : Remove DC offset of input data (SOURCE), default = disabled.
ENABLE=<1/0> : Enable data acq. and calcs (can be controlled over asyn), default = disabled.
MODE=<CONT/TRIGG> : Continious or triggered mode, defaults to TRIGG
RATE=<rate in hz> : fft data sample rate in hz (must be lower than ecmc rate and (ecmc_rate/fft_rate)=integer), default = ecmc rate.

View File

@@ -33,6 +33,19 @@ record(waveform,"$(P)Plugin-FFT${INDEX}-Raw-Data-Act"){
field(TSE, "0")
}
# Pre-processed data
record(waveform,"$(P)Plugin-FFT${INDEX}-PreProc-Data-Act"){
info(asyn:FIFO, "1000")
field(DESC, "Pre-processed data")
field(PINI, "1")
field(DTYP, "asynFloat64ArrayIn")
field(INP, "@asyn(PLUGIN.FFT${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.fft${INDEX}.preprocdata")
field(FTVL, "DOUBLE")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
# FFT amplitude result
record(waveform,"$(P)Plugin-FFT${INDEX}-Spectrum-Amp-Act"){
info(asyn:FIFO, "1000")

View File

@@ -17,6 +17,7 @@
#define ECMC_PLUGIN_ASYN_PREFIX "plugin.fft"
#define ECMC_PLUGIN_ASYN_ENABLE "enable"
#define ECMC_PLUGIN_ASYN_RAWDATA "rawdata"
#define ECMC_PLUGIN_ASYN_PPDATA "preprocdata"
#define ECMC_PLUGIN_ASYN_FFT_AMP "fftamplitude"
#define ECMC_PLUGIN_ASYN_FFT_MODE "mode"
#define ECMC_PLUGIN_ASYN_FFT_STAT "status"
@@ -108,6 +109,7 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
// Asyn
asynEnableId_ = -1; // Enable/disable acq./calcs
asynRawDataId_ = -1; // Raw data (input) array (double)
asynPPDataId_ = -1; // Pre-processed data array (double)
asynFFTAmpId_ = -1; // FFT amplitude array (double)
asynFFTModeId_ = -1; // FFT mode (cont/trigg)
asynFFTStatId_ = -1; // FFT status (no_stat/idle/acq/calc)
@@ -124,6 +126,7 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
cfgDbgMode_ = 0;
cfgNfft_ = ECMC_PLUGIN_DEFAULT_NFFT; // samples in fft (must be n^2)
cfgDcRemove_ = 0;
cfgLinRemove_ = 0;
cfgApplyScale_ = 1; // Scale as default to get correct amplitude in fft
cfgEnable_ = 0; // start disabled (enable over asyn)
cfgMode_ = TRIGG;
@@ -152,6 +155,7 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
// Allocate buffers
rawDataBuffer_ = new double[cfgNfft_]; // Raw input data (real)
prepProcDataBuffer_ = new double[cfgNfft_]; // Data for preprocessing
fftBufferInput_ = new std::complex<double>[cfgNfft_]; // FFT input (complex)
fftBufferResult_ = new std::complex<double>[cfgNfft_]; // FFT result (complex)
fftBufferResultAmp_ = new double[cfgNfft_ / 2 + 1]; // FFT result amplitude (real)
@@ -178,6 +182,11 @@ ecmcFFT::~ecmcFFT() {
if(rawDataBuffer_) {
delete[] rawDataBuffer_;
}
if(prepProcDataBuffer_) {
delete[] prepProcDataBuffer_;
}
// De register callback when unload
if(callbackHandle_ >= 0) {
dataItem_->deregDataUpdatedCallback(callbackHandle_);
@@ -232,12 +241,18 @@ void ecmcFFT::parseConfigStr(char *configStr) {
cfgApplyScale_ = atoi(pThisOption);
}
// ECMC_PLUGIN_DC_REMOVE_OPTION_CMD (1/0)
else if (!strncmp(pThisOption, ECMC_PLUGIN_DC_REMOVE_OPTION_CMD, strlen(ECMC_PLUGIN_DC_REMOVE_OPTION_CMD))) {
pThisOption += strlen(ECMC_PLUGIN_DC_REMOVE_OPTION_CMD);
// ECMC_PLUGIN_RM_DC_OPTION_CMD (1/0)
else if (!strncmp(pThisOption, ECMC_PLUGIN_RM_DC_OPTION_CMD, strlen(ECMC_PLUGIN_RM_DC_OPTION_CMD))) {
pThisOption += strlen(ECMC_PLUGIN_RM_DC_OPTION_CMD);
cfgDcRemove_ = atoi(pThisOption);
}
// ECMC_PLUGIN_RM_LIN_OPTION_CMD (1/0)
else if (!strncmp(pThisOption, ECMC_PLUGIN_RM_LIN_OPTION_CMD, strlen(ECMC_PLUGIN_RM_LIN_OPTION_CMD))) {
pThisOption += strlen(ECMC_PLUGIN_RM_LIN_OPTION_CMD);
cfgLinRemove_ = atoi(pThisOption);
}
// ECMC_PLUGIN_ENABLE_OPTION_CMD (1/0)
else if (!strncmp(pThisOption, ECMC_PLUGIN_ENABLE_OPTION_CMD, strlen(ECMC_PLUGIN_ENABLE_OPTION_CMD))) {
pThisOption += strlen(ECMC_PLUGIN_ENABLE_OPTION_CMD);
@@ -393,14 +408,14 @@ void ecmcFFT::dataUpdatedCallback(uint8_t* data,
void ecmcFFT::addDataToBuffer(double data) {
if(rawDataBuffer_ && (elementsInBuffer_ < cfgNfft_) ) {
rawDataBuffer_[elementsInBuffer_] = data;
fftBufferInput_[elementsInBuffer_].real(data);
fftBufferInput_[elementsInBuffer_].imag(0);
prepProcDataBuffer_[elementsInBuffer_] = data;
}
elementsInBuffer_ ++;
}
void ecmcFFT::clearBuffers() {
memset(rawDataBuffer_, 0, cfgNfft_ * sizeof(double));
memset(prepProcDataBuffer_, 0, cfgNfft_ * sizeof(double));
memset(fftBufferResultAmp_, 0, (cfgNfft_ / 2 + 1) * sizeof(double));
memset(fftBufferXAxis_, 0, (cfgNfft_ / 2 + 1) * sizeof(double));
for(unsigned int i = 0; i < cfgNfft_; ++i) {
@@ -413,6 +428,13 @@ void ecmcFFT::clearBuffers() {
}
void ecmcFFT::calcFFT() {
// move pre-processed data to fft input buffer
for(unsigned int i = 0; i < cfgNfft_; ++i) {
fftBufferInput_[i].real(prepProcDataBuffer_[i]);
fftBufferInput_[i].imag(0);
}
// Do fft
fftDouble_->transform(fftBufferInput_, fftBufferResult_);
}
@@ -449,17 +471,36 @@ void ecmcFFT::removeDCOffset() {
return;
}
// calc average of raw data
// calc average of preprocess buffer data
double sum = 0;
for(unsigned int i = 0; i < cfgNfft_; ++i ) {
sum += fftBufferInput_[i].real();
sum += prepProcDataBuffer_[i];
}
double avg = sum / ((double)cfgNfft_);
for(unsigned int i = 0; i < cfgNfft_; ++i ) {
fftBufferInput_[i].real(fftBufferInput_[i].real()-avg);
prepProcDataBuffer_[i] = (prepProcDataBuffer_[i]-avg);
}
}
void ecmcFFT::removeLin() {
if(!cfgLinRemove_) {
return;
}
double k=0;
double m=0;
// calc least square (best fit of line)
if(leastSquare(cfgNfft_,prepProcDataBuffer_,&k,&m)) {
printf("%s/%s:%d: Error: " ECMC_PLUGIN_RM_LIN_OPTION_CMD " failed, divison by 0. Data will not be processed with the option/configuration.\n",
__FILE__, __FUNCTION__, __LINE__);
return;
}
// remove linear component (now we have k and m (y=k*x+m))
for(unsigned int x = 0; x < cfgNfft_; ++x ) {
prepProcDataBuffer_[x] = prepProcDataBuffer_[x] - (k*x + m);
}
}
void ecmcFFT::printEcDataArray(uint8_t* data,
size_t size,
@@ -683,6 +724,17 @@ void ecmcFFT::initAsyn() {
}
doCallbacksFloat64Array(rawDataBuffer_, cfgNfft_, asynRawDataId_,0);
// Add rawdata "plugin.fft%d.preprocdata"
paramName =ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
"." + ECMC_PLUGIN_ASYN_PPDATA;
if( createParam(0, paramName.c_str(), asynParamFloat64Array, &asynPPDataId_ ) != asynSuccess ) {
throw std::runtime_error("Failed create asyn parameter preprocdata");
}
doCallbacksFloat64Array(prepProcDataBuffer_, cfgNfft_, asynRawDataId_,0);
// Add fft amplitude "plugin.fft%d.fftamplitude"
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
"." + ECMC_PLUGIN_ASYN_FFT_AMP;
@@ -800,14 +852,18 @@ void ecmcFFT::doCalcWorker() {
if(destructs_) {
break;
}
// Pre-process
removeDCOffset(); // Remove dc on rawdata
removeLin(); // Remove fitted line
// Process
calcFFT(); // FFT cacluation
// Post-process
scaleFFT(); // Scale FFT
calcFFTAmp(); // Calculate amplitude from complex
calcFFTXAxis(); // Calculate x axis
doCallbacksFloat64Array(rawDataBuffer_, cfgNfft_, asynRawDataId_, 0);
doCallbacksFloat64Array(prepProcDataBuffer_, cfgNfft_, asynPPDataId_, 0);
doCallbacksFloat64Array(fftBufferResultAmp_,cfgNfft_/2+1, asynFFTAmpId_, 0);
doCallbacksFloat64Array(fftBufferXAxis_, cfgNfft_/2+1, asynFFTXAxisId_,0);
callParamCallbacks();
@@ -876,6 +932,14 @@ asynStatus ecmcFFT::readFloat64Array(asynUser *pasynUser, epicsFloat64 *value,
memcpy (value, rawDataBuffer_, ncopy);
*nIn = ncopy;
return asynSuccess;
} else if( function == asynPPDataId_) {
unsigned int ncopy = cfgNfft_;
if(nElements < ncopy) {
ncopy = nElements;
}
memcpy (value, prepProcDataBuffer_, ncopy);
*nIn = ncopy;
return asynSuccess;
} else if( function == asynFFTXAxisId_ ) {
unsigned int ncopy = cfgNfft_/ 2 + 1;
if(nElements < ncopy) {
@@ -924,3 +988,33 @@ asynStatus ecmcFFT::readFloat64(asynUser *pasynUser, epicsFloat64 *value) {
return asynError;
}
/* y = k*x+m */
int ecmcFFT::leastSquare(int n, const double y[], double* k, double* m){
double sumx = 0.0;
double sumx2 = 0.0;
double sumxy = 0.0;
double sumy = 0.0;
double sumy2 = 0.0;
for (int x = 0; x < n; ++x){
//simulate x by just index
sumx += x;
sumx2 += x * x;
sumxy += x * y[x];
sumy += y[x];
sumy2 += y[x] * y[x];
}
double denom = (n * sumx2 - sumx * sumx);
if (denom == 0) {
// Cannot dive by 0.. something wrong..
*k = 0;
*m = 0;
return 1; // Error
}
*k = (n * sumxy - sumx * sumy) / denom;
*m = (sumy * sumx2 - sumx * sumxy) / denom;
return 0;
}

View File

@@ -64,6 +64,7 @@ class ecmcFFT : public asynPortDriver {
void calcFFTAmp();
void calcFFTXAxis();
void removeDCOffset();
void removeLin();
void initAsyn();
void updateStatus(FFT_STATUS status); // Also updates asynparam
static int dataTypeSupported(ecmcEcDataType dt);
@@ -73,6 +74,7 @@ class ecmcFFT : public asynPortDriver {
ecmcAsynPortDriver *asynPort_;
kissfft<double>* fftDouble_;
double* rawDataBuffer_; // Input data (real)
double* prepProcDataBuffer_; // Preprocessed data (real)
std::complex<double>* fftBufferInput_; // Result (complex)
std::complex<double>* fftBufferResult_; // Result (complex)
double* fftBufferResultAmp_; // Resulting amplitude (abs of fftBufferResult_)
@@ -96,6 +98,7 @@ class ecmcFFT : public asynPortDriver {
int cfgDbgMode_; // Config: allow dbg printouts
int cfgApplyScale_; // Config: apply scale 1/nfft
int cfgDcRemove_; // Config: remove dc (average)
int cfgLinRemove_; // Config: remove linear componet (by least square)
size_t cfgNfft_; // Config: Data set size
int cfgEnable_; // Config: Enable data acq./calc.
FFT_MODE cfgMode_; // Config: Mode continous or triggered.
@@ -104,6 +107,7 @@ class ecmcFFT : public asynPortDriver {
// Asyn
int asynEnableId_; // Enable/disable acq./calcs
int asynRawDataId_; // Raw data (input) array (double)
int asynPPDataId_; // Pre-processed data array (double)
int asynFFTAmpId_; // FFT amplitude array (double)
int asynFFTModeId_; // FFT mode (cont/trigg)
int asynFFTStatId_; // FFT status (no_stat/idle/acq/calc)
@@ -137,6 +141,10 @@ class ecmcFFT : public asynPortDriver {
size_t elements,
int objId);
static std::string to_string(int value);
static int leastSquare(int n,
const double y[],
double* k,
double* m); // y=kx+m
};
#endif /* ECMC_FFT_H_ */

View File

@@ -19,9 +19,11 @@
#define ECMC_PLUGIN_SOURCE_OPTION_CMD "SOURCE="
#define ECMC_PLUGIN_NFFT_OPTION_CMD "NFFT="
#define ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD "APPLY_SCALE="
#define ECMC_PLUGIN_DC_REMOVE_OPTION_CMD "DC_REMOVE="
#define ECMC_PLUGIN_RM_DC_OPTION_CMD "RM_DC="
#define ECMC_PLUGIN_ENABLE_OPTION_CMD "ENABLE="
#define ECMC_PLUGIN_RATE_OPTION_CMD "RATE="
#define ECMC_PLUGIN_RM_LIN_OPTION_CMD "RM_LIN="
// CONT, TRIGG
#define ECMC_PLUGIN_MODE_OPTION_CMD "MODE="
#define ECMC_PLUGIN_MODE_CONT_OPTION "CONT"

View File

@@ -12,7 +12,7 @@
// Needed to get headers in ecmc right...
#define ECMC_IS_PLUGIN
#define ECMC_EXAMPLE_PLUGIN_VERSION 1
#define ECMC_EXAMPLE_PLUGIN_VERSION 2
#ifdef __cplusplus
extern "C" {
@@ -119,7 +119,8 @@ struct ecmcPluginData pluginDataDef = {
" "ECMC_PLUGIN_SOURCE_OPTION_CMD"<source> : Sets source variable for FFT (example: ec0.s1.AI_1).\n"
" "ECMC_PLUGIN_NFFT_OPTION_CMD"<nfft> : Data points to collect, default = 4096.\n"
" "ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD"<1/0> : Apply scale, default = disabled.\n"
" "ECMC_PLUGIN_DC_REMOVE_OPTION_CMD"<1/0> : Remove DC offset of input data (SOURCE), default = disabled.\n"
" "ECMC_PLUGIN_RM_DC_OPTION_CMD"<1/0> : Remove DC offset of input data (SOURCE), default = disabled.\n"
" "ECMC_PLUGIN_RM_LIN_OPTION_CMD"<1/0> : Remove linear component in data (SOURCE) by least square, default = disabled.\n"
" "ECMC_PLUGIN_ENABLE_OPTION_CMD"<1/0> : Enable data acq. and calcs (can be controlled over asyn), default = disabled.\n"
" "ECMC_PLUGIN_MODE_OPTION_CMD"<CONT/TRIGG> : Continious or triggered mode, defaults to TRIGG\n"
" "ECMC_PLUGIN_RATE_OPTION_CMD"<rate in hz> : fft data sample rate in hz (must be lower than ecmc rate and (ecmc_rate/fft_rate)=integer), default = ecmc rate."