Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db67919b85 | ||
|
|
07385b261a | ||
|
|
375e5e7b21 | ||
|
|
85b231537b | ||
|
|
24fd9bbb3d | ||
|
|
4df1650541 | ||
|
|
0989b969ba | ||
|
|
c40fdcfabc | ||
|
|
4c8edccfb8 | ||
|
|
a136c5f4b2 |
56
README.md
56
README.md
@@ -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.
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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."
|
||||
|
||||
Reference in New Issue
Block a user