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/
|
||||
*PVs.list
|
||||
*-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
|
||||
|
||||
@@ -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.
|
||||
* DBG_PRINT=1/0 : Enables/disables printouts from plugin, default = disabled.
|
||||
* 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_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.
|
||||
* BREAKTABLE= EPICS breaktable : Apply breaktable to raw value.
|
||||
|
||||
Example configuration string:
|
||||
```
|
||||
@@ -74,7 +75,7 @@ Example: Ethercat slave 1 analog input ch1
|
||||
#### DBG_PRINT (default: disabled)
|
||||
Enable/disable printouts from plugin can be made bu setting the "DBG_PRINT" option.
|
||||
|
||||
Exmaple: Disable
|
||||
Example: Disable
|
||||
```
|
||||
"DBG_PRINT=0;SOURCE=ax1.poserr;"
|
||||
```
|
||||
@@ -84,23 +85,23 @@ Defines number of samples for each measurement.
|
||||
|
||||
Note: Must be a n² number..
|
||||
|
||||
Exmaple: 1024
|
||||
Example: 1024
|
||||
```
|
||||
"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).
|
||||
#### SCALE (default 1.0)
|
||||
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
|
||||
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
|
||||
@@ -108,22 +109,22 @@ 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
|
||||
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 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
|
||||
```
|
||||
Exmaple: Enable FFT index 0 from ecmc PLC code:
|
||||
Example: Enable FFT index 0 from ecmc PLC code:
|
||||
```
|
||||
fft_enable(0,1)
|
||||
```
|
||||
@@ -152,11 +153,11 @@ Triggered mode:
|
||||
5. FTT results are sent by callback over asyn to epics records
|
||||
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
|
||||
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.
|
||||
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
|
||||
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.
|
||||
@@ -216,6 +251,7 @@ Note: The FFT asynparameters will not be visible by the ecmcReport iocsh command
|
||||
## PLC interface
|
||||
|
||||
### PLC Functions
|
||||
|
||||
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].
|
||||
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);
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
```
|
||||
@@ -279,7 +386,7 @@ Plugin info:
|
||||
DBG_PRINT=<1/0> : Enables/disables printouts from plugin, default = disabled.
|
||||
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.
|
||||
SCALE=<1/0> : Apply scale, 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
EPICS_MODULE_NAME:=ecmcPlugin_FFT
|
||||
EPICS_MODULE_NAME:=ecmc_plugin_fft
|
||||
|
||||
EPICS_MODULE_TAG:=master
|
||||
#
|
||||
@@ -8,8 +8,8 @@ E3_MODULE_VERSION:=master
|
||||
# DEPENDENT MODULE VERSION
|
||||
# For Example,
|
||||
|
||||
ECMC_DEP_VERSION:=master
|
||||
ASYN_DEP_VERSION:=4.36.0
|
||||
ECMC_DEP_VERSION:=develop
|
||||
ASYN_DEP_VERSION:=4.37.0
|
||||
|
||||
#DEVLIB2_DEP_VERSION:=2.9.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_SRC_PATH:=ecmcPlugin_FFT-loc
|
||||
E3_MODULE_SRC_PATH:=ecmc_plugin_fft
|
||||
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_VERSION:=3.1.2
|
||||
E3_REQUIRE_VERSION:=3.4.0
|
||||
|
||||
# The definitions shown below can also be placed in an untracked 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("SCRIPTEXEC" ,"$(SCRIPTEXEC="iocshLoad")")
|
||||
|
||||
require ecmccfg master
|
||||
require ecmccfg "6.3.0"
|
||||
|
||||
##############################################################################
|
||||
###### Startup
|
||||
require ecmc "master"
|
||||
require stream "${stream_VER=2.8.10}"
|
||||
require ecmc "6.3.0"
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
#- define default PATH for scripts and database/templates
|
||||
@@ -41,29 +40,30 @@ ecmcConfigOrDie "Cfg.SetSampleRate(${ECMC_EC_SAMPLE_RATE})"
|
||||
# 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)
|
||||
|
||||
########################################################################s######
|
||||
## 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_CONFIG,"SOURCE=plcs.plc0.static.sineval;DBG_PRINT=0;NFFT=1024;RATE=100;DC_REMOVE=1;APPLY_SCALE=1;MODE=CONT;")
|
||||
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;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"
|
||||
# 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######
|
||||
## 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_CONFIG,"SOURCE=ecmc.thread.latency.max;DBG_PRINT=0;NFFT=1024;")
|
||||
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;ENABLE=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
|
||||
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_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'")
|
||||
|
||||
##############################################################################
|
||||
@@ -80,4 +80,4 @@ dbLoadRecords("ecmcGeneral.db","P=${ECMC_PREFIX},PORT=${ECMC_ASYN_PORT},ADDR=0,T
|
||||
ecmcConfigOrDie "Cfg.SetAppMode(1)"
|
||||
|
||||
iocInit
|
||||
|
||||
dbl > pvs.log
|
||||
|
||||
@@ -23,7 +23,7 @@ record(waveform,"$(P)Plugin-FFT${INDEX}-Source"){
|
||||
# Rawdata
|
||||
record(waveform,"$(P)Plugin-FFT${INDEX}-Raw-Data-Act"){
|
||||
info(asyn:FIFO, "1000")
|
||||
field(DESC, "Raw data")
|
||||
field(DESC, "${RAW_DESC="Raw data"}")
|
||||
field(PINI, "1")
|
||||
field(DTYP, "asynFloat64ArrayIn")
|
||||
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(SCAN, "I/O Intr")
|
||||
field(TSE, "0")
|
||||
field(EGU, "${RAW_EGU= }")
|
||||
}
|
||||
|
||||
# Pre-processed data
|
||||
@@ -49,7 +50,7 @@ record(waveform,"$(P)Plugin-FFT${INDEX}-PreProc-Data-Act"){
|
||||
# FFT amplitude result
|
||||
record(waveform,"$(P)Plugin-FFT${INDEX}-Spectrum-Amp-Act"){
|
||||
info(asyn:FIFO, "1000")
|
||||
field(DESC, "FFT spectrum amplitude result")
|
||||
field(DESC, "${AMP_DESC="Spectrum amplitude"}")
|
||||
field(PINI, "1")
|
||||
field(DTYP, "asynFloat64ArrayIn")
|
||||
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(SCAN, "I/O Intr")
|
||||
field(TSE, "0")
|
||||
field(EGU, "${AMP_EGU= }")
|
||||
}
|
||||
|
||||
# FFT xaxis
|
||||
record(waveform,"$(P)Plugin-FFT${INDEX}-Spectrum-X-Axis-Act"){
|
||||
info(asyn:FIFO, "1000")
|
||||
field(DESC, "Raw data")
|
||||
field(DESC, "X-Axis data")
|
||||
field(EGU, "Hz")
|
||||
field(PINI, "1")
|
||||
field(DTYP, "asynFloat64ArrayIn")
|
||||
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"){
|
||||
info(asyn:READBACK,"1")
|
||||
field(DESC, "FFT Enable")
|
||||
field(DTYP,"asynInt32")
|
||||
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")
|
||||
}
|
||||
|
||||
# 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_NFFT "nfft"
|
||||
#define ECMC_PLUGIN_ASYN_RATE "samplerate"
|
||||
#define ECMC_PLUGIN_ASYN_BUFF_ID "buffid"
|
||||
|
||||
|
||||
#include <sstream>
|
||||
#include "ecmcFFT.h"
|
||||
#include "ecmcPluginClient.h"
|
||||
#include "ecmcAsynPortDriver.h"
|
||||
#include "ecmcAsynPortDriverUtils.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
|
||||
static int printMissingObjError = 1;
|
||||
@@ -90,6 +103,7 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
|
||||
0) /* Default stack size */
|
||||
{
|
||||
cfgDataSourceStr_ = NULL;
|
||||
cfgBreakTableStr_ = NULL;
|
||||
rawDataBuffer_ = NULL;
|
||||
dataItem_ = NULL;
|
||||
dataItemInfo_ = NULL;
|
||||
@@ -105,6 +119,8 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
|
||||
cycleCounter_ = 0;
|
||||
ignoreCycles_ = 0;
|
||||
dataSourceLinked_ = 0;
|
||||
breakTable_ = NULL;
|
||||
lastBreakPoint_ = 0;
|
||||
|
||||
// Asyn
|
||||
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
|
||||
asynNfftId_ = -1; // Nfft
|
||||
asynSRateId_ = -1; // Sample rate Hz
|
||||
asynElementsInBuffer_= -1;
|
||||
|
||||
ecmcSampleRateHz_ = getEcmcSampleRate();
|
||||
cfgFFTSampleRateHz_ = ecmcSampleRateHz_;
|
||||
ecmcSampleRateHz_ = getEcmcSampleRate();
|
||||
cfgFFTSampleRateHz_ = ecmcSampleRateHz_;
|
||||
cfgDataSampleRateHz_ = ecmcSampleRateHz_;
|
||||
|
||||
// Config defaults
|
||||
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
|
||||
//cfgApplyScale_ = 1; // Scale as default to get correct amplitude in fft
|
||||
cfgEnable_ = 0; // start disabled (enable over asyn)
|
||||
cfgMode_ = TRIGG;
|
||||
cfgScale_ = 1.0;
|
||||
|
||||
parseConfigStr(configStr); // Assigns all configs
|
||||
// Check valid nfft
|
||||
@@ -146,6 +165,11 @@ ecmcFFT::ecmcFFT(int fftIndex, // index of this object (if several is cr
|
||||
cfgFFTSampleRateHz_ = ecmcSampleRateHz_;
|
||||
}
|
||||
|
||||
// Check if breaktable
|
||||
if(cfgBreakTableStr_) {
|
||||
verifyBreakTable();
|
||||
}
|
||||
|
||||
// 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;
|
||||
@@ -194,6 +218,9 @@ ecmcFFT::~ecmcFFT() {
|
||||
if(cfgDataSourceStr_) {
|
||||
free(cfgDataSourceStr_);
|
||||
}
|
||||
if(cfgBreakTableStr_) {
|
||||
free(cfgBreakTableStr_);
|
||||
}
|
||||
if(fftDouble_) {
|
||||
delete fftDouble_;
|
||||
}
|
||||
@@ -229,17 +256,23 @@ void ecmcFFT::parseConfigStr(char *configStr) {
|
||||
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)
|
||||
else if (!strncmp(pThisOption, ECMC_PLUGIN_NFFT_OPTION_CMD, strlen(ECMC_PLUGIN_NFFT_OPTION_CMD))) {
|
||||
pThisOption += strlen(ECMC_PLUGIN_NFFT_OPTION_CMD);
|
||||
cfgNfft_ = atoi(pThisOption);
|
||||
}
|
||||
|
||||
// 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))) {
|
||||
pThisOption += strlen(ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD);
|
||||
cfgApplyScale_ = atoi(pThisOption);
|
||||
}
|
||||
// // 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))) {
|
||||
// pThisOption += strlen(ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD);
|
||||
// cfgApplyScale_ = atoi(pThisOption);
|
||||
// }
|
||||
|
||||
// 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))) {
|
||||
@@ -276,6 +309,12 @@ void ecmcFFT::parseConfigStr(char *configStr) {
|
||||
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;
|
||||
}
|
||||
free(pOptions);
|
||||
@@ -293,7 +332,7 @@ void ecmcFFT::connectToDataSource() {
|
||||
if( dataSourceLinked_ ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Get dataItem
|
||||
dataItem_ = (ecmcDataItem*) getEcmcDataItem(cfgDataSourceStr_);
|
||||
if(!dataItem_) {
|
||||
@@ -312,6 +351,12 @@ void ecmcFFT::connectToDataSource() {
|
||||
if( !dataTypeSupported(dataItem_->getEcmcDataType()) ) {
|
||||
throw std::invalid_argument( "Data type not supported." );
|
||||
}
|
||||
|
||||
// Add oversampling
|
||||
cfgDataSampleRateHz_ = cfgFFTSampleRateHz_ * dataItem_->getEcmcDataSize()/dataItem_->getEcmcDataElementSize();
|
||||
setDoubleParam(asynSRateId_, cfgDataSampleRateHz_);
|
||||
callParamCallbacks();
|
||||
|
||||
dataSourceLinked_ = 1;
|
||||
updateStatus(IDLE);
|
||||
}
|
||||
@@ -365,7 +410,8 @@ void ecmcFFT::dataUpdatedCallback(uint8_t* data,
|
||||
size_t dataElementSize = getEcDataTypeByteSize(dt);
|
||||
|
||||
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) {
|
||||
case ECMC_EC_U8:
|
||||
addDataToBuffer((double)getUint8(pData));
|
||||
@@ -406,7 +452,22 @@ void ecmcFFT::dataUpdatedCallback(uint8_t* data,
|
||||
}
|
||||
|
||||
void ecmcFFT::addDataToBuffer(double data) {
|
||||
|
||||
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;
|
||||
prepProcDataBuffer_[elementsInBuffer_] = data;
|
||||
}
|
||||
@@ -439,9 +500,10 @@ void ecmcFFT::calcFFT() {
|
||||
}
|
||||
|
||||
void ecmcFFT::scaleFFT() {
|
||||
if(!cfgApplyScale_) {
|
||||
return;
|
||||
}
|
||||
// Always scale
|
||||
//if(!cfgApplyScale_) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
for(unsigned int i = 0 ; i < cfgNfft_ ; ++i ) {
|
||||
fftBufferResult_[i] = fftBufferResult_[i] * scale_;
|
||||
@@ -456,10 +518,9 @@ void ecmcFFT::calcFFTAmp() {
|
||||
|
||||
// Should be enough todo once
|
||||
void ecmcFFT::calcFFTXAxis() {
|
||||
//fill x axis buffer with freqs
|
||||
//fill x axis buffer with freqs
|
||||
double freq = 0;
|
||||
double deltaFreq = ecmcSampleRateHz_* ((double)dataItemInfo_->dataSize /
|
||||
(double)dataItemInfo_->dataElementSize) / ((double)(cfgNfft_));
|
||||
double deltaFreq = cfgDataSampleRateHz_ / ((double)(cfgNfft_));
|
||||
for(unsigned int i = 0; i < (cfgNfft_ / 2 + 1); ++i) {
|
||||
fftBufferXAxis_[i] = freq;
|
||||
freq = freq + deltaFreq;
|
||||
@@ -731,7 +792,7 @@ void ecmcFFT::initAsyn() {
|
||||
if( createParam(0, paramName.c_str(), asynParamFloat64Array, &asynPPDataId_ ) != asynSuccess ) {
|
||||
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 ) {
|
||||
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_) +
|
||||
"." + ECMC_PLUGIN_ASYN_FFT_MODE;
|
||||
|
||||
@@ -753,7 +814,7 @@ void ecmcFFT::initAsyn() {
|
||||
}
|
||||
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_) +
|
||||
"." + ECMC_PLUGIN_ASYN_FFT_STAT;
|
||||
|
||||
@@ -762,16 +823,16 @@ void ecmcFFT::initAsyn() {
|
||||
}
|
||||
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_) +
|
||||
"." + ECMC_PLUGIN_ASYN_FFT_SOURCE;
|
||||
|
||||
if( createParam(0, paramName.c_str(), asynParamInt8Array, &asynSourceId_ ) != asynSuccess ) {
|
||||
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_) +
|
||||
"." + ECMC_PLUGIN_ASYN_FFT_TRIGG;
|
||||
|
||||
@@ -780,7 +841,7 @@ void ecmcFFT::initAsyn() {
|
||||
}
|
||||
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_) +
|
||||
"." + ECMC_PLUGIN_ASYN_FFT_X_FREQS;
|
||||
|
||||
@@ -789,23 +850,32 @@ void ecmcFFT::initAsyn() {
|
||||
}
|
||||
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_) +
|
||||
"." + ECMC_PLUGIN_ASYN_NFFT;
|
||||
|
||||
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_);
|
||||
|
||||
// Add fft mode "plugin.fft%d.rate"
|
||||
// Add fft "plugin.fft%d.rate"
|
||||
paramName = ECMC_PLUGIN_ASYN_PREFIX + to_string(objectId_) +
|
||||
"." + 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");
|
||||
}
|
||||
setDoubleParam(asynSRateId_, cfgFFTSampleRateHz_);
|
||||
setIntegerParam(asynElementsInBuffer_, (epicsInt32)elementsInBuffer_);
|
||||
|
||||
// Update integers
|
||||
callParamCallbacks();
|
||||
@@ -841,6 +911,9 @@ FFT_STATUS ecmcFFT::getStatusFFT() {
|
||||
void ecmcFFT::updateStatus(FFT_STATUS status) {
|
||||
status_ = status;
|
||||
setIntegerParam(asynFFTStatId_,(epicsInt32) status);
|
||||
|
||||
setIntegerParam(asynElementsInBuffer_, (epicsInt32)elementsInBuffer_);
|
||||
|
||||
callParamCallbacks();
|
||||
}
|
||||
|
||||
@@ -916,6 +989,9 @@ asynStatus ecmcFFT::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
||||
}else if( function == asynNfftId_ ){
|
||||
*value = (epicsInt32)cfgNfft_;
|
||||
return asynSuccess;
|
||||
}else if( function == asynElementsInBuffer_){
|
||||
*value = (epicsInt32)elementsInBuffer_;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
return asynError;
|
||||
@@ -982,7 +1058,7 @@ asynStatus ecmcFFT::readInt8Array(asynUser *pasynUser, epicsInt8 *value,
|
||||
asynStatus ecmcFFT::readFloat64(asynUser *pasynUser, epicsFloat64 *value) {
|
||||
int function = pasynUser->reason;
|
||||
if( function == asynSRateId_ ) {
|
||||
*value = cfgFFTSampleRateHz_;
|
||||
*value = cfgDataSampleRateHz_;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
@@ -1017,4 +1093,28 @@ int ecmcFFT::leastSquare(int n, const double y[], double* k, double* m){
|
||||
*k = (n * sumxy - sumx * sumy) / denom;
|
||||
*m = (sumy * sumx2 - sumx * sumxy) / denom;
|
||||
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 <string>
|
||||
#include "kissfft/kissfft.hh"
|
||||
#include "dbBase.h"
|
||||
|
||||
class ecmcFFT : public asynPortDriver {
|
||||
public:
|
||||
@@ -68,6 +69,7 @@ class ecmcFFT : public asynPortDriver {
|
||||
void initAsyn();
|
||||
void updateStatus(FFT_STATUS status); // Also updates asynparam
|
||||
static int dataTypeSupported(ecmcEcDataType dt);
|
||||
bool verifyBreakTable();
|
||||
|
||||
ecmcDataItem *dataItem_;
|
||||
ecmcDataItemInfo *dataItemInfo_;
|
||||
@@ -90,11 +92,14 @@ class ecmcFFT : public asynPortDriver {
|
||||
int triggOnce_;
|
||||
int cycleCounter_;
|
||||
int ignoreCycles_;
|
||||
void *breakTable_;
|
||||
short lastBreakPoint_;
|
||||
double scale_; // Config: Data set size
|
||||
FFT_STATUS status_; // Status/state (NO_STAT, IDLE, ACQ, CALC)
|
||||
|
||||
// Config options
|
||||
char* cfgDataSourceStr_; // Config: data source string
|
||||
char* cfgBreakTableStr_; // Config: EPICS breaktable name
|
||||
int cfgDbgMode_; // Config: allow dbg printouts
|
||||
int cfgApplyScale_; // Config: apply scale 1/nfft
|
||||
int cfgDcRemove_; // Config: remove dc (average)
|
||||
@@ -102,7 +107,9 @@ class ecmcFFT : public asynPortDriver {
|
||||
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)
|
||||
double cfgFFTSampleRateHz_; // Config: Sample rate (defaults to ecmc rate)
|
||||
double cfgScale_;
|
||||
double cfgDataSampleRateHz_; // Config: Sample for data
|
||||
|
||||
// Asyn
|
||||
int asynEnableId_; // Enable/disable acq./calcs
|
||||
@@ -116,6 +123,7 @@ class ecmcFFT : public asynPortDriver {
|
||||
int asynFFTXAxisId_; // FFT X-axis frequencies
|
||||
int asynNfftId_; // NFFT
|
||||
int asynSRateId_; // Sample rate
|
||||
int asynElementsInBuffer_; // Current buffer index
|
||||
|
||||
// Thread related
|
||||
epicsEvent doCalcEvent_;
|
||||
@@ -18,11 +18,13 @@
|
||||
#define ECMC_PLUGIN_DBG_PRINT_OPTION_CMD "DBG_PRINT="
|
||||
#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_APPLY_SCALE_OPTION_CMD "APPLY_SCALE="
|
||||
#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="
|
||||
#define ECMC_PLUGIN_SCALE_OPTION_CMD "SCALE="
|
||||
#define ECMC_PLUGIN_BREAKTABLE_OPTION_CMD "BREAKTABLE="
|
||||
|
||||
// CONT, TRIGG
|
||||
#define ECMC_PLUGIN_MODE_OPTION_CMD "MODE="
|
||||
@@ -3,11 +3,13 @@
|
||||
* ecmc is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*
|
||||
* ecmcPluginExample.cpp
|
||||
* ecmcPluginFFT.cpp
|
||||
*
|
||||
* Created on: Mar 21, 2020
|
||||
* 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...
|
||||
@@ -30,11 +32,11 @@ static int lastEcmcError = 0;
|
||||
static char* lastConfStr = NULL;
|
||||
|
||||
/** 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.
|
||||
* 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
|
||||
|
||||
@@ -46,7 +48,7 @@ int fftConstruct(char *configStr)
|
||||
/** Optional function.
|
||||
* Will be called once at unload.
|
||||
**/
|
||||
void fftDestruct(void)
|
||||
static void fftDestruct(void)
|
||||
{
|
||||
deleteAllFFTs();
|
||||
if(lastConfStr){
|
||||
@@ -55,12 +57,12 @@ void fftDestruct(void)
|
||||
}
|
||||
|
||||
/** Optional function.
|
||||
* Will be called each realtime cycle if definded
|
||||
* ecmcError: Error code of ecmc. Makes it posible for
|
||||
* Will be called each realtime cycle if defined
|
||||
* ecmcError: Error code of ecmc. Makes it possible for
|
||||
* this plugin to react on ecmc errors
|
||||
* 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;
|
||||
return 0;
|
||||
@@ -69,7 +71,7 @@ int fftRealtime(int ecmcError)
|
||||
/** 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)
|
||||
**/
|
||||
int fftEnterRT(){
|
||||
static int fftEnterRT(){
|
||||
return linkDataToFFTs();
|
||||
}
|
||||
|
||||
@@ -77,53 +79,54 @@ int fftEnterRT(){
|
||||
* Will be called once just before leaving realtime mode
|
||||
* Return value other than 0 will be considered error.
|
||||
**/
|
||||
int fftExitRT(void){
|
||||
static int fftExitRT(void){
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Plc function for clear of buffers
|
||||
double fft_clear(double index) {
|
||||
static double fft_clear(double index) {
|
||||
return (double)clearFFT((int)index);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
// Plc function for enable
|
||||
double fft_stat(double index) {
|
||||
static double fft_stat(double index) {
|
||||
return (double)statFFT((int)index);
|
||||
}
|
||||
|
||||
// Register data for plugin so ecmc know what to use
|
||||
struct ecmcPluginData pluginDataDef = {
|
||||
static struct ecmcPluginData pluginDataDef = {
|
||||
// Allways use ECMC_PLUG_VERSION_MAGIC
|
||||
.ifVersion = ECMC_PLUG_VERSION_MAGIC,
|
||||
// Name
|
||||
.name = "ecmcPlugin_FFT",
|
||||
.name = "ecmc_plugin_fft",
|
||||
// Description
|
||||
.desc = "FFT plugin for use with ecmc.",
|
||||
// Option description
|
||||
.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_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_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."
|
||||
.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_NFFT_OPTION_CMD"<nfft> : Data points to collect, default = 4096.\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_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.\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
|
||||
.version = ECMC_EXAMPLE_PLUGIN_VERSION,
|
||||
@@ -158,7 +161,8 @@ struct ecmcPluginData pluginDataDef = {
|
||||
.funcArg7 = NULL,
|
||||
.funcArg8 = NULL,
|
||||
.funcArg9 = NULL,
|
||||
.funcArg10 = NULL,
|
||||
.funcArg10 = NULL,
|
||||
.funcGenericObj = NULL,
|
||||
},
|
||||
.funcs[1] =
|
||||
{ /*----fft_enable----*/
|
||||
@@ -180,7 +184,8 @@ struct ecmcPluginData pluginDataDef = {
|
||||
.funcArg7 = NULL,
|
||||
.funcArg8 = NULL,
|
||||
.funcArg9 = NULL,
|
||||
.funcArg10 = NULL,
|
||||
.funcArg10 = NULL,
|
||||
.funcGenericObj = NULL,
|
||||
},
|
||||
.funcs[2] =
|
||||
{ /*----fft_trigg----*/
|
||||
@@ -202,7 +207,8 @@ struct ecmcPluginData pluginDataDef = {
|
||||
.funcArg7 = NULL,
|
||||
.funcArg8 = NULL,
|
||||
.funcArg9 = NULL,
|
||||
.funcArg10 = NULL,
|
||||
.funcArg10 = NULL,
|
||||
.funcGenericObj = NULL,
|
||||
},
|
||||
.funcs[3] =
|
||||
{ /*----fft_mode----*/
|
||||
@@ -224,7 +230,8 @@ struct ecmcPluginData pluginDataDef = {
|
||||
.funcArg7 = NULL,
|
||||
.funcArg8 = NULL,
|
||||
.funcArg9 = NULL,
|
||||
.funcArg10 = NULL,
|
||||
.funcArg10 = NULL,
|
||||
.funcGenericObj = NULL,
|
||||
},
|
||||
.funcs[4] =
|
||||
{ /*----fft_stat----*/
|
||||
@@ -246,7 +253,8 @@ struct ecmcPluginData pluginDataDef = {
|
||||
.funcArg7 = NULL,
|
||||
.funcArg8 = NULL,
|
||||
.funcArg9 = NULL,
|
||||
.funcArg10 = NULL,
|
||||
.funcArg10 = NULL,
|
||||
.funcGenericObj = NULL,
|
||||
},
|
||||
.funcs[5] = {0}, // last element set all to zero..
|
||||
// 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