Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 01214019a6 | |||
| 90339dae2f | |||
| d17d5d7f5d | |||
| fcee0a8ff4 | |||
|
|
a84383815d | ||
|
|
223fd94a86 | ||
|
|
96d66df11b | ||
|
|
87c8084ae0 | ||
|
|
a581ddc559 | ||
|
|
5418c98488 | ||
|
|
e6f5286836 | ||
|
|
028d56d83b | ||
|
|
ae67695c6a | ||
|
|
08542988a1 | ||
|
|
5938255f9e | ||
|
|
f49fdb2d76 | ||
|
|
b43aa23f4b | ||
|
|
f1e460e6dc | ||
|
|
d89c34d041 | ||
|
|
c8f24ca340 | ||
|
|
fd31b8957e | ||
|
|
e4e379a392 | ||
|
|
a72c764098 | ||
|
|
bdd937ad47 | ||
|
|
47f5ce247c | ||
|
|
b163fcab98 | ||
|
|
fd3115bbcf | ||
|
|
6dbdc97957 | ||
|
|
ecbf760a51 | ||
|
|
be359cbfa8 | ||
|
|
e2f15ad698 | ||
|
|
ca35cd929c | ||
|
|
c37694e796 | ||
|
|
23dfc5284a | ||
|
|
90539a098e | ||
|
|
ceeb3da16c | ||
|
|
4cd8f922e4 | ||
|
|
ffc1d7820e | ||
|
|
41a07f984a | ||
|
|
7ae0efaef3 | ||
|
|
a7faed674d | ||
|
|
460f8e935e | ||
|
|
6c64cb3607 | ||
|
|
a43f893336 | ||
|
|
de04f2b686 | ||
|
|
c5d255c82d | ||
|
|
e389f0b39d | ||
|
|
f27f27df39 | ||
|
|
6029642b78 | ||
|
|
999bf637d2 | ||
|
|
9ce4fbe14b | ||
|
|
210a71e4ad | ||
|
|
a863a7e400 | ||
|
|
9bcbbfd1b0 | ||
|
|
deca91d7aa | ||
|
|
2767b2676e | ||
|
|
c4f1ee6574 | ||
|
|
6775c92a60 | ||
|
|
88bbddd58a | ||
|
|
2cce34dbd1 | ||
|
|
424e00e4e0 | ||
|
|
f212815a0e |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -13,4 +13,6 @@ core.*
|
|||||||
*_old/
|
*_old/
|
||||||
*PVs.list
|
*PVs.list
|
||||||
*-loc/*.Makefile
|
*-loc/*.Makefile
|
||||||
ecmcPlugin_Simple-loc/*.Makefile
|
ecmc_plugin_fft/*.Makefile
|
||||||
|
*__*
|
||||||
|
O.*
|
||||||
35
GNUmakefile
Normal file
35
GNUmakefile
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
include /ioc/tools/driver.makefile
|
||||||
|
|
||||||
|
MODULE = ecmc_plugin_fft
|
||||||
|
|
||||||
|
# "Transfer" module name to plugin
|
||||||
|
USR_CFLAGS +=-DECMC_PLUGIN_MODULE_NAME=${MODULE}
|
||||||
|
|
||||||
|
BUILDCLASSES = Linux
|
||||||
|
ARCH_FILTER = deb10% deb12%
|
||||||
|
|
||||||
|
EXCLUDE_VERSIONS+=3 7.0.5 7.0.6 7.0.7 7.0.9
|
||||||
|
|
||||||
|
IGNORE_MODULES += asynMotor
|
||||||
|
IGNORE_MODULES += motorBase
|
||||||
|
|
||||||
|
USR_CXXFLAGS += -std=c++17
|
||||||
|
OPT_CXXFLAGS_YES = -O3
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
ECmasterECMC_VERSION = v1.1.0
|
||||||
|
ecmc_VERSION = 10.0
|
||||||
|
|
||||||
|
APP:=src
|
||||||
|
APPDB:=$(APP)/Db
|
||||||
|
APPSRC:=$(APP)/src
|
||||||
|
|
||||||
|
USR_CFLAGS += -shared -fPIC -Wall -Wextra
|
||||||
|
USR_LDFLAGS += -lstdc++
|
||||||
|
USR_INCLUDES += -I$(where_am_I)$(APPSRC)
|
||||||
|
|
||||||
|
TEMPLATES += $(wildcard $(APPDB)/*.db)
|
||||||
|
TEMPLATES += $(wildcard $(APPDB)/*.template)
|
||||||
|
SOURCES += $(APPSRC)/ecmcPluginFFT.c
|
||||||
|
SOURCES += $(APPSRC)/ecmcFFTWrap.cpp
|
||||||
|
SOURCES += $(APPSRC)/ecmcFFT.cpp
|
||||||
28
Makefile
28
Makefile
@@ -1,28 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2018 - 2019 European Spallation Source ERIC
|
|
||||||
#
|
|
||||||
# The program is free software: you can redistribute
|
|
||||||
# it and/or modify it under the terms of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation, either version 2 of the
|
|
||||||
# License, or any newer version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
# more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program. If not, see https://www.gnu.org/licenses/gpl-2.0.txt
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Author : Jeong Han Lee
|
|
||||||
# email : han.lee@esss.se
|
|
||||||
# Date : 2020Mar22-1607-33CET
|
|
||||||
# version : 1.0.0
|
|
||||||
|
|
||||||
TOP:=$(CURDIR)
|
|
||||||
|
|
||||||
include $(TOP)/configure/CONFIG
|
|
||||||
|
|
||||||
include $(TOP)/configure/RULES
|
|
||||||
|
|
||||||
151
README.md
151
README.md
@@ -1,4 +1,4 @@
|
|||||||
e3-ecmcPlugin_FFT
|
e3-ecmc_plugin_fft
|
||||||
======
|
======
|
||||||
ESS Site-specific EPICS module : ecmcPlugin_FFT
|
ESS Site-specific EPICS module : ecmcPlugin_FFT
|
||||||
|
|
||||||
@@ -46,12 +46,13 @@ The different available configuration settings:
|
|||||||
* SOURCE= source variable : Sets source variable for FFT (example: ec0.s1.AI_1). This config is mandatory.
|
* 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.
|
* 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.
|
* SCALE=scale : Apply scale to input data, default = 1.0.
|
||||||
* RM_DC=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.
|
* 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.
|
* 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
|
* 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.
|
* 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.
|
||||||
|
* BREAKTABLE= EPICS breaktable : Apply breaktable to raw value.
|
||||||
|
|
||||||
Example configuration string:
|
Example configuration string:
|
||||||
```
|
```
|
||||||
@@ -74,7 +75,7 @@ Example: Ethercat slave 1 analog input ch1
|
|||||||
#### DBG_PRINT (default: disabled)
|
#### DBG_PRINT (default: disabled)
|
||||||
Enable/disable printouts from plugin can be made bu setting the "DBG_PRINT" option.
|
Enable/disable printouts from plugin can be made bu setting the "DBG_PRINT" option.
|
||||||
|
|
||||||
Exmaple: Disable
|
Example: Disable
|
||||||
```
|
```
|
||||||
"DBG_PRINT=0;SOURCE=ax1.poserr;"
|
"DBG_PRINT=0;SOURCE=ax1.poserr;"
|
||||||
```
|
```
|
||||||
@@ -84,23 +85,23 @@ Defines number of samples for each measurement.
|
|||||||
|
|
||||||
Note: Must be a n² number..
|
Note: Must be a n² number..
|
||||||
|
|
||||||
Exmaple: 1024
|
Example: 1024
|
||||||
```
|
```
|
||||||
"NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
"NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
||||||
```
|
```
|
||||||
#### APPLY_SCALE (default disabled)
|
#### SCALE (default 1.0)
|
||||||
Apply scaling in order to get correct amplitude of fft. Disabled as default (lower cpu usage).
|
Apply custom scale to input data.
|
||||||
|
|
||||||
Exmaple: Enable
|
Example: 5.0
|
||||||
```
|
```
|
||||||
"APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
"SCALE=5.0;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
||||||
```
|
```
|
||||||
### RM_DC
|
### RM_DC
|
||||||
Remove DC of input signal. Default is disabled.
|
Remove DC of input signal. Default is disabled.
|
||||||
|
|
||||||
Exmaple: Remove DC offset
|
Example: Remove DC offset
|
||||||
```
|
```
|
||||||
"RM_DC=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
"RM_DC=1;SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
||||||
|
|
||||||
```
|
```
|
||||||
### RM_LIN
|
### RM_LIN
|
||||||
@@ -108,22 +109,22 @@ Remove linear component of input signal. Default is disabled.
|
|||||||
The linear component is calculated by least square method.
|
The linear component is calculated by least square method.
|
||||||
Could be usefull for values that increase, like actual position.
|
Could be usefull for values that increase, like actual position.
|
||||||
|
|
||||||
Exmaple: Remove linear component
|
Example: Remove linear component
|
||||||
```
|
```
|
||||||
"RM_LIN=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
"RM_LIN=1;SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
||||||
```
|
```
|
||||||
#### ENABLE (default: disabled)
|
#### 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.
|
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
|
Example: Enable at startup by config
|
||||||
```
|
```
|
||||||
"ENABLE=1;RM_DC=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
"ENABLE=1;RM_DC=1;SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
||||||
```
|
```
|
||||||
Exmaple: Enable FFT index 0 from EPICS:
|
Example: Enable FFT index 0 from EPICS:
|
||||||
```
|
```
|
||||||
caput IOC_TEST:Plugin-FFT0-Enable 1
|
caput IOC_TEST:Plugin-FFT0-Enable 1
|
||||||
```
|
```
|
||||||
Exmaple: Enable FFT index 0 from ecmc PLC code:
|
Example: Enable FFT index 0 from ecmc PLC code:
|
||||||
```
|
```
|
||||||
fft_enable(0,1)
|
fft_enable(0,1)
|
||||||
```
|
```
|
||||||
@@ -152,11 +153,11 @@ Triggered mode:
|
|||||||
5. FTT results are sent by callback over asyn to epics records
|
5. FTT results are sent by callback over asyn to epics records
|
||||||
6. goto 1.
|
6. goto 1.
|
||||||
|
|
||||||
Exmaple: Mode triggered
|
Example: Mode triggered
|
||||||
```
|
```
|
||||||
"MODE=TRIGG;ENABLE=1;RM_DC=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
"MODE=TRIGG;ENABLE=1;RM_DC=1;SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
||||||
```
|
```
|
||||||
Exmaple: Mode from EPICS record
|
Example: Mode from EPICS record
|
||||||
```
|
```
|
||||||
# CONT
|
# CONT
|
||||||
caput IOC_TEST:Plugin-FFT0-Mode-RB 1
|
caput IOC_TEST:Plugin-FFT0-Mode-RB 1
|
||||||
@@ -169,10 +170,44 @@ Note: The record is a output record with readback so can both be read and writte
|
|||||||
Sets the sample rate of the raw input data (from data source). The default value is the ecmc rate for that data source.
|
Sets the sample rate of the raw input data (from data source). The default value is the ecmc rate for that data source.
|
||||||
Note: only a lower and "integer" division of sample rate can be defined.
|
Note: only a lower and "integer" division of sample rate can be defined.
|
||||||
|
|
||||||
Exmaple: Rate = 100Hz
|
Example: Rate = 100Hz
|
||||||
```
|
```
|
||||||
RATE=100;MODE=TRIGG;ENABLE=1;RM_DC=1;APPLY_SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
"RATE=100;MODE=TRIGG;ENABLE=1;RM_DC=1;SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### BREAKTABLE (default: no break table)
|
||||||
|
|
||||||
|
Note: The break table must be added in EPICS
|
||||||
|
|
||||||
|
Example: Apply BREAKTABLE=typeTelemess33020_21877 to raw value
|
||||||
|
```
|
||||||
|
"...;BREAKTABLE=typeTelemess33020_21877;"
|
||||||
|
```
|
||||||
|
|
||||||
|
Example: Load custom breaktable in EPICS
|
||||||
|
```
|
||||||
|
dbLoadRecords ./bptBreakTable.dbd
|
||||||
|
```
|
||||||
|
|
||||||
|
Example: breaktable (in a bptBreakTable.dbd)
|
||||||
|
```
|
||||||
|
# <raw> <eng>
|
||||||
|
breaktable(typeTelemess33020_21877) {
|
||||||
|
2502.48 0
|
||||||
|
4058.89 1.5
|
||||||
|
6164.64 3
|
||||||
|
8880.74 4.5
|
||||||
|
11993.57 6
|
||||||
|
15259.00 7.5
|
||||||
|
18371.84 9
|
||||||
|
21271.05 10.5
|
||||||
|
24658.54 12
|
||||||
|
27344.13 13.5
|
||||||
|
29297.28 15
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## EPICS records
|
## EPICS records
|
||||||
Each FFT plugin object will create a new asynportdriver-port named "PLUGIN.FFT<index>" (index is explaine above).
|
Each FFT plugin object will create a new asynportdriver-port named "PLUGIN.FFT<index>" (index is explaine above).
|
||||||
The reason for a dedicated asynport is to disturb ecmc as little as possible.
|
The reason for a dedicated asynport is to disturb ecmc as little as possible.
|
||||||
@@ -216,6 +251,7 @@ Note: The FFT asynparameters will not be visible by the ecmcReport iocsh command
|
|||||||
## PLC interface
|
## PLC interface
|
||||||
|
|
||||||
### PLC Functions
|
### PLC Functions
|
||||||
|
|
||||||
1. "fft_clear(arg0);" double fft_clear(index) : Clear/resets all buffers fft[index].
|
1. "fft_clear(arg0);" double fft_clear(index) : Clear/resets all buffers fft[index].
|
||||||
2. "fft_enable(arg0, arg1);" double fft_enable(index, enable) : Set enable for fft[index].
|
2. "fft_enable(arg0, arg1);" double fft_enable(index, enable) : Set enable for fft[index].
|
||||||
3. "fft_trigg(arg0);" double fft_trigg(index) : Trigg new measurement for fft[index]. Will clear buffers.
|
3. "fft_trigg(arg0);" double fft_trigg(index) : Trigg new measurement for fft[index]. Will clear buffers.
|
||||||
@@ -268,6 +304,77 @@ static.time:=ec_get_time()/1E9;
|
|||||||
static.sineval:=sin(2*pi*${FREQ=5}*static.time);
|
static.sineval:=sin(2*pi*${FREQ=5}*static.time);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## FFT GUI
|
||||||
|
|
||||||
|
### FFT GUI (FFT and rawdata plots + controls)
|
||||||
|
A simple tool, [ecmcFFTMainGui.py](tools/ecmcFFTMainGui.py), to visualize the calculated spectrum, rawdata and also plugin controls can be found in the tools directory. The GUI connects to the plugin records over pypics framwork.
|
||||||
|
The gui are included in the ecmccomgui repo:
|
||||||
|
https://github.com/anderssandstrom/ecmccomgui
|
||||||
|
|
||||||
|
Example: ecmcFFTMainGui.py help printout
|
||||||
|
```
|
||||||
|
python ecmcFFTMainGui.py
|
||||||
|
ecmcFFTMainGui: Plots waveforms of FFT data (updates on Y data callback).
|
||||||
|
python ecmcFFTMainGui.py <prefix> <fftId>
|
||||||
|
<prefix>: Ioc prefix ('IOC_TEST:')
|
||||||
|
<fftId> : Id of fft plugin ('0')
|
||||||
|
example : python ecmcFFTMainGui.py 'IOC_TEST:' '0'
|
||||||
|
Will connect to Pvs: <prefix>Plugin-FFT<fftId>-*
|
||||||
|
```
|
||||||
|
|
||||||
|
Example: Start ecmcFFMainTGui.py for:
|
||||||
|
* predix="IOC_TEST:"
|
||||||
|
* fftPluginId=0 (the first loaded FFT plugin in the ioc)
|
||||||
|
```
|
||||||
|
python ecmcFFTMainGui.py IOC_TEST: 0
|
||||||
|
```
|
||||||
|

|
||||||
|
|
||||||
|
### FFT GUI (only FFT plot)
|
||||||
|
|
||||||
|
A simple tool, [ecmcFFTGui.py](tools/ecmcFFTGui.py), to visualize the calculated spectrum can be found in the tools directory.
|
||||||
|
The GUI connects to the plugin records over pypics framwork.
|
||||||
|
|
||||||
|
Example: ecmcFFTGui.py help printout
|
||||||
|
```
|
||||||
|
python ecmcFFTGui.py
|
||||||
|
ecmcFFTGui: Plots waveforms of FFT data (updates on Y data callback).
|
||||||
|
python ecmcFFTGui.py <x.pv> <y.pv>
|
||||||
|
example: python ecmcFFTGui.py IOC_TEST:Plugin-FFT1-Spectrum-X-Axis-Act IOC_TEST:Plugin-FFT1-Spectrum-Amp-Act
|
||||||
|
```
|
||||||
|
|
||||||
|
Example: Start ecmcFFTGui.py for spectrum amplitude and freq. waveform pvs
|
||||||
|
```
|
||||||
|
python ecmcFFTGui.py IOC_TEST:Plugin-FFT1-Spectrum-X-Axis-Act IOC_TEST:Plugin-FFT1-Spectrum-Amp-Act
|
||||||
|
```
|
||||||
|

|
||||||
|
|
||||||
|
### Array GUI (generic waveform plt)
|
||||||
|
A simple generic tool, [ecmcFFTGui.py](tools/ecmcFFTGui.py), to visualize wavforms.
|
||||||
|
The GUI connects to the plugin records over pypics framwork.
|
||||||
|
|
||||||
|
Example: ecmcArrayGui.py help printout
|
||||||
|
```
|
||||||
|
python ecmcArrayGui.py
|
||||||
|
ecmcArrayGui: Plots waveforms data (updates on data callback).
|
||||||
|
python ecmcArrayGui.py <y.pv>
|
||||||
|
example: python ecmcArrayGui.py IOC_TEST:Plugin-FFT0-Raw-Data-Act
|
||||||
|
```
|
||||||
|
|
||||||
|
Example: Start ecmcArrayGui.py for raw data wavform
|
||||||
|
```
|
||||||
|
python ecmcArrayGui.py IOC_TEST:Plugin-FFT0-Raw-Data-Act
|
||||||
|
```
|
||||||
|

|
||||||
|
|
||||||
|
### Needed packages:
|
||||||
|
* python 3.5
|
||||||
|
* epics
|
||||||
|
* PyQt5
|
||||||
|
* numpy
|
||||||
|
* matplotlib
|
||||||
|
|
||||||
|
|
||||||
## Plugin info
|
## Plugin info
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -279,7 +386,7 @@ Plugin info:
|
|||||||
DBG_PRINT=<1/0> : Enables/disables printouts from plugin, default = disabled.
|
DBG_PRINT=<1/0> : Enables/disables printouts from plugin, default = disabled.
|
||||||
SOURCE=<source> : Sets source variable for FFT (example: ec0.s1.AI_1).
|
SOURCE=<source> : Sets source variable for FFT (example: ec0.s1.AI_1).
|
||||||
NFFT=<nfft> : Data points to collect, default = 4096.
|
NFFT=<nfft> : Data points to collect, default = 4096.
|
||||||
APPLY_SCALE=<1/0> : Apply scale, default = disabled.
|
SCALE=<1/0> : Apply scale, default = disabled.
|
||||||
RM_DC=<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.
|
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
|
MODE=<CONT/TRIGG> : Continious or triggered mode, defaults to TRIGG
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
EPICS_MODULE_NAME:=ecmcPlugin_FFT
|
EPICS_MODULE_NAME:=ecmc_plugin_fft
|
||||||
|
|
||||||
EPICS_MODULE_TAG:=master
|
EPICS_MODULE_TAG:=master
|
||||||
#
|
#
|
||||||
@@ -8,8 +8,8 @@ E3_MODULE_VERSION:=master
|
|||||||
# DEPENDENT MODULE VERSION
|
# DEPENDENT MODULE VERSION
|
||||||
# For Example,
|
# For Example,
|
||||||
|
|
||||||
ECMC_DEP_VERSION:=master
|
ECMC_DEP_VERSION:=develop
|
||||||
ASYN_DEP_VERSION:=4.36.0
|
ASYN_DEP_VERSION:=4.37.0
|
||||||
|
|
||||||
#DEVLIB2_DEP_VERSION:=2.9.0
|
#DEVLIB2_DEP_VERSION:=2.9.0
|
||||||
#PCRE_DEP_VERSION:=8.41.0
|
#PCRE_DEP_VERSION:=8.41.0
|
||||||
@@ -27,7 +27,7 @@ ASYN_DEP_VERSION:=4.36.0
|
|||||||
#
|
#
|
||||||
|
|
||||||
E3_MODULE_NAME:=$(EPICS_MODULE_NAME)
|
E3_MODULE_NAME:=$(EPICS_MODULE_NAME)
|
||||||
E3_MODULE_SRC_PATH:=ecmcPlugin_FFT-loc
|
E3_MODULE_SRC_PATH:=ecmc_plugin_fft
|
||||||
E3_MODULE_MAKEFILE:=$(EPICS_MODULE_NAME).Makefile
|
E3_MODULE_MAKEFILE:=$(EPICS_MODULE_NAME).Makefile
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#
|
#
|
||||||
EPICS_BASE:=/epics/base-7.0.3.1
|
EPICS_BASE:=${HOME}/epics/base-7.0.4
|
||||||
|
|
||||||
E3_REQUIRE_NAME:=require
|
E3_REQUIRE_NAME:=require
|
||||||
E3_REQUIRE_VERSION:=3.1.2
|
E3_REQUIRE_VERSION:=3.4.0
|
||||||
|
|
||||||
# The definitions shown below can also be placed in an untracked RELEASE.local
|
# The definitions shown below can also be placed in an untracked RELEASE.local
|
||||||
-include $(TOP)/../../RELEASE.local
|
-include $(TOP)/../../RELEASE.local
|
||||||
|
|||||||
BIN
docs/gui/ecmcArrayGui.png
Normal file
BIN
docs/gui/ecmcArrayGui.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
BIN
docs/gui/ecmcFFTGui.png
Normal file
BIN
docs/gui/ecmcFFTGui.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/gui/ecmcFFTMainGui.png
Normal file
BIN
docs/gui/ecmcFFTMainGui.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
@@ -1,62 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2019 European Spallation Source ERIC
|
|
||||||
#
|
|
||||||
# The program is free software: you can redistribute
|
|
||||||
# it and/or modify it under the terms of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation, either version 2 of the
|
|
||||||
# License, or any newer version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
# more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program. If not, see https://www.gnu.org/licenses/gpl-2.0.txt
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Author : anderssandstrom
|
|
||||||
# email : anderssandstrom@esss.se
|
|
||||||
# Date : 2020Mar22-1607-33CET
|
|
||||||
# version : 0.0.0
|
|
||||||
#
|
|
||||||
# template file is generated by ./e3TemplateGenerator.bash with bf03d40
|
|
||||||
# Please look at many other _module_.Makefile in e3-* repository
|
|
||||||
#
|
|
||||||
|
|
||||||
## The following lines are mandatory, please don't change them.
|
|
||||||
where_am_I := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
|
||||||
include $(E3_REQUIRE_TOOLS)/driver.makefile
|
|
||||||
include $(E3_REQUIRE_CONFIG)/DECOUPLE_FLAGS
|
|
||||||
|
|
||||||
ifneq ($(strip $(ASYN_DEP_VERSION)),)
|
|
||||||
asyn_VERSION=$(ASYN_DEP_VERSION)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(strip $(ECMC_DEP_VERSION)),)
|
|
||||||
ecmc_VERSION=$(ECMC_DEP_VERSION)
|
|
||||||
endif
|
|
||||||
|
|
||||||
APP:=ecmcPlugin_FFTApp
|
|
||||||
APPDB:=$(APP)/Db
|
|
||||||
APPSRC:=$(APP)/src
|
|
||||||
|
|
||||||
USR_CFLAGS += -shared -fPIC -Wall -Wextra
|
|
||||||
USR_LDFLAGS += -lstdc++
|
|
||||||
USR_INCLUDES += -I$(where_am_I)$(APPSRC)
|
|
||||||
|
|
||||||
TEMPLATES += $(wildcard $(APPDB)/*.db)
|
|
||||||
TEMPLATES += $(wildcard $(APPDB)/*.template)
|
|
||||||
SOURCES += $(APPSRC)/ecmcPluginFFT.c
|
|
||||||
SOURCES += $(APPSRC)/ecmcFFTWrap.cpp
|
|
||||||
SOURCES += $(APPSRC)/ecmcFFT.cpp
|
|
||||||
|
|
||||||
db:
|
|
||||||
|
|
||||||
.PHONY: db
|
|
||||||
|
|
||||||
vlibs:
|
|
||||||
|
|
||||||
.PHONY: vlibs
|
|
||||||
|
|
||||||
###
|
|
||||||
@@ -7,12 +7,11 @@ epicsEnvSet("IOC" ,"$(IOC="IOC_TEST")")
|
|||||||
epicsEnvSet("ECMCCFG_INIT" ,"") #Only run startup once (auto at PSI, need call at ESS), variable set to "#" in startup.cmd
|
epicsEnvSet("ECMCCFG_INIT" ,"") #Only run startup once (auto at PSI, need call at ESS), variable set to "#" in startup.cmd
|
||||||
epicsEnvSet("SCRIPTEXEC" ,"$(SCRIPTEXEC="iocshLoad")")
|
epicsEnvSet("SCRIPTEXEC" ,"$(SCRIPTEXEC="iocshLoad")")
|
||||||
|
|
||||||
require ecmccfg master
|
require ecmccfg "6.3.0"
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
###### Startup
|
###### Startup
|
||||||
require ecmc "master"
|
require ecmc "6.3.0"
|
||||||
require stream "${stream_VER=2.8.10}"
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
#- define default PATH for scripts and database/templates
|
#- define default PATH for scripts and database/templates
|
||||||
@@ -41,29 +40,30 @@ ecmcConfigOrDie "Cfg.SetSampleRate(${ECMC_EC_SAMPLE_RATE})"
|
|||||||
# No EtherCAT hardware..
|
# No EtherCAT hardware..
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
require ecmcPlugin_FFT master # te get access to db file..
|
require ecmc_plugin_fft master # te get access to db file..
|
||||||
epicsEnvSet("FFT_NELM", 1024)
|
epicsEnvSet("FFT_NELM", 1024)
|
||||||
|
|
||||||
########################################################################s######
|
########################################################################s######
|
||||||
## Load plugin: FFT
|
## Load plugin: FFT
|
||||||
epicsEnvSet(ECMC_PLUGIN_FILNAME,"/epics/base-7.0.3.1/require/3.1.2/siteMods/ecmcPlugin_FFT/master/lib/${EPICS_HOST_ARCH=linux-x86_64}/libecmcPlugin_FFT.so")
|
epicsEnvSet(ECMC_PLUGIN_FILNAME,"/home/pi/epics/base-7.0.4/require/3.3.0/siteMods/ecmc_plugin_fft/master/lib/${EPICS_HOST_ARCH=linux-x86_64}/libecmc_plugin_fft.so")
|
||||||
epicsEnvSet(ECMC_PLUGIN_CONFIG,"SOURCE=plcs.plc0.static.sineval;DBG_PRINT=0;NFFT=1024;RATE=100;DC_REMOVE=1;APPLY_SCALE=1;MODE=CONT;")
|
epicsEnvSet(ECMC_PLUGIN_CONFIG,"SOURCE=plcs.plc0.static.sineval;DBG_PRINT=0;NFFT=1024;RATE=100;RM_DC=1;SCALE=1;MODE=CONT;ENABLE=1;")
|
||||||
${SCRIPTEXEC} ${ecmccfg_DIR}loadPlugin.cmd, "PLUGIN_ID=0,FILE=${ECMC_PLUGIN_FILNAME},CONFIG='${ECMC_PLUGIN_CONFIG}', REPORT=1"
|
${SCRIPTEXEC} ${ecmccfg_DIR}loadPlugin.cmd, "PLUGIN_ID=0,FILE=${ECMC_PLUGIN_FILNAME},CONFIG='${ECMC_PLUGIN_CONFIG}', REPORT=1"
|
||||||
# Note: INDEX is the index of FFT object in FFT plugin and not PLUGIN_ID. In this case the same
|
# Note: INDEX is the index of FFT object in FFT plugin and not PLUGIN_ID. In this case the same
|
||||||
dbLoadRecords(ecmcPluginFFT.template,"P=$(IOC):,INDEX=0, NELM=${FFT_NELM}")
|
dbLoadRecords(ecmcPluginFFT.template,"P=$(IOC):,INDEX=0, NELM=${FFT_NELM}, AMP_DESC='Sine amplitude',AMP_EGU='',RAW_DESC='Sine',AMP_EGU='', TITLE='FFT of sinus in 5Hz'")
|
||||||
|
|
||||||
########################################################################s######
|
########################################################################s######
|
||||||
## Load plugin: FFT again (will create a new FFT object in the same namespace)
|
## Load plugin: FFT again (will create a new FFT object in the same namespace)
|
||||||
epicsEnvSet(ECMC_PLUGIN_FILNAME,"/epics/base-7.0.3.1/require/3.1.2/siteMods/ecmcPlugin_FFT/master/lib/${EPICS_HOST_ARCH=linux-x86_64}/libecmcPlugin_FFT.so")
|
epicsEnvSet(ECMC_PLUGIN_FILNAME,"/home/pi/epics/base-7.0.4/require/3.3.0/siteMods/ecmc_plugin_fft/master/lib/${EPICS_HOST_ARCH=linux-x86_64}/libecmc_plugin_fft.so")
|
||||||
epicsEnvSet(ECMC_PLUGIN_CONFIG,"SOURCE=ecmc.thread.latency.max;DBG_PRINT=0;NFFT=1024;")
|
epicsEnvSet(ECMC_PLUGIN_CONFIG,"SOURCE=ecmc.thread.latency.max;DBG_PRINT=0;NFFT=1024;ENABLE=1;")
|
||||||
${SCRIPTEXEC} ${ecmccfg_DIR}loadPlugin.cmd, "PLUGIN_ID=1,FILE=${ECMC_PLUGIN_FILNAME},CONFIG='${ECMC_PLUGIN_CONFIG}', REPORT=1"
|
${SCRIPTEXEC} ${ecmccfg_DIR}loadPlugin.cmd, "PLUGIN_ID=1,FILE=${ECMC_PLUGIN_FILNAME},CONFIG='${ECMC_PLUGIN_CONFIG}', REPORT=1"
|
||||||
# Note: INDEX is the index of FFT object in FFT plugin and not PLUGIN_ID. In this case the same
|
# Note: INDEX is the index of FFT object in FFT plugin and not PLUGIN_ID. In this case the same
|
||||||
dbLoadRecords(ecmcPluginFFT.template,"P=$(IOC):,INDEX=1, NELM=${FFT_NELM}")
|
dbLoadRecords(ecmcPluginFFT.template,"P=$(IOC):,INDEX=1, NELM=${FFT_NELM}, AMP_DESC='Latency amplitude',AMP_EGU='ns',RAW_DESC='Latency',AMP_EGU='ns',TITLE='FFT of ecmc latencny'")
|
||||||
|
|
||||||
epicsEnvUnset(ECMC_PLUGIN_FILNAME)
|
epicsEnvUnset(ECMC_PLUGIN_FILNAME)
|
||||||
epicsEnvUnset(ECMC_PLUGIN_CONFIG)
|
epicsEnvUnset(ECMC_PLUGIN_CONFIG)
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
## PLC 0: Generate a sine wave at 10Hz
|
## PLC 0: Generate a sine wave at 5Hz
|
||||||
$(SCRIPTEXEC) $(ecmccfg_DIR)loadPLCFile.cmd, "PLC_ID=0, SAMPLE_RATE_MS=10,FILE=./plc/plc_no_ec_fft_sin.plc, PLC_MACROS='FREQ=5'")
|
$(SCRIPTEXEC) $(ecmccfg_DIR)loadPLCFile.cmd, "PLC_ID=0, SAMPLE_RATE_MS=10,FILE=./plc/plc_no_ec_fft_sin.plc, PLC_MACROS='FREQ=5'")
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
@@ -80,4 +80,4 @@ dbLoadRecords("ecmcGeneral.db","P=${ECMC_PREFIX},PORT=${ECMC_ASYN_PORT},ADDR=0,T
|
|||||||
ecmcConfigOrDie "Cfg.SetAppMode(1)"
|
ecmcConfigOrDie "Cfg.SetAppMode(1)"
|
||||||
|
|
||||||
iocInit
|
iocInit
|
||||||
|
dbl > pvs.log
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ record(waveform,"$(P)Plugin-FFT${INDEX}-Source"){
|
|||||||
# Rawdata
|
# Rawdata
|
||||||
record(waveform,"$(P)Plugin-FFT${INDEX}-Raw-Data-Act"){
|
record(waveform,"$(P)Plugin-FFT${INDEX}-Raw-Data-Act"){
|
||||||
info(asyn:FIFO, "1000")
|
info(asyn:FIFO, "1000")
|
||||||
field(DESC, "Raw data")
|
field(DESC, "${RAW_DESC="Raw data"}")
|
||||||
field(PINI, "1")
|
field(PINI, "1")
|
||||||
field(DTYP, "asynFloat64ArrayIn")
|
field(DTYP, "asynFloat64ArrayIn")
|
||||||
field(INP, "@asyn(PLUGIN.FFT${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.fft${INDEX}.rawdata")
|
field(INP, "@asyn(PLUGIN.FFT${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.fft${INDEX}.rawdata")
|
||||||
@@ -31,6 +31,7 @@ record(waveform,"$(P)Plugin-FFT${INDEX}-Raw-Data-Act"){
|
|||||||
field(NELM, "$(NELM)")
|
field(NELM, "$(NELM)")
|
||||||
field(SCAN, "I/O Intr")
|
field(SCAN, "I/O Intr")
|
||||||
field(TSE, "0")
|
field(TSE, "0")
|
||||||
|
field(EGU, "${RAW_EGU= }")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Pre-processed data
|
# Pre-processed data
|
||||||
@@ -49,7 +50,7 @@ record(waveform,"$(P)Plugin-FFT${INDEX}-PreProc-Data-Act"){
|
|||||||
# FFT amplitude result
|
# FFT amplitude result
|
||||||
record(waveform,"$(P)Plugin-FFT${INDEX}-Spectrum-Amp-Act"){
|
record(waveform,"$(P)Plugin-FFT${INDEX}-Spectrum-Amp-Act"){
|
||||||
info(asyn:FIFO, "1000")
|
info(asyn:FIFO, "1000")
|
||||||
field(DESC, "FFT spectrum amplitude result")
|
field(DESC, "${AMP_DESC="Spectrum amplitude"}")
|
||||||
field(PINI, "1")
|
field(PINI, "1")
|
||||||
field(DTYP, "asynFloat64ArrayIn")
|
field(DTYP, "asynFloat64ArrayIn")
|
||||||
field(INP, "@asyn(PLUGIN.FFT${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.fft${INDEX}.fftamplitude")
|
field(INP, "@asyn(PLUGIN.FFT${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.fft${INDEX}.fftamplitude")
|
||||||
@@ -57,12 +58,14 @@ record(waveform,"$(P)Plugin-FFT${INDEX}-Spectrum-Amp-Act"){
|
|||||||
field(NELM, "$(NELM)")
|
field(NELM, "$(NELM)")
|
||||||
field(SCAN, "I/O Intr")
|
field(SCAN, "I/O Intr")
|
||||||
field(TSE, "0")
|
field(TSE, "0")
|
||||||
|
field(EGU, "${AMP_EGU= }")
|
||||||
}
|
}
|
||||||
|
|
||||||
# FFT xaxis
|
# FFT xaxis
|
||||||
record(waveform,"$(P)Plugin-FFT${INDEX}-Spectrum-X-Axis-Act"){
|
record(waveform,"$(P)Plugin-FFT${INDEX}-Spectrum-X-Axis-Act"){
|
||||||
info(asyn:FIFO, "1000")
|
info(asyn:FIFO, "1000")
|
||||||
field(DESC, "Raw data")
|
field(DESC, "X-Axis data")
|
||||||
|
field(EGU, "Hz")
|
||||||
field(PINI, "1")
|
field(PINI, "1")
|
||||||
field(DTYP, "asynFloat64ArrayIn")
|
field(DTYP, "asynFloat64ArrayIn")
|
||||||
field(INP, "@asyn(PLUGIN.FFT${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.fft${INDEX}.fftxaxis")
|
field(INP, "@asyn(PLUGIN.FFT${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.fft${INDEX}.fftxaxis")
|
||||||
@@ -73,6 +76,7 @@ record(waveform,"$(P)Plugin-FFT${INDEX}-Spectrum-X-Axis-Act"){
|
|||||||
}
|
}
|
||||||
|
|
||||||
record(bo,"$(P)Plugin-FFT${INDEX}-Enable"){
|
record(bo,"$(P)Plugin-FFT${INDEX}-Enable"){
|
||||||
|
info(asyn:READBACK,"1")
|
||||||
field(DESC, "FFT Enable")
|
field(DESC, "FFT Enable")
|
||||||
field(DTYP,"asynInt32")
|
field(DTYP,"asynInt32")
|
||||||
field(OUT, "@asyn(PLUGIN.FFT${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.fft${INDEX}.enable")
|
field(OUT, "@asyn(PLUGIN.FFT${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.fft${INDEX}.enable")
|
||||||
@@ -121,4 +125,18 @@ record(ai,"$(P)Plugin-FFT${INDEX}-SampleRate-Act"){
|
|||||||
field(TSE, "0")
|
field(TSE, "0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Actual buffer index
|
||||||
|
record(longin,"$(P)Plugin-FFT${INDEX}-BuffIdAct"){
|
||||||
|
field(DESC, "Current buffer index")
|
||||||
|
field(PINI, "1")
|
||||||
|
field(DTYP, "asynInt32")
|
||||||
|
field(INP, "@asyn(PLUGIN.FFT${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.fft${INDEX}.buffid")
|
||||||
|
field(SCAN, "I/O Intr")
|
||||||
|
field(TSE, "0")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Plot title (for epicscomgui)
|
||||||
|
record(stringin,"$(P)Plugin-FFT${INDEX}-Title"){
|
||||||
|
field(DESC, "Title of FFT plot")
|
||||||
|
field(VAL, "${TITLE="FFT"}")
|
||||||
|
}
|
||||||
@@ -26,14 +26,27 @@
|
|||||||
#define ECMC_PLUGIN_ASYN_FFT_X_FREQS "fftxaxis"
|
#define ECMC_PLUGIN_ASYN_FFT_X_FREQS "fftxaxis"
|
||||||
#define ECMC_PLUGIN_ASYN_NFFT "nfft"
|
#define ECMC_PLUGIN_ASYN_NFFT "nfft"
|
||||||
#define ECMC_PLUGIN_ASYN_RATE "samplerate"
|
#define ECMC_PLUGIN_ASYN_RATE "samplerate"
|
||||||
|
#define ECMC_PLUGIN_ASYN_BUFF_ID "buffid"
|
||||||
|
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "ecmcFFT.h"
|
#include "ecmcFFT.h"
|
||||||
#include "ecmcPluginClient.h"
|
#include "ecmcPluginClient.h"
|
||||||
#include "ecmcAsynPortDriver.h"
|
#include "ecmcAsynPortDriver.h"
|
||||||
|
#include "ecmcAsynPortDriverUtils.h"
|
||||||
#include "epicsThread.h"
|
#include "epicsThread.h"
|
||||||
|
|
||||||
|
// Breaktable
|
||||||
|
#include "ellLib.h"
|
||||||
|
#include "dbStaticLib.h"
|
||||||
|
#include "dbAccess.h"
|
||||||
|
#include "epicsVersion.h"
|
||||||
|
#include "cvtTable.h"
|
||||||
|
#ifdef BASE_VERSION
|
||||||
|
#define EPICS_3_13
|
||||||
|
extern DBBASE *pdbbase;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// New data callback from ecmc
|
// New data callback from ecmc
|
||||||
static int printMissingObjError = 1;
|
static int printMissingObjError = 1;
|
||||||
@@ -90,6 +103,7 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
|
|||||||
0) /* Default stack size */
|
0) /* Default stack size */
|
||||||
{
|
{
|
||||||
cfgDataSourceStr_ = NULL;
|
cfgDataSourceStr_ = NULL;
|
||||||
|
cfgBreakTableStr_ = NULL;
|
||||||
rawDataBuffer_ = NULL;
|
rawDataBuffer_ = NULL;
|
||||||
dataItem_ = NULL;
|
dataItem_ = NULL;
|
||||||
dataItemInfo_ = NULL;
|
dataItemInfo_ = NULL;
|
||||||
@@ -105,6 +119,8 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
|
|||||||
cycleCounter_ = 0;
|
cycleCounter_ = 0;
|
||||||
ignoreCycles_ = 0;
|
ignoreCycles_ = 0;
|
||||||
dataSourceLinked_ = 0;
|
dataSourceLinked_ = 0;
|
||||||
|
breakTable_ = NULL;
|
||||||
|
lastBreakPoint_ = 0;
|
||||||
|
|
||||||
// Asyn
|
// Asyn
|
||||||
asynEnableId_ = -1; // Enable/disable acq./calcs
|
asynEnableId_ = -1; // Enable/disable acq./calcs
|
||||||
@@ -118,18 +134,21 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
|
|||||||
asynFFTXAxisId_ = -1; // FFT X-axis frequencies
|
asynFFTXAxisId_ = -1; // FFT X-axis frequencies
|
||||||
asynNfftId_ = -1; // Nfft
|
asynNfftId_ = -1; // Nfft
|
||||||
asynSRateId_ = -1; // Sample rate Hz
|
asynSRateId_ = -1; // Sample rate Hz
|
||||||
|
asynElementsInBuffer_= -1;
|
||||||
|
|
||||||
ecmcSampleRateHz_ = getEcmcSampleRate();
|
ecmcSampleRateHz_ = getEcmcSampleRate();
|
||||||
cfgFFTSampleRateHz_ = ecmcSampleRateHz_;
|
cfgFFTSampleRateHz_ = ecmcSampleRateHz_;
|
||||||
|
cfgDataSampleRateHz_ = ecmcSampleRateHz_;
|
||||||
|
|
||||||
// Config defaults
|
// Config defaults
|
||||||
cfgDbgMode_ = 0;
|
cfgDbgMode_ = 0;
|
||||||
cfgNfft_ = ECMC_PLUGIN_DEFAULT_NFFT; // samples in fft (must be n^2)
|
cfgNfft_ = ECMC_PLUGIN_DEFAULT_NFFT; // samples in fft (must be n^2)
|
||||||
cfgDcRemove_ = 0;
|
cfgDcRemove_ = 0;
|
||||||
cfgLinRemove_ = 0;
|
cfgLinRemove_ = 0;
|
||||||
cfgApplyScale_ = 1; // Scale as default to get correct amplitude in fft
|
//cfgApplyScale_ = 1; // Scale as default to get correct amplitude in fft
|
||||||
cfgEnable_ = 0; // start disabled (enable over asyn)
|
cfgEnable_ = 0; // start disabled (enable over asyn)
|
||||||
cfgMode_ = TRIGG;
|
cfgMode_ = TRIGG;
|
||||||
|
cfgScale_ = 1.0;
|
||||||
|
|
||||||
parseConfigStr(configStr); // Assigns all configs
|
parseConfigStr(configStr); // Assigns all configs
|
||||||
// Check valid nfft
|
// Check valid nfft
|
||||||
@@ -146,6 +165,11 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
|
|||||||
cfgFFTSampleRateHz_ = ecmcSampleRateHz_;
|
cfgFFTSampleRateHz_ = ecmcSampleRateHz_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if breaktable
|
||||||
|
if(cfgBreakTableStr_) {
|
||||||
|
verifyBreakTable();
|
||||||
|
}
|
||||||
|
|
||||||
// Se if any data update cycles should be ignored
|
// Se if any data update cycles should be ignored
|
||||||
// example ecmc 1000Hz, fft 100Hz then ignore 9 cycles (could be strange if not multiples)
|
// example ecmc 1000Hz, fft 100Hz then ignore 9 cycles (could be strange if not multiples)
|
||||||
ignoreCycles_ = ecmcSampleRateHz_ / cfgFFTSampleRateHz_ -1;
|
ignoreCycles_ = ecmcSampleRateHz_ / cfgFFTSampleRateHz_ -1;
|
||||||
@@ -194,6 +218,9 @@ ecmcFFT::~ecmcFFT() {
|
|||||||
if(cfgDataSourceStr_) {
|
if(cfgDataSourceStr_) {
|
||||||
free(cfgDataSourceStr_);
|
free(cfgDataSourceStr_);
|
||||||
}
|
}
|
||||||
|
if(cfgBreakTableStr_) {
|
||||||
|
free(cfgBreakTableStr_);
|
||||||
|
}
|
||||||
if(fftDouble_) {
|
if(fftDouble_) {
|
||||||
delete fftDouble_;
|
delete fftDouble_;
|
||||||
}
|
}
|
||||||
@@ -229,17 +256,23 @@ void ecmcFFT::parseConfigStr(char *configStr) {
|
|||||||
cfgDataSourceStr_=strdup(pThisOption);
|
cfgDataSourceStr_=strdup(pThisOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ECMC_PLUGIN_BREAKTABLE_OPTION_CMD (EPICS breaktable name)
|
||||||
|
else if (!strncmp(pThisOption, ECMC_PLUGIN_BREAKTABLE_OPTION_CMD, strlen(ECMC_PLUGIN_BREAKTABLE_OPTION_CMD))) {
|
||||||
|
pThisOption += strlen(ECMC_PLUGIN_BREAKTABLE_OPTION_CMD);
|
||||||
|
cfgBreakTableStr_=strdup(pThisOption);
|
||||||
|
}
|
||||||
|
|
||||||
// ECMC_PLUGIN_NFFT_OPTION_CMD (1/0)
|
// ECMC_PLUGIN_NFFT_OPTION_CMD (1/0)
|
||||||
else if (!strncmp(pThisOption, ECMC_PLUGIN_NFFT_OPTION_CMD, strlen(ECMC_PLUGIN_NFFT_OPTION_CMD))) {
|
else if (!strncmp(pThisOption, ECMC_PLUGIN_NFFT_OPTION_CMD, strlen(ECMC_PLUGIN_NFFT_OPTION_CMD))) {
|
||||||
pThisOption += strlen(ECMC_PLUGIN_NFFT_OPTION_CMD);
|
pThisOption += strlen(ECMC_PLUGIN_NFFT_OPTION_CMD);
|
||||||
cfgNfft_ = atoi(pThisOption);
|
cfgNfft_ = atoi(pThisOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD (1/0)
|
// // ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD (1/0)
|
||||||
else if (!strncmp(pThisOption, ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD, strlen(ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD))) {
|
// else if (!strncmp(pThisOption, ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD, strlen(ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD))) {
|
||||||
pThisOption += strlen(ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD);
|
// pThisOption += strlen(ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD);
|
||||||
cfgApplyScale_ = atoi(pThisOption);
|
// cfgApplyScale_ = atoi(pThisOption);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// ECMC_PLUGIN_RM_DC_OPTION_CMD (1/0)
|
// 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))) {
|
else if (!strncmp(pThisOption, ECMC_PLUGIN_RM_DC_OPTION_CMD, strlen(ECMC_PLUGIN_RM_DC_OPTION_CMD))) {
|
||||||
@@ -276,6 +309,12 @@ void ecmcFFT::parseConfigStr(char *configStr) {
|
|||||||
cfgFFTSampleRateHz_ = atof(pThisOption);
|
cfgFFTSampleRateHz_ = atof(pThisOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ECMC_PLUGIN_SCALE_OPTION_CMD rate in HZ
|
||||||
|
else if (!strncmp(pThisOption, ECMC_PLUGIN_SCALE_OPTION_CMD, strlen(ECMC_PLUGIN_SCALE_OPTION_CMD))) {
|
||||||
|
pThisOption += strlen(ECMC_PLUGIN_SCALE_OPTION_CMD);
|
||||||
|
cfgScale_ = atof(pThisOption);
|
||||||
|
}
|
||||||
|
|
||||||
pThisOption = pNextOption;
|
pThisOption = pNextOption;
|
||||||
}
|
}
|
||||||
free(pOptions);
|
free(pOptions);
|
||||||
@@ -293,7 +332,7 @@ void ecmcFFT::connectToDataSource() {
|
|||||||
if( dataSourceLinked_ ) {
|
if( dataSourceLinked_ ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get dataItem
|
// Get dataItem
|
||||||
dataItem_ = (ecmcDataItem*) getEcmcDataItem(cfgDataSourceStr_);
|
dataItem_ = (ecmcDataItem*) getEcmcDataItem(cfgDataSourceStr_);
|
||||||
if(!dataItem_) {
|
if(!dataItem_) {
|
||||||
@@ -312,6 +351,12 @@ void ecmcFFT::connectToDataSource() {
|
|||||||
if( !dataTypeSupported(dataItem_->getEcmcDataType()) ) {
|
if( !dataTypeSupported(dataItem_->getEcmcDataType()) ) {
|
||||||
throw std::invalid_argument( "Data type not supported." );
|
throw std::invalid_argument( "Data type not supported." );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add oversampling
|
||||||
|
cfgDataSampleRateHz_ = cfgFFTSampleRateHz_ * dataItem_->getEcmcDataSize()/dataItem_->getEcmcDataElementSize();
|
||||||
|
setDoubleParam(asynSRateId_, cfgDataSampleRateHz_);
|
||||||
|
callParamCallbacks();
|
||||||
|
|
||||||
dataSourceLinked_ = 1;
|
dataSourceLinked_ = 1;
|
||||||
updateStatus(IDLE);
|
updateStatus(IDLE);
|
||||||
}
|
}
|
||||||
@@ -365,7 +410,8 @@ void ecmcFFT::dataUpdatedCallback(uint8_t* data,
|
|||||||
size_t dataElementSize = getEcDataTypeByteSize(dt);
|
size_t dataElementSize = getEcDataTypeByteSize(dt);
|
||||||
|
|
||||||
uint8_t *pData = data;
|
uint8_t *pData = data;
|
||||||
for(unsigned int i = 0; i < size / dataElementSize; ++i) {
|
for(unsigned int i = 0; i < size / dataElementSize; ++i) {
|
||||||
|
//printf("dataElementSize=%d, size=%d\n",dataElementSize,size);
|
||||||
switch(dt) {
|
switch(dt) {
|
||||||
case ECMC_EC_U8:
|
case ECMC_EC_U8:
|
||||||
addDataToBuffer((double)getUint8(pData));
|
addDataToBuffer((double)getUint8(pData));
|
||||||
@@ -406,7 +452,22 @@ void ecmcFFT::dataUpdatedCallback(uint8_t* data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ecmcFFT::addDataToBuffer(double data) {
|
void ecmcFFT::addDataToBuffer(double data) {
|
||||||
|
|
||||||
if(rawDataBuffer_ && (elementsInBuffer_ < cfgNfft_) ) {
|
if(rawDataBuffer_ && (elementsInBuffer_ < cfgNfft_) ) {
|
||||||
|
|
||||||
|
if( cfgBreakTableStr_ && interruptAccept ) {
|
||||||
|
double breakData = data;
|
||||||
|
// Supply a breaktable (init=0, LINR must be > 1 but only used if init > 0)
|
||||||
|
if (cvtRawToEngBpt(&breakData, 2, 0, &breakTable_, &lastBreakPoint_)!=0) {
|
||||||
|
//TODO: What does status here mean..
|
||||||
|
//throw std::runtime_error("Breaktable conversion failed.\n");
|
||||||
|
}
|
||||||
|
//printf("Index %d: Before %lf, after %lf\n",objectId_,data,breakData);
|
||||||
|
data = breakData * cfgScale_;
|
||||||
|
} else {
|
||||||
|
data = data * cfgScale_;
|
||||||
|
}
|
||||||
|
|
||||||
rawDataBuffer_[elementsInBuffer_] = data;
|
rawDataBuffer_[elementsInBuffer_] = data;
|
||||||
prepProcDataBuffer_[elementsInBuffer_] = data;
|
prepProcDataBuffer_[elementsInBuffer_] = data;
|
||||||
}
|
}
|
||||||
@@ -439,9 +500,10 @@ void ecmcFFT::calcFFT() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ecmcFFT::scaleFFT() {
|
void ecmcFFT::scaleFFT() {
|
||||||
if(!cfgApplyScale_) {
|
// Always scale
|
||||||
return;
|
//if(!cfgApplyScale_) {
|
||||||
}
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
for(unsigned int i = 0 ; i < cfgNfft_ ; ++i ) {
|
for(unsigned int i = 0 ; i < cfgNfft_ ; ++i ) {
|
||||||
fftBufferResult_[i] = fftBufferResult_[i] * scale_;
|
fftBufferResult_[i] = fftBufferResult_[i] * scale_;
|
||||||
@@ -456,10 +518,9 @@ void ecmcFFT::calcFFTAmp() {
|
|||||||
|
|
||||||
// Should be enough todo once
|
// Should be enough todo once
|
||||||
void ecmcFFT::calcFFTXAxis() {
|
void ecmcFFT::calcFFTXAxis() {
|
||||||
//fill x axis buffer with freqs
|
//fill x axis buffer with freqs
|
||||||
double freq = 0;
|
double freq = 0;
|
||||||
double deltaFreq = ecmcSampleRateHz_* ((double)dataItemInfo_->dataSize /
|
double deltaFreq = cfgDataSampleRateHz_ / ((double)(cfgNfft_));
|
||||||
(double)dataItemInfo_->dataElementSize) / ((double)(cfgNfft_));
|
|
||||||
for(unsigned int i = 0; i < (cfgNfft_ / 2 + 1); ++i) {
|
for(unsigned int i = 0; i < (cfgNfft_ / 2 + 1); ++i) {
|
||||||
fftBufferXAxis_[i] = freq;
|
fftBufferXAxis_[i] = freq;
|
||||||
freq = freq + deltaFreq;
|
freq = freq + deltaFreq;
|
||||||
@@ -731,7 +792,7 @@ void ecmcFFT::initAsyn() {
|
|||||||
if( createParam(0, paramName.c_str(), asynParamFloat64Array, &asynPPDataId_ ) != asynSuccess ) {
|
if( createParam(0, paramName.c_str(), asynParamFloat64Array, &asynPPDataId_ ) != asynSuccess ) {
|
||||||
throw std::runtime_error("Failed create asyn parameter preprocdata");
|
throw std::runtime_error("Failed create asyn parameter preprocdata");
|
||||||
}
|
}
|
||||||
doCallbacksFloat64Array(prepProcDataBuffer_, cfgNfft_, asynRawDataId_,0);
|
doCallbacksFloat64Array(prepProcDataBuffer_, cfgNfft_, asynPPDataId_,0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -742,9 +803,9 @@ void ecmcFFT::initAsyn() {
|
|||||||
if( createParam(0, paramName.c_str(), asynParamFloat64Array, &asynFFTAmpId_ ) != asynSuccess ) {
|
if( createParam(0, paramName.c_str(), asynParamFloat64Array, &asynFFTAmpId_ ) != asynSuccess ) {
|
||||||
throw std::runtime_error("Failed create asyn parameter fftamplitude");
|
throw std::runtime_error("Failed create asyn parameter fftamplitude");
|
||||||
}
|
}
|
||||||
doCallbacksFloat64Array(fftBufferResultAmp_, cfgNfft_/2+1, asynFFTXAxisId_,0);
|
doCallbacksFloat64Array(fftBufferResultAmp_, cfgNfft_/2+1, asynFFTAmpId_,0);
|
||||||
|
|
||||||
// Add fft mode "plugin.fft%d.mode"
|
// Add fft "plugin.fft%d.mode"
|
||||||
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
||||||
"." + ECMC_PLUGIN_ASYN_FFT_MODE;
|
"." + ECMC_PLUGIN_ASYN_FFT_MODE;
|
||||||
|
|
||||||
@@ -753,7 +814,7 @@ void ecmcFFT::initAsyn() {
|
|||||||
}
|
}
|
||||||
setIntegerParam(asynFFTModeId_, (epicsInt32)cfgMode_);
|
setIntegerParam(asynFFTModeId_, (epicsInt32)cfgMode_);
|
||||||
|
|
||||||
// Add fft mode "plugin.fft%d.status"
|
// Add fft "plugin.fft%d.status"
|
||||||
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
||||||
"." + ECMC_PLUGIN_ASYN_FFT_STAT;
|
"." + ECMC_PLUGIN_ASYN_FFT_STAT;
|
||||||
|
|
||||||
@@ -762,16 +823,16 @@ void ecmcFFT::initAsyn() {
|
|||||||
}
|
}
|
||||||
setIntegerParam(asynFFTStatId_, (epicsInt32)status_);
|
setIntegerParam(asynFFTStatId_, (epicsInt32)status_);
|
||||||
|
|
||||||
// Add fft mode "plugin.fft%d.source"
|
// Add fft "plugin.fft%d.source"
|
||||||
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
||||||
"." + ECMC_PLUGIN_ASYN_FFT_SOURCE;
|
"." + ECMC_PLUGIN_ASYN_FFT_SOURCE;
|
||||||
|
|
||||||
if( createParam(0, paramName.c_str(), asynParamInt8Array, &asynSourceId_ ) != asynSuccess ) {
|
if( createParam(0, paramName.c_str(), asynParamInt8Array, &asynSourceId_ ) != asynSuccess ) {
|
||||||
throw std::runtime_error("Failed create asyn parameter source");
|
throw std::runtime_error("Failed create asyn parameter source");
|
||||||
}
|
}
|
||||||
doCallbacksInt8Array(cfgDataSourceStr_, strlen(cfgDataSourceStr_), asynSourceId_,0);
|
doCallbacksInt8Array((epicsInt8*)cfgDataSourceStr_, strlen(cfgDataSourceStr_), asynSourceId_,0);
|
||||||
|
|
||||||
// Add fft mode "plugin.fft%d.trigg"
|
// Add fft "plugin.fft%d.trigg"
|
||||||
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
||||||
"." + ECMC_PLUGIN_ASYN_FFT_TRIGG;
|
"." + ECMC_PLUGIN_ASYN_FFT_TRIGG;
|
||||||
|
|
||||||
@@ -780,7 +841,7 @@ void ecmcFFT::initAsyn() {
|
|||||||
}
|
}
|
||||||
setIntegerParam(asynTriggId_, (epicsInt32)triggOnce_);
|
setIntegerParam(asynTriggId_, (epicsInt32)triggOnce_);
|
||||||
|
|
||||||
// Add fft mode "plugin.fft%d.fftxaxis"
|
// Add fft "plugin.fft%d.fftxaxis"
|
||||||
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
||||||
"." + ECMC_PLUGIN_ASYN_FFT_X_FREQS;
|
"." + ECMC_PLUGIN_ASYN_FFT_X_FREQS;
|
||||||
|
|
||||||
@@ -789,23 +850,32 @@ void ecmcFFT::initAsyn() {
|
|||||||
}
|
}
|
||||||
doCallbacksFloat64Array(fftBufferXAxis_,cfgNfft_ / 2 + 1, asynFFTXAxisId_,0);
|
doCallbacksFloat64Array(fftBufferXAxis_,cfgNfft_ / 2 + 1, asynFFTXAxisId_,0);
|
||||||
|
|
||||||
// Add fft mode "plugin.fft%d.nfft"
|
// Add fft "plugin.fft%d.nfft"
|
||||||
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
||||||
"." + ECMC_PLUGIN_ASYN_NFFT;
|
"." + ECMC_PLUGIN_ASYN_NFFT;
|
||||||
|
|
||||||
if( createParam(0, paramName.c_str(), asynParamInt32, &asynNfftId_ ) != asynSuccess ) {
|
if( createParam(0, paramName.c_str(), asynParamInt32, &asynNfftId_ ) != asynSuccess ) {
|
||||||
throw std::runtime_error("Failed create asyn parameter trigg");
|
throw std::runtime_error("Failed create asyn parameter nfft");
|
||||||
}
|
}
|
||||||
setIntegerParam(asynNfftId_, (epicsInt32)cfgNfft_);
|
setIntegerParam(asynNfftId_, (epicsInt32)cfgNfft_);
|
||||||
|
|
||||||
// Add fft mode "plugin.fft%d.rate"
|
// Add fft "plugin.fft%d.rate"
|
||||||
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
||||||
"." + ECMC_PLUGIN_ASYN_RATE;
|
"." + ECMC_PLUGIN_ASYN_RATE;
|
||||||
|
|
||||||
if( createParam(0, paramName.c_str(), asynParamInt32, &asynSRateId_ ) != asynSuccess ) {
|
if( createParam(0, paramName.c_str(), asynParamFloat64, &asynSRateId_ ) != asynSuccess ) {
|
||||||
|
throw std::runtime_error("Failed create asyn parameter rate");
|
||||||
|
}
|
||||||
|
setDoubleParam(asynSRateId_, cfgDataSampleRateHz_);
|
||||||
|
|
||||||
|
// Add fft "plugin.fft%d.buffid"
|
||||||
|
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
||||||
|
"." + ECMC_PLUGIN_ASYN_BUFF_ID;
|
||||||
|
|
||||||
|
if( createParam(0, paramName.c_str(), asynParamInt32, &asynElementsInBuffer_ ) != asynSuccess ) {
|
||||||
throw std::runtime_error("Failed create asyn parameter trigg");
|
throw std::runtime_error("Failed create asyn parameter trigg");
|
||||||
}
|
}
|
||||||
setDoubleParam(asynSRateId_, cfgFFTSampleRateHz_);
|
setIntegerParam(asynElementsInBuffer_, (epicsInt32)elementsInBuffer_);
|
||||||
|
|
||||||
// Update integers
|
// Update integers
|
||||||
callParamCallbacks();
|
callParamCallbacks();
|
||||||
@@ -841,6 +911,9 @@ FFT_STATUS ecmcFFT::getStatusFFT() {
|
|||||||
void ecmcFFT::updateStatus(FFT_STATUS status) {
|
void ecmcFFT::updateStatus(FFT_STATUS status) {
|
||||||
status_ = status;
|
status_ = status;
|
||||||
setIntegerParam(asynFFTStatId_,(epicsInt32) status);
|
setIntegerParam(asynFFTStatId_,(epicsInt32) status);
|
||||||
|
|
||||||
|
setIntegerParam(asynElementsInBuffer_, (epicsInt32)elementsInBuffer_);
|
||||||
|
|
||||||
callParamCallbacks();
|
callParamCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -916,6 +989,9 @@ asynStatus ecmcFFT::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
|||||||
}else if( function == asynNfftId_ ){
|
}else if( function == asynNfftId_ ){
|
||||||
*value = (epicsInt32)cfgNfft_;
|
*value = (epicsInt32)cfgNfft_;
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
|
}else if( function == asynElementsInBuffer_){
|
||||||
|
*value = (epicsInt32)elementsInBuffer_;
|
||||||
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
return asynError;
|
return asynError;
|
||||||
@@ -982,7 +1058,7 @@ asynStatus ecmcFFT::readInt8Array(asynUser *pasynUser, epicsInt8 *value,
|
|||||||
asynStatus ecmcFFT::readFloat64(asynUser *pasynUser, epicsFloat64 *value) {
|
asynStatus ecmcFFT::readFloat64(asynUser *pasynUser, epicsFloat64 *value) {
|
||||||
int function = pasynUser->reason;
|
int function = pasynUser->reason;
|
||||||
if( function == asynSRateId_ ) {
|
if( function == asynSRateId_ ) {
|
||||||
*value = cfgFFTSampleRateHz_;
|
*value = cfgDataSampleRateHz_;
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1017,4 +1093,28 @@ int ecmcFFT::leastSquare(int n, const double y[], double* k, double* m){
|
|||||||
*k = (n * sumxy - sumx * sumy) / denom;
|
*k = (n * sumxy - sumx * sumy) / denom;
|
||||||
*m = (sumy * sumx2 - sumx * sumxy) / denom;
|
*m = (sumy * sumx2 - sumx * sumxy) / denom;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ecmcFFT::verifyBreakTable() {
|
||||||
|
brkTable *pbrkTable;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for(pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
|
||||||
|
pbrkTable;
|
||||||
|
pbrkTable = (brkTable *)ellNext(&pbrkTable->node)){
|
||||||
|
if (strcmp(cfgBreakTableStr_,pbrkTable->name)==0)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
breakTable_ = pbrkTable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found) {
|
||||||
|
breakTable_ = NULL;
|
||||||
|
throw std::out_of_range("Breaktable not found...");
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "inttypes.h"
|
#include "inttypes.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "kissfft/kissfft.hh"
|
#include "kissfft/kissfft.hh"
|
||||||
|
#include "dbBase.h"
|
||||||
|
|
||||||
class ecmcFFT : public asynPortDriver {
|
class ecmcFFT : public asynPortDriver {
|
||||||
public:
|
public:
|
||||||
@@ -68,6 +69,7 @@ class ecmcFFT : public asynPortDriver {
|
|||||||
void initAsyn();
|
void initAsyn();
|
||||||
void updateStatus(FFT_STATUS status); // Also updates asynparam
|
void updateStatus(FFT_STATUS status); // Also updates asynparam
|
||||||
static int dataTypeSupported(ecmcEcDataType dt);
|
static int dataTypeSupported(ecmcEcDataType dt);
|
||||||
|
bool verifyBreakTable();
|
||||||
|
|
||||||
ecmcDataItem *dataItem_;
|
ecmcDataItem *dataItem_;
|
||||||
ecmcDataItemInfo *dataItemInfo_;
|
ecmcDataItemInfo *dataItemInfo_;
|
||||||
@@ -90,11 +92,14 @@ class ecmcFFT : public asynPortDriver {
|
|||||||
int triggOnce_;
|
int triggOnce_;
|
||||||
int cycleCounter_;
|
int cycleCounter_;
|
||||||
int ignoreCycles_;
|
int ignoreCycles_;
|
||||||
|
void *breakTable_;
|
||||||
|
short lastBreakPoint_;
|
||||||
double scale_; // Config: Data set size
|
double scale_; // Config: Data set size
|
||||||
FFT_STATUS status_; // Status/state (NO_STAT, IDLE, ACQ, CALC)
|
FFT_STATUS status_; // Status/state (NO_STAT, IDLE, ACQ, CALC)
|
||||||
|
|
||||||
// Config options
|
// Config options
|
||||||
char* cfgDataSourceStr_; // Config: data source string
|
char* cfgDataSourceStr_; // Config: data source string
|
||||||
|
char* cfgBreakTableStr_; // Config: EPICS breaktable name
|
||||||
int cfgDbgMode_; // Config: allow dbg printouts
|
int cfgDbgMode_; // Config: allow dbg printouts
|
||||||
int cfgApplyScale_; // Config: apply scale 1/nfft
|
int cfgApplyScale_; // Config: apply scale 1/nfft
|
||||||
int cfgDcRemove_; // Config: remove dc (average)
|
int cfgDcRemove_; // Config: remove dc (average)
|
||||||
@@ -102,7 +107,9 @@ class ecmcFFT : public asynPortDriver {
|
|||||||
size_t cfgNfft_; // Config: Data set size
|
size_t cfgNfft_; // Config: Data set size
|
||||||
int cfgEnable_; // Config: Enable data acq./calc.
|
int cfgEnable_; // Config: Enable data acq./calc.
|
||||||
FFT_MODE cfgMode_; // Config: Mode continous or triggered.
|
FFT_MODE cfgMode_; // Config: Mode continous or triggered.
|
||||||
double cfgFFTSampleRateHz_; // Config: Sample rate (defaukts to ecmc rate)
|
double cfgFFTSampleRateHz_; // Config: Sample rate (defaults to ecmc rate)
|
||||||
|
double cfgScale_;
|
||||||
|
double cfgDataSampleRateHz_; // Config: Sample for data
|
||||||
|
|
||||||
// Asyn
|
// Asyn
|
||||||
int asynEnableId_; // Enable/disable acq./calcs
|
int asynEnableId_; // Enable/disable acq./calcs
|
||||||
@@ -116,6 +123,7 @@ class ecmcFFT : public asynPortDriver {
|
|||||||
int asynFFTXAxisId_; // FFT X-axis frequencies
|
int asynFFTXAxisId_; // FFT X-axis frequencies
|
||||||
int asynNfftId_; // NFFT
|
int asynNfftId_; // NFFT
|
||||||
int asynSRateId_; // Sample rate
|
int asynSRateId_; // Sample rate
|
||||||
|
int asynElementsInBuffer_; // Current buffer index
|
||||||
|
|
||||||
// Thread related
|
// Thread related
|
||||||
epicsEvent doCalcEvent_;
|
epicsEvent doCalcEvent_;
|
||||||
@@ -18,11 +18,13 @@
|
|||||||
#define ECMC_PLUGIN_DBG_PRINT_OPTION_CMD "DBG_PRINT="
|
#define ECMC_PLUGIN_DBG_PRINT_OPTION_CMD "DBG_PRINT="
|
||||||
#define ECMC_PLUGIN_SOURCE_OPTION_CMD "SOURCE="
|
#define ECMC_PLUGIN_SOURCE_OPTION_CMD "SOURCE="
|
||||||
#define ECMC_PLUGIN_NFFT_OPTION_CMD "NFFT="
|
#define ECMC_PLUGIN_NFFT_OPTION_CMD "NFFT="
|
||||||
#define ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD "APPLY_SCALE="
|
//#define ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD "APPLY_SCALE="
|
||||||
#define ECMC_PLUGIN_RM_DC_OPTION_CMD "RM_DC="
|
#define ECMC_PLUGIN_RM_DC_OPTION_CMD "RM_DC="
|
||||||
#define ECMC_PLUGIN_ENABLE_OPTION_CMD "ENABLE="
|
#define ECMC_PLUGIN_ENABLE_OPTION_CMD "ENABLE="
|
||||||
#define ECMC_PLUGIN_RATE_OPTION_CMD "RATE="
|
#define ECMC_PLUGIN_RATE_OPTION_CMD "RATE="
|
||||||
#define ECMC_PLUGIN_RM_LIN_OPTION_CMD "RM_LIN="
|
#define ECMC_PLUGIN_RM_LIN_OPTION_CMD "RM_LIN="
|
||||||
|
#define ECMC_PLUGIN_SCALE_OPTION_CMD "SCALE="
|
||||||
|
#define ECMC_PLUGIN_BREAKTABLE_OPTION_CMD "BREAKTABLE="
|
||||||
|
|
||||||
// CONT, TRIGG
|
// CONT, TRIGG
|
||||||
#define ECMC_PLUGIN_MODE_OPTION_CMD "MODE="
|
#define ECMC_PLUGIN_MODE_OPTION_CMD "MODE="
|
||||||
@@ -3,11 +3,13 @@
|
|||||||
* ecmc is distributed subject to a Software License Agreement found
|
* ecmc is distributed subject to a Software License Agreement found
|
||||||
* in file LICENSE that is included with this distribution.
|
* in file LICENSE that is included with this distribution.
|
||||||
*
|
*
|
||||||
* ecmcPluginExample.cpp
|
* ecmcPluginFFT.cpp
|
||||||
*
|
*
|
||||||
* Created on: Mar 21, 2020
|
* Created on: Mar 21, 2020
|
||||||
* Author: anderssandstrom
|
* Author: anderssandstrom
|
||||||
*
|
* Instructions:
|
||||||
|
* - IMPORTANT: Add "USR_CFLAGS +=-DECMC_PLUGIN_MODULE_NAME=${MODULE}" to GNUMakefile
|
||||||
|
* - All functions and ecmcPluginData struct must be declared static
|
||||||
\*************************************************************************/
|
\*************************************************************************/
|
||||||
|
|
||||||
// Needed to get headers in ecmc right...
|
// Needed to get headers in ecmc right...
|
||||||
@@ -30,11 +32,11 @@ static int lastEcmcError = 0;
|
|||||||
static char* lastConfStr = NULL;
|
static char* lastConfStr = NULL;
|
||||||
|
|
||||||
/** Optional.
|
/** Optional.
|
||||||
* Will be called once after successfull load into ecmc.
|
* Will be called once after successful load into ecmc.
|
||||||
* Return value other than 0 will be considered error.
|
* Return value other than 0 will be considered error.
|
||||||
* configStr can be used for configuration parameters.
|
* configStr can be used for configuration parameters.
|
||||||
**/
|
**/
|
||||||
int fftConstruct(char *configStr)
|
static int fftConstruct(char *configStr)
|
||||||
{
|
{
|
||||||
//This module is allowed to load several times so no need to check if loaded
|
//This module is allowed to load several times so no need to check if loaded
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@ int fftConstruct(char *configStr)
|
|||||||
/** Optional function.
|
/** Optional function.
|
||||||
* Will be called once at unload.
|
* Will be called once at unload.
|
||||||
**/
|
**/
|
||||||
void fftDestruct(void)
|
static void fftDestruct(void)
|
||||||
{
|
{
|
||||||
deleteAllFFTs();
|
deleteAllFFTs();
|
||||||
if(lastConfStr){
|
if(lastConfStr){
|
||||||
@@ -55,12 +57,12 @@ void fftDestruct(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Optional function.
|
/** Optional function.
|
||||||
* Will be called each realtime cycle if definded
|
* Will be called each realtime cycle if defined
|
||||||
* ecmcError: Error code of ecmc. Makes it posible for
|
* ecmcError: Error code of ecmc. Makes it possible for
|
||||||
* this plugin to react on ecmc errors
|
* this plugin to react on ecmc errors
|
||||||
* Return value other than 0 will be considered to be an error code in ecmc.
|
* Return value other than 0 will be considered to be an error code in ecmc.
|
||||||
**/
|
**/
|
||||||
int fftRealtime(int ecmcError)
|
static int fftRealtime(int ecmcError)
|
||||||
{
|
{
|
||||||
lastEcmcError = ecmcError;
|
lastEcmcError = ecmcError;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -69,7 +71,7 @@ int fftRealtime(int ecmcError)
|
|||||||
/** Link to data source here since all sources should be availabe at this stage
|
/** Link to data source here since all sources should be availabe at this stage
|
||||||
* (for example ecmc PLC variables are defined only at enter of realtime)
|
* (for example ecmc PLC variables are defined only at enter of realtime)
|
||||||
**/
|
**/
|
||||||
int fftEnterRT(){
|
static int fftEnterRT(){
|
||||||
return linkDataToFFTs();
|
return linkDataToFFTs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,53 +79,54 @@ int fftEnterRT(){
|
|||||||
* Will be called once just before leaving realtime mode
|
* Will be called once just before leaving realtime mode
|
||||||
* Return value other than 0 will be considered error.
|
* Return value other than 0 will be considered error.
|
||||||
**/
|
**/
|
||||||
int fftExitRT(void){
|
static int fftExitRT(void){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plc function for clear of buffers
|
// Plc function for clear of buffers
|
||||||
double fft_clear(double index) {
|
static double fft_clear(double index) {
|
||||||
return (double)clearFFT((int)index);
|
return (double)clearFFT((int)index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plc function for enable
|
// Plc function for enable
|
||||||
double fft_enable(double index, double enable) {
|
static double fft_enable(double index, double enable) {
|
||||||
return (double)enableFFT((int)index, (int)enable);
|
return (double)enableFFT((int)index, (int)enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plc function for trigg new measurement (will clear buffers)
|
// Plc function for trigg new measurement (will clear buffers)
|
||||||
double fft_trigg(double index) {
|
static double fft_trigg(double index) {
|
||||||
return (double)triggFFT((int)index);
|
return (double)triggFFT((int)index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plc function for enable
|
// Plc function for enable
|
||||||
double fft_mode(double index, double mode) {
|
static double fft_mode(double index, double mode) {
|
||||||
return (double)modeFFT((int)index, (FFT_MODE)((int)mode));
|
return (double)modeFFT((int)index, (FFT_MODE)((int)mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plc function for enable
|
// Plc function for enable
|
||||||
double fft_stat(double index) {
|
static double fft_stat(double index) {
|
||||||
return (double)statFFT((int)index);
|
return (double)statFFT((int)index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register data for plugin so ecmc know what to use
|
// Register data for plugin so ecmc know what to use
|
||||||
struct ecmcPluginData pluginDataDef = {
|
static struct ecmcPluginData pluginDataDef = {
|
||||||
// Allways use ECMC_PLUG_VERSION_MAGIC
|
// Allways use ECMC_PLUG_VERSION_MAGIC
|
||||||
.ifVersion = ECMC_PLUG_VERSION_MAGIC,
|
.ifVersion = ECMC_PLUG_VERSION_MAGIC,
|
||||||
// Name
|
// Name
|
||||||
.name = "ecmcPlugin_FFT",
|
.name = "ecmc_plugin_fft",
|
||||||
// Description
|
// Description
|
||||||
.desc = "FFT plugin for use with ecmc.",
|
.desc = "FFT plugin for use with ecmc.",
|
||||||
// Option description
|
// Option description
|
||||||
.optionDesc = "\n "ECMC_PLUGIN_DBG_PRINT_OPTION_CMD"<1/0> : Enables/disables printouts from plugin, default = disabled.\n"
|
.optionDesc = "\n "ECMC_PLUGIN_DBG_PRINT_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_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_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_SCALE_OPTION_CMD"scalefactor : Apply scale to source data, default = 1.0.\n"
|
||||||
" "ECMC_PLUGIN_RM_DC_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_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_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_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."
|
" "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.\n"
|
||||||
|
" "ECMC_PLUGIN_BREAKTABLE_OPTION_CMD"<brktab> : Use epics breaktable to convert raw values (applied before any other signal cond. alg.), default not used."
|
||||||
,
|
,
|
||||||
// Plugin version
|
// Plugin version
|
||||||
.version = ECMC_EXAMPLE_PLUGIN_VERSION,
|
.version = ECMC_EXAMPLE_PLUGIN_VERSION,
|
||||||
@@ -158,7 +161,8 @@ struct ecmcPluginData pluginDataDef = {
|
|||||||
.funcArg7 = NULL,
|
.funcArg7 = NULL,
|
||||||
.funcArg8 = NULL,
|
.funcArg8 = NULL,
|
||||||
.funcArg9 = NULL,
|
.funcArg9 = NULL,
|
||||||
.funcArg10 = NULL,
|
.funcArg10 = NULL,
|
||||||
|
.funcGenericObj = NULL,
|
||||||
},
|
},
|
||||||
.funcs[1] =
|
.funcs[1] =
|
||||||
{ /*----fft_enable----*/
|
{ /*----fft_enable----*/
|
||||||
@@ -180,7 +184,8 @@ struct ecmcPluginData pluginDataDef = {
|
|||||||
.funcArg7 = NULL,
|
.funcArg7 = NULL,
|
||||||
.funcArg8 = NULL,
|
.funcArg8 = NULL,
|
||||||
.funcArg9 = NULL,
|
.funcArg9 = NULL,
|
||||||
.funcArg10 = NULL,
|
.funcArg10 = NULL,
|
||||||
|
.funcGenericObj = NULL,
|
||||||
},
|
},
|
||||||
.funcs[2] =
|
.funcs[2] =
|
||||||
{ /*----fft_trigg----*/
|
{ /*----fft_trigg----*/
|
||||||
@@ -202,7 +207,8 @@ struct ecmcPluginData pluginDataDef = {
|
|||||||
.funcArg7 = NULL,
|
.funcArg7 = NULL,
|
||||||
.funcArg8 = NULL,
|
.funcArg8 = NULL,
|
||||||
.funcArg9 = NULL,
|
.funcArg9 = NULL,
|
||||||
.funcArg10 = NULL,
|
.funcArg10 = NULL,
|
||||||
|
.funcGenericObj = NULL,
|
||||||
},
|
},
|
||||||
.funcs[3] =
|
.funcs[3] =
|
||||||
{ /*----fft_mode----*/
|
{ /*----fft_mode----*/
|
||||||
@@ -224,7 +230,8 @@ struct ecmcPluginData pluginDataDef = {
|
|||||||
.funcArg7 = NULL,
|
.funcArg7 = NULL,
|
||||||
.funcArg8 = NULL,
|
.funcArg8 = NULL,
|
||||||
.funcArg9 = NULL,
|
.funcArg9 = NULL,
|
||||||
.funcArg10 = NULL,
|
.funcArg10 = NULL,
|
||||||
|
.funcGenericObj = NULL,
|
||||||
},
|
},
|
||||||
.funcs[4] =
|
.funcs[4] =
|
||||||
{ /*----fft_stat----*/
|
{ /*----fft_stat----*/
|
||||||
@@ -246,7 +253,8 @@ struct ecmcPluginData pluginDataDef = {
|
|||||||
.funcArg7 = NULL,
|
.funcArg7 = NULL,
|
||||||
.funcArg8 = NULL,
|
.funcArg8 = NULL,
|
||||||
.funcArg9 = NULL,
|
.funcArg9 = NULL,
|
||||||
.funcArg10 = NULL,
|
.funcArg10 = NULL,
|
||||||
|
.funcGenericObj = NULL,
|
||||||
},
|
},
|
||||||
.funcs[5] = {0}, // last element set all to zero..
|
.funcs[5] = {0}, // last element set all to zero..
|
||||||
// PLC consts
|
// PLC consts
|
||||||
8
tools/README.md
Normal file
8
tools/README.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# FFT tools
|
||||||
|
|
||||||
|
## GUI
|
||||||
|
|
||||||
|
A python gui for vizualization and control of the FFT plugin can be found in the ecmccomgui repo:
|
||||||
|
https://github.com/anderssandstrom/ecmccomgui
|
||||||
|
|
||||||
|

|
||||||
Reference in New Issue
Block a user