Add config option RATE, update option descriptions..
This commit is contained in:
@@ -39,7 +39,7 @@ record(waveform,"$(P)Plugin-FFT${INDEX}-Spectrum-Amp-Act"){
|
||||
field(DESC, "FFT spectrum amplitude result")
|
||||
field(PINI, "1")
|
||||
field(DTYP, "asynFloat64ArrayIn")
|
||||
field(INP, "@asyn($(PORT),$(ADDR=0=),$(TIMEOUT=1000=1))T_SMP_MS=$(T_SMP_MS=1000)/TYPE=asynFloat64ArrayIn/plugin.fft${INDEX}.fftamplitude?")
|
||||
field(INP, "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1000))T_SMP_MS=$(T_SMP_MS=1000)/TYPE=asynFloat64ArrayIn/plugin.fft${INDEX}.fftamplitude?")
|
||||
field(FTVL, "DOUBLE")
|
||||
field(NELM, "$(NELM)")
|
||||
field(SCAN, "I/O Intr")
|
||||
@@ -71,7 +71,7 @@ record(longout,"$(P)Plugin-FFT${INDEX}-Mode-RB"){
|
||||
field(PINI, "1")
|
||||
field(TSE, -2)
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(ADDR=0=0),$(TIMEOUT=1000=0))T_SMP_MS=$(T_SMP_MS=1000)/TYPE=asynInt32/plugin.fft${INDEX}.mode=")
|
||||
field(OUT, "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1000))T_SMP_MS=$(T_SMP_MS=1000)/TYPE=asynInt32/plugin.fft${INDEX}.mode=")
|
||||
field(SCAN, "Passive")
|
||||
field(TSE, "$(TSE=0)")
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
// New data callback from ecmc
|
||||
static int printMissingObjError = 1;
|
||||
|
||||
/** This callback will not be used (sample data inteface is used instead to get an stable sample freq)
|
||||
since the callback is called when data is updated it might */
|
||||
void f_dataUpdatedCallback(uint8_t* data, size_t size, ecmcEcDataType dt, void* obj) {
|
||||
if(!obj) {
|
||||
if(printMissingObjError){
|
||||
@@ -58,6 +60,7 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
|
||||
cfgDataSourceStr_ = NULL;
|
||||
dataBuffer_ = NULL;
|
||||
dataItem_ = NULL;
|
||||
dataItemInfo_ = NULL;
|
||||
fftDouble_ = NULL;
|
||||
asynPort_ = NULL;
|
||||
asynEnable_ = NULL; // Enable
|
||||
@@ -74,6 +77,12 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
|
||||
objectId_ = fftIndex;
|
||||
scale_ = 1.0;
|
||||
triggOnce_ = 0;
|
||||
cycleCounter_ = 0;
|
||||
ignoreCycles_ = 0;
|
||||
|
||||
ecmcSampleRateHz_ = getEcmcSampleRate();
|
||||
cfgFFTSampleRateHz_ = ecmcSampleRateHz_;
|
||||
|
||||
// Config defaults
|
||||
cfgDbgMode_ = 0;
|
||||
cfgNfft_ = ECMC_PLUGIN_DEFAULT_NFFT; // samples in fft (must be n^2)
|
||||
@@ -92,6 +101,20 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
|
||||
if(cfgNfft_ <= 0) {
|
||||
throw std::out_of_range("NFFT must be > 0 and even N^2.");
|
||||
}
|
||||
|
||||
// Check valid sample rate
|
||||
if(cfgFFTSampleRateHz_ <= 0) {
|
||||
throw std::out_of_range("FFT Invalid sample rate");
|
||||
}
|
||||
if(cfgFFTSampleRateHz_ > ecmcSampleRateHz_) {
|
||||
printf("Warning FFT sample rate faster than ecmc rate. FFT rate will be set to ecmc rate.\n");
|
||||
cfgFFTSampleRateHz_ = ecmcSampleRateHz_;
|
||||
}
|
||||
|
||||
// Se if any data update cycles should be ignored
|
||||
// example ecmc 1000Hz, fft 100Hz then ignore 9 cycles (could be strange if not multiples)
|
||||
ignoreCycles_ = ecmcSampleRateHz_ / cfgFFTSampleRateHz_ -1;
|
||||
|
||||
// set scale factor
|
||||
scale_ = 1.0 / cfgNfft_; // sqrt((double)cfgNfft_);
|
||||
|
||||
@@ -185,6 +208,12 @@ void ecmcFFT::parseConfigStr(char *configStr) {
|
||||
}
|
||||
}
|
||||
|
||||
// ECMC_PLUGIN_RATE_OPTION_CMD rate in HZ
|
||||
else if (!strncmp(pThisOption, ECMC_PLUGIN_RATE_OPTION_CMD, strlen(ECMC_PLUGIN_RATE_OPTION_CMD))) {
|
||||
pThisOption += strlen(ECMC_PLUGIN_RATE_OPTION_CMD);
|
||||
cfgFFTSampleRateHz_ = atof(pThisOption);
|
||||
}
|
||||
|
||||
pThisOption = pNextOption;
|
||||
}
|
||||
free(pOptions);
|
||||
@@ -202,6 +231,8 @@ void ecmcFFT::connectToDataSource() {
|
||||
if(!dataItem_) {
|
||||
throw std::runtime_error( "Data item NULL." );
|
||||
}
|
||||
|
||||
dataItemInfo_ = dataItem_->getDataItemInfo();
|
||||
|
||||
// Register data callback
|
||||
callbackHandle_ = dataItem_->regDataUpdatedCallback(f_dataUpdatedCallback, this);
|
||||
@@ -220,10 +251,19 @@ void ecmcFFT::connectToDataSource() {
|
||||
void ecmcFFT::dataUpdatedCallback(uint8_t* data,
|
||||
size_t size,
|
||||
ecmcEcDataType dt) {
|
||||
|
||||
// No buffer or full or not enabled
|
||||
if(!dataBuffer_ || !cfgEnable_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// See if data should be ignored
|
||||
if(cycleCounter_ < ignoreCycles_) {
|
||||
cycleCounter_++;
|
||||
return; // ignore this callback
|
||||
}
|
||||
cycleCounter_ = 0;
|
||||
|
||||
if (cfgMode_ == TRIGG && !triggOnce_ ) {
|
||||
updateStatus(IDLE);
|
||||
return; // Wait for trigger from plc or asyn
|
||||
@@ -718,3 +758,12 @@ void ecmcFFT::updateStatus(FFT_STATUS status) {
|
||||
status_ = status;
|
||||
asynFFTStat_->refreshParamRT(1);
|
||||
}
|
||||
|
||||
// Do nut use this as same time as callback!
|
||||
void ecmcFFT::sampleData() {
|
||||
|
||||
dataUpdatedCallback(dataItemInfo_->data,
|
||||
dataItemInfo_->dataSize,
|
||||
dataItemInfo_->dataType);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,10 @@ class ecmcFFT {
|
||||
FFT_STATUS getStatusFFT();
|
||||
void clearBuffers();
|
||||
void triggFFT();
|
||||
|
||||
/** Do not use this as same time as callback!
|
||||
* if used it should be called from ecmc realtime callback*/
|
||||
void sampleData();
|
||||
|
||||
private:
|
||||
void parseConfigStr(char *configStr);
|
||||
@@ -57,29 +61,33 @@ class ecmcFFT {
|
||||
static int dataTypeSupported(ecmcEcDataType dt);
|
||||
|
||||
ecmcDataItem *dataItem_;
|
||||
ecmcDataItemInfo *dataItemInfo_;
|
||||
ecmcAsynPortDriver *asynPort_;
|
||||
kissfft<double>* fftDouble_;
|
||||
double* dataBuffer_; // Input data (real)
|
||||
std::complex<double>* fftBuffer_; // Result (complex)
|
||||
double* fftBufferAmp_; // Resulting amplitude (abs of fftBuffer_)
|
||||
size_t elementsInBuffer_;
|
||||
double ecmcSampleRateHz_;
|
||||
// ecmc callback handle for use when deregister at unload
|
||||
int callbackHandle_;
|
||||
int fftCalcDone_;
|
||||
int objectId_; // Unique object id
|
||||
int triggOnce_;
|
||||
int cycleCounter_;
|
||||
int ignoreCycles_;
|
||||
double scale_; // Config: Data set size
|
||||
FFT_STATUS status_; // Status/state (NO_STAT, IDLE, ACQ, CALC)
|
||||
|
||||
// Config options
|
||||
char* cfgDataSourceStr_; // Config: data source string
|
||||
int cfgDbgMode_; // Config: allow dbg printouts
|
||||
int cfgApplyScale_; // Config: apply scale 1/nfft
|
||||
int cfgDcRemove_; // Config: remove dc (average)
|
||||
size_t cfgNfft_; // Config: Data set size
|
||||
int cfgEnable_; // Config: Enable data acq./calc.
|
||||
FFT_MODE cfgMode_; // Config: Mode continous or triggered.
|
||||
|
||||
char* cfgDataSourceStr_; // Config: data source string
|
||||
int cfgDbgMode_; // Config: allow dbg printouts
|
||||
int cfgApplyScale_; // Config: apply scale 1/nfft
|
||||
int cfgDcRemove_; // Config: remove dc (average)
|
||||
size_t cfgNfft_; // Config: Data set size
|
||||
int cfgEnable_; // Config: Enable data acq./calc.
|
||||
FFT_MODE cfgMode_; // Config: Mode continous or triggered.
|
||||
double cfgFFTSampleRateHz_; // Config: Sample rate (defaukts to ecmc rate)
|
||||
|
||||
// Asyn
|
||||
ecmcAsynDataItem* asynEnable_; // Enable/disable acq./calcs
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD "APPLY_SCALE="
|
||||
#define ECMC_PLUGIN_DC_REMOVE_OPTION_CMD "DC_REMOVE="
|
||||
#define ECMC_PLUGIN_ENABLE_OPTION_CMD "ENABLE="
|
||||
#define ECMC_PLUGIN_RATE_OPTION_CMD "RATE="
|
||||
// CONT, TRIGG
|
||||
#define ECMC_PLUGIN_MODE_OPTION_CMD "MODE="
|
||||
#define ECMC_PLUGIN_MODE_CONT_OPTION "CONT"
|
||||
|
||||
@@ -122,3 +122,18 @@ FFT_STATUS statFFT(int fftIndex) {
|
||||
return NO_STAT;
|
||||
}
|
||||
|
||||
int sampleFFTs() {
|
||||
for(std::vector<ecmcFFT*>::iterator pfft = ffts.begin(); pfft != ffts.end(); ++pfft) {
|
||||
if(*pfft) {
|
||||
try {
|
||||
(*pfft)->sampleData();
|
||||
}
|
||||
catch(std::exception& e) {
|
||||
printf("Exception: %s. Plugin will unload.\n",e.what());
|
||||
return ECMC_PLUGIN_FFT_ERROR_CODE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,12 @@ int triggFFT(int fftIndex);
|
||||
*/
|
||||
FFT_STATUS statFFT(int fftIndex);
|
||||
|
||||
/** \brief Sample data in all FFT objects
|
||||
*
|
||||
* This function should be executed in the realtime callback from ecmc.\
|
||||
*/
|
||||
int sampleFFTs();
|
||||
|
||||
/** \brief Link data to _all_ fft objects
|
||||
*
|
||||
* This tells the FFT lib to connect to ecmc to find it's data source.\n
|
||||
|
||||
@@ -61,9 +61,10 @@ void fftDestruct(void)
|
||||
* Return value other than 0 will be considered to be an error code in ecmc.
|
||||
**/
|
||||
int fftRealtime(int ecmcError)
|
||||
{
|
||||
{
|
||||
lastEcmcError = ecmcError;
|
||||
return 0;
|
||||
// Let all fft:s sample data
|
||||
return 0; // sampleFFTs(); Use callback instead
|
||||
}
|
||||
|
||||
/** Link to data source here since all sources should be availabe at this stage
|
||||
@@ -115,13 +116,14 @@ struct ecmcPluginData pluginDataDef = {
|
||||
// Description
|
||||
.desc = "FFT plugin for use with ecmc.",
|
||||
// Option description
|
||||
.optionDesc = "\n "ECMC_PLUGIN_DBG_OPTION_CMD"<1/0> : Enables/disables printouts from plugin.\n"
|
||||
" "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.\n"
|
||||
" "ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD"<1/0> : Apply scale.\n"
|
||||
" "ECMC_PLUGIN_DC_REMOVE_OPTION_CMD"<1/0> : Remove DC offset of input data (SOURCE).\n"
|
||||
" "ECMC_PLUGIN_ENABLE_OPTION_CMD"<1/0> : Enable data acq. and calcs (can be controlled over asyn)."
|
||||
" "ECMC_PLUGIN_MODE_OPTION_CMD"<CONT/TRIGG> : Continious or triggered mode."
|
||||
.optionDesc = "\n "ECMC_PLUGIN_DBG_OPTION_CMD"<1/0> : Enables/disables printouts from plugin, default = disabled.\n"
|
||||
" "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, defaults to disabled.\n"
|
||||
" "ECMC_PLUGIN_DC_REMOVE_OPTION_CMD"<1/0> : Remove DC offset of input data (SOURCE), 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."
|
||||
,
|
||||
// Plugin version
|
||||
.version = ECMC_EXAMPLE_PLUGIN_VERSION,
|
||||
|
||||
Reference in New Issue
Block a user