git-svn-id: https://subversion.xor.aps.anl.gov/synApps/areaDetector/trunk@14245 dc6c5ff5-0b8b-c028-a01f-ffb33f00fc8b
1084 lines
31 KiB
HTML
Executable File
1084 lines
31 KiB
HTML
Executable File
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<title>areaDetector Plugin NDPluginProcess</title>
|
|
<meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type" />
|
|
</head>
|
|
<body>
|
|
<div style="text-align: center">
|
|
<h1>
|
|
areaDetector Plugin NDPluginProcess</h1>
|
|
<h2>
|
|
December 3, 2011</h2>
|
|
<h2>
|
|
Mark Rivers</h2>
|
|
<h2>
|
|
University of Chicago</h2>
|
|
</div>
|
|
<h2>
|
|
Contents</h2>
|
|
<ul>
|
|
<li><a href="#Overview">Overview</a></li>
|
|
<li><a href="#Configuration">Configuration</a></li>
|
|
<li><a href="#Screens">Screen shots</a></li>
|
|
</ul>
|
|
<h2 id="Overview">
|
|
Overview
|
|
</h2>
|
|
<p>
|
|
NDPluginProcess performs arithmetic processing on NDArray data. It performs the
|
|
following operations in the order listed. Each of these operations can be individually
|
|
enabled and disabled.
|
|
</p>
|
|
<ol>
|
|
<li>Subtracts a background array which has been previously acquired.</li>
|
|
<li>Divides by a flat field array which has been previously acquired, and then multiplies
|
|
by a flat field scale factor.</li>
|
|
<li>Multiplies by a scale factor and adds an offset.</li>
|
|
<li>Clips to a minimum specified value.</li>
|
|
<li>Clips to a minimum specified value.</li>
|
|
<li>Applies a recursive digital filter.</li>
|
|
<li>Converts to the specified output data type.</li>
|
|
<li>Exports the processed data as a new NDArray object.</li>
|
|
</ol>
|
|
<p>
|
|
If any of the above operations is enabled, then the array is first converted to
|
|
NDFloat64 data type, i.e. double-precision float. The operations are all performed
|
|
in double-precision, and then the array is converted to the specified output data
|
|
type.
|
|
</p>
|
|
<p>
|
|
NDPluginProcess is both a <b>recipient</b> of callbacks and a <b>source</b> of NDArray
|
|
callbacks. This means that other plugins, such the NDPluginStdArrays, NDPluginStats,
|
|
and NDPluginFile plugins can be connected to an NDPluginProcess plugin, in which
|
|
case they will use the processed data.
|
|
</p>
|
|
<p>
|
|
NDPluginProcess is fully N-dimensional. It can be used for 2-D images, 3-D (color)
|
|
images, or any type of N-dimensional data.
|
|
</p>
|
|
<p>
|
|
NDPluginProcess inherits from NDPluginDriver. The <a href="areaDetectorDoxygenHTML/class_n_d_plugin_process.html">
|
|
NDPluginProcess class documentation</a> describes this class in detail.
|
|
</p>
|
|
<p>
|
|
NDPluginProcess.h defines the following parameters. It also implements all of the
|
|
standard plugin parameters from <a href="pluginDoc.html#NDPluginDriver">NDPluginDriver</a>.
|
|
The EPICS database NDProcess.template provide access to these parameters, listed
|
|
in the following table. Note that to reduce the width of this table the parameter
|
|
index variable names have been split into 2 lines, but these are just a single name,
|
|
for example <code>NDPluginProcessSaveBackground</code>.
|
|
</p>
|
|
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left">
|
|
<tbody>
|
|
<tr>
|
|
<td align="center" colspan="7,">
|
|
<b>Parameter Definitions in NDPluginProcess.h and EPICS Record Definitions in NDProcess.template</b></td>
|
|
</tr>
|
|
<tr>
|
|
<th>
|
|
Parameter index variable</th>
|
|
<th>
|
|
asyn interface</th>
|
|
<th>
|
|
Access</th>
|
|
<th>
|
|
Description</th>
|
|
<th>
|
|
drvInfo string</th>
|
|
<th>
|
|
EPICS record name</th>
|
|
<th>
|
|
EPICS record type</th>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" colspan="7,">
|
|
<b>Background subtraction</b></td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
SaveBackground</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Command to use the most recently acquired array as a background. Note that this
|
|
recently acquired array should have been acquired with EnableBackground=0, or else
|
|
that array will already have had the background subtracted, which is probably not
|
|
what was intended!</td>
|
|
<td>
|
|
SAVE_BACKGROUND</td>
|
|
<td>
|
|
$(P)$(R)SaveBackground<br />
|
|
$(P)$(R)SaveBackground_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
ValidBackground</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/o</td>
|
|
<td>
|
|
Flag indicating whether there is a valid background array that has been acquired
|
|
for this array using SaveBackground. This flag will be Invalid (0) if no background
|
|
has been acquired, or if the size of the array has changed since the background
|
|
was last acquired.</td>
|
|
<td>
|
|
VALID_BACKGROUND</td>
|
|
<td>
|
|
$(P)$(R)ValidBackground_RBV</td>
|
|
<td>
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
EnableBackground</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Flag indicating whether the background array acquired with SaveBackground should
|
|
be subtracted when processing the array. If ValidBackground=0 then no background
|
|
subtraction is done even if EnableBackground=Enable.</td>
|
|
<td>
|
|
ENABLE_BACKGROUND</td>
|
|
<td>
|
|
$(P)$(R)EnableBackground<br />
|
|
$(P)$(R)EnableBackground_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" colspan="7,">
|
|
<b>Flat field normalization</b></td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
SaveFlatField</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Command to use the most recently acquired array as a flat field. Note that this
|
|
recently acquired array should have been acquired with EnableFlatField=0, or else
|
|
that array will already have been flat field normalized, which is probably not what
|
|
was intended!</td>
|
|
<td>
|
|
SAVE_FLAT_FIELD</td>
|
|
<td>
|
|
$(P)$(R)SaveFlatField<br />
|
|
$(P)$(R)SaveFlatField_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
ValidFlatField</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/o</td>
|
|
<td>
|
|
Flag indicating whether there is a valid flat field array that has been acquired
|
|
for this array using SaveFlatField. This flag will be Invalid (0) if no flat field
|
|
has been acquired, or if the size of the array has changed since the flat field
|
|
was last acquired.</td>
|
|
<td>
|
|
VALID_FLAT_FIELD</td>
|
|
<td>
|
|
$(P)$(R)ValidFlatField_RBV</td>
|
|
<td>
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
EnableFlatField</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Flag indicating whether the array should be divided by the flat field array (acquired
|
|
with SaveFlatField) when processing the array. If ValidFlatField=0 then no flat
|
|
field normalization is done even if EnableBackground=Enable. The processing step
|
|
consists of:
|
|
<br />
|
|
Array = Array / FlatField * ScaleFlatField</td>
|
|
<td>
|
|
ENABLE_FLAT_FIELD</td>
|
|
<td>
|
|
$(P)$(R)EnableFlatField<br />
|
|
$(P)$(R)EnableFlatField_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
ScaleFlatField</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
The scale factor to multiply by after dividing the array by the flat field array.
|
|
This scale factor is normally chosen so that the data after scaling fills the dynamic
|
|
range of the output data type.
|
|
</td>
|
|
<td>
|
|
SCALE_FLAT_FIELD</td>
|
|
<td>
|
|
$(P)$(R)ScaleFlatField<br />
|
|
$(P)$(R)ScaleFlatField_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" colspan="7,">
|
|
<b>Scaling and offset</b></td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
EnableOffsetScale</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Flag indicating whether the array should be multiplied by Scale and then summed
|
|
with Offset when processing the array. The processing step consists of:
|
|
<br />
|
|
Array = Array * Scale + Offset</td>
|
|
<td>
|
|
ENABLE_SCALE_OFFSET</td>
|
|
<td>
|
|
$(P)$(R)EnableOffsetScale<br />
|
|
$(P)$(R)EnableOffsetScale_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
Scale</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
The scale factor to multiply by.
|
|
</td>
|
|
<td>
|
|
SCALE</td>
|
|
<td>
|
|
$(P)$(R)Scale<br />
|
|
$(P)$(R)Scale_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
Offset</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
The offset to add.
|
|
</td>
|
|
<td>
|
|
OFFSET</td>
|
|
<td>
|
|
$(P)$(R)Offset<br />
|
|
$(P)$(R)Offset_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" colspan="7,">
|
|
<b>Low and high clipping</b></td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
EnableLowClip</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Flag to control whether to clip values to the LowClip value for this array (0=Disable,
|
|
1=Enable).
|
|
</td>
|
|
<td>
|
|
ENABLE_LOW_CLIP</td>
|
|
<td>
|
|
$(P)$(R)EnableLowClip<br />
|
|
$(P)$(R)EnableLowClip_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
LowClip</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
The minimum allowed value for this array. If EnableLowClip=1, then all values in
|
|
the array less than LowClip will be replaced by LowClip.
|
|
</td>
|
|
<td>
|
|
LOW_CLIP</td>
|
|
<td>
|
|
$(P)$(R)LowClip<br />
|
|
$(P)$(R)LowClip_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
EnableHighClip</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Flag to control whether to clip values to the HighClip value for this array (0=Disable,
|
|
1=Enable).
|
|
</td>
|
|
<td>
|
|
ENABLE_HIGH_CLIP</td>
|
|
<td>
|
|
$(P)$(R)EnableHighClip<br />
|
|
$(P)$(R)EnableHighClip_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
HighClip</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
The maximum allowed value for this array. If EnableHighClip=1, then all values in
|
|
the array greater than HighClip will be replaced by HighClip.
|
|
</td>
|
|
<td>
|
|
HIGH_CLIP</td>
|
|
<td>
|
|
$(P)$(R)HighClip<br />
|
|
$(P)$(R)HighClip_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
DataType</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Data type of the output array (NDDataType_t). This can be different from the data
|
|
type of the NDArray callback data.</td>
|
|
<td>
|
|
PROCESS_DATA_TYPE</td>
|
|
<td>
|
|
$(P)$(R)DataTypeOut<br />
|
|
$(P)$(R)DataTypeOut_RBV</td>
|
|
<td>
|
|
mbbo<br />
|
|
mbbi</td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" colspan="7,">
|
|
<b>Recursive filter</b></td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
EnableFilter</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Flag indicating whether the array should be processed with a recursive filter. The
|
|
details of the filter operation are explained below.<br />
|
|
</td>
|
|
<td>
|
|
ENABLE_FILTER</td>
|
|
<td>
|
|
$(P)$(R)EnableFilter<br />
|
|
$(P)$(R)EnableFilter_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
ResetFilter</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Command to reset the filter back to its initial state.</td>
|
|
<td>
|
|
RESET_FILTER</td>
|
|
<td>
|
|
$(P)$(R)ResetFilter<br />
|
|
$(P)$(R)ResetFilter_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
AutoResetFilter</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
If enabled then when NumFiltered=NumFilter the filter automatically resets. This
|
|
can be very useful when using the Average or Sum filter modes. As soon as N sums
|
|
or averages have been performed the filter resets, so the next sum or average is
|
|
computed.</td>
|
|
<td>
|
|
AUTO_RESET_FILTER</td>
|
|
<td>
|
|
$(P)$(R)AutoResetFilter<br />
|
|
$(P)$(R)AutoResetFilter_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
FilterCallbacks</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Choices are "Every array" and "Array N only". If "Every array" is selected then
|
|
the plugin does callbacks for every incoming array it receives. If "Array N only"
|
|
is selected then the plugin only does callbacks when NumFiltered=NumFilter. This
|
|
can be very useful when using the Sum or Average filter modes. Callbacks are then
|
|
done only when N sums or averages have been performed. If used with AutoResetFilter
|
|
then as input arrays arrive the plugin will continually output one summed or averaged
|
|
array after every N incoming arrays.</td>
|
|
<td>
|
|
FILTER_CALLBACKS</td>
|
|
<td>
|
|
$(P)$(R)FilterCallbacks<br />
|
|
$(P)$(R)FilterCallbacks_RBV</td>
|
|
<td>
|
|
bo<br />
|
|
bi</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
NumFilter</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
The characteristic number of arrays to use when filtering. The value of NumFiltered
|
|
will increase as each array is processed, until it reaches the value of NumFilter,
|
|
when it will no longer increase. The value of NumFiltered is used in the filter
|
|
equations, as explained below.
|
|
</td>
|
|
<td>
|
|
NUM_FILTER</td>
|
|
<td>
|
|
$(P)$(R)NumFilter<br />
|
|
$(P)$(R)NumFilter_RBV</td>
|
|
<td>
|
|
longout<br />
|
|
longin</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
NumFiltered</td>
|
|
<td>
|
|
asynInt32</td>
|
|
<td>
|
|
r/o</td>
|
|
<td>
|
|
The number of arrays that have been processed by the filter since the filter was
|
|
last reset. The value of NumFiltered is incremented as each array is processed,
|
|
until it reaches the value of NumFilter, when it will cease incrementing. The value
|
|
of NumFiltered is used in the filter equations, as explained below.
|
|
</td>
|
|
<td>
|
|
NUM_FILTERED</td>
|
|
<td>
|
|
$(P)$(R)NumFiltered_RBV</td>
|
|
<td>
|
|
longin</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
N.A.</td>
|
|
<td>
|
|
N.A.</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
The filter type, chosen from a predefined list, as described below.
|
|
</td>
|
|
<td>
|
|
N.A.</td>
|
|
<td>
|
|
$(P)$(R)FilterType</td>
|
|
<td>
|
|
mbbo</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
OOffset</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Output offset coefficient.
|
|
</td>
|
|
<td>
|
|
FILTER_OOFFSET</td>
|
|
<td>
|
|
$(P)$(R)OOffset<br />
|
|
$(P)$(R)OOffset_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
OScale</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Output scale coefficient.
|
|
</td>
|
|
<td>
|
|
FILTER_OSCALE</td>
|
|
<td>
|
|
$(P)$(R)OScale<br />
|
|
$(P)$(R)OScale_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
OC1</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Output coefficient #1.
|
|
</td>
|
|
<td>
|
|
FILTER_OC1</td>
|
|
<td>
|
|
$(P)$(R)OC1<br />
|
|
$(P)$(R)OC1_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
OC2</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Output coefficient #2.
|
|
</td>
|
|
<td>
|
|
FILTER_OC2</td>
|
|
<td>
|
|
$(P)$(R)OC2<br />
|
|
$(P)$(R)OC2_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
OC3</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Output coefficient #3.
|
|
</td>
|
|
<td>
|
|
FILTER_OC3</td>
|
|
<td>
|
|
$(P)$(R)OC3<br />
|
|
$(P)$(R)OC3_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
OC4</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Output coefficient #4.
|
|
</td>
|
|
<td>
|
|
FILTER_OC4</td>
|
|
<td>
|
|
$(P)$(R)OC4<br />
|
|
$(P)$(R)OC4_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
FOffset</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Filter offset coefficient.
|
|
</td>
|
|
<td>
|
|
FILTER_FOFFSET</td>
|
|
<td>
|
|
$(P)$(R)FOffset<br />
|
|
$(P)$(R)FOffset_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
FScale</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Filter scale coefficient.
|
|
</td>
|
|
<td>
|
|
FILTER_FSCALE</td>
|
|
<td>
|
|
$(P)$(R)FScale<br />
|
|
$(P)$(R)FScale_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
FC1</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Filter coefficient #1.
|
|
</td>
|
|
<td>
|
|
FILTER_FC1</td>
|
|
<td>
|
|
$(P)$(R)FC1<br />
|
|
$(P)$(R)FC1_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
FC2</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Filter coefficient #2.
|
|
</td>
|
|
<td>
|
|
FILTER_FC2</td>
|
|
<td>
|
|
$(P)$(R)FC2<br />
|
|
$(P)$(R)FC2_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
FC3</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Filter coefficient #3.
|
|
</td>
|
|
<td>
|
|
FILTER_FC3</td>
|
|
<td>
|
|
$(P)$(R)FC3<br />
|
|
$(P)$(R)FC3_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
FC4</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Filter coefficient #4.
|
|
</td>
|
|
<td>
|
|
FILTER_FC4</td>
|
|
<td>
|
|
$(P)$(R)FC4<br />
|
|
$(P)$(R)FC4_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
ROffset</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Reset offset coefficient.
|
|
</td>
|
|
<td>
|
|
FILTER_ROFFSET</td>
|
|
<td>
|
|
$(P)$(R)ROffset<br />
|
|
$(P)$(R)ROffset_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
RC1</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Filter coefficient #1.
|
|
</td>
|
|
<td>
|
|
FILTER_RC1</td>
|
|
<td>
|
|
$(P)$(R)RC1<br />
|
|
$(P)$(R)RC1_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
NDPluginProcess<br />
|
|
RC2</td>
|
|
<td>
|
|
asynFloat64</td>
|
|
<td>
|
|
r/w</td>
|
|
<td>
|
|
Filter coefficient #2.
|
|
</td>
|
|
<td>
|
|
FILTER_RC2</td>
|
|
<td>
|
|
$(P)$(R)RC2<br />
|
|
$(P)$(R)RC2_RBV</td>
|
|
<td>
|
|
ao<br />
|
|
ai</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h3>
|
|
Recursive filter implementation</h3>
|
|
<p>
|
|
The recursive filter performs filtering in the time (not spatial) domain. It is
|
|
implemented in a fairly general manner, so that a variety of filters can be implemented.
|
|
These include integrating filters and differentiating filter types. The recursive
|
|
filter stores one "filter" array internally. Using this internal filter array, and
|
|
a new input array, it computes an output array, and a new version of the filter
|
|
array. The equations governing the output array and new filter array are:
|
|
</p>
|
|
<pre>
|
|
O[n] = OOffset + OScale*((OC1 + OC2/N)*F[n-1] +
|
|
(OC3 + OC4/N)*I[n])
|
|
F[n] = FOffset + FScale*((FC1 + FC2/N)*F[n-1] +
|
|
(FC3 + FC4/N)*I[n])
|
|
On filter reset
|
|
F[0] = ROffset + RC1*F[0] + RC2*I[0]
|
|
|
|
where
|
|
I[n] = New input array from callback
|
|
I[0] = First input array after a filter reset
|
|
F[n-1] = Stored filter array
|
|
F[n] = New filter array
|
|
F[0] = Current filter array when filter is reset.
|
|
May be a copy of I[0] if there was no valid filter array.
|
|
N = Current value of NumFiltered
|
|
O[n] = Output array passed to clients
|
|
</pre>
|
|
<h3>
|
|
Predefined filters</h3>
|
|
<p>
|
|
The NDProcess.template database implements the following predefined filters using
|
|
the $(P)$(R)FilterType record. The implementation of these predefined filter types
|
|
is done entirely in the database, not in the plugin code. The database simply downloads
|
|
values of OC1-OC4, FC1-FC4, and RC1-RC2 that result in predefined filter behaviours.
|
|
The operation of the recursive filter is by no means limited to these fixed filter
|
|
types, they are simply provided as a convenience, and can be easily modified or
|
|
extended. Note that the database does not download values of OOffset, OScale, FOffset,
|
|
FScale, or ROffset, so these remain unchanged when a new filter is selected. The
|
|
equations below do not include these offset and scale values, but they are useful
|
|
in many circumstances.</p>
|
|
<p>
|
|
The NDProcess_settings.req file for save/restore saves the values of all of the
|
|
filter coefficients, and downloads them when EPICS initialized at iocInit. It also
|
|
saves the FilterType, but does not process this record at iocInit, so that any customized
|
|
filter coefficients will be preserved, and will not be replaced by the defaults
|
|
for that filter type.
|
|
</p>
|
|
<h4>
|
|
Recursive Average</h4>
|
|
<p>
|
|
The recursive average filter does input array averaging. It is defined as:</p>
|
|
<pre>
|
|
O[n] = F[n] = (1-1/N)*F[n-1] + 1/N*I[n]
|
|
</pre>
|
|
<p>
|
|
N is the characteristic number of arrays in the average. For example, if N=100,
|
|
then each new array is weighted by 0.01 and the previous filter value is weighted
|
|
by 0.99. This is an infinite impulse response (IIR) filter, because the effect of
|
|
one array never complelely dissappears, but rather decays exponentially. When this
|
|
filter is reset the filter array is initialized with the first input array. This
|
|
filter can be used to decrease the noise and increase the dynamic range of a repetitive
|
|
input signal with a small signal. In that case it can be useful to use set EnableOffsetScale=Enable
|
|
and set Scale to a large enough number to more fully use the dynamic range of the
|
|
output data type. The averaged signal will then better use the dynamic range of
|
|
the output data type.
|
|
</p>
|
|
<h4>
|
|
Average</h4>
|
|
<p>
|
|
The average filter does input array averaging. It is defined as:</p>
|
|
<pre>
|
|
O[n] = F[n] = F[n-1] + 1/N*I[n]
|
|
</pre>
|
|
<p>
|
|
N is the number of arrays in the average. For example, if N=100, then each new array
|
|
is weighted by 0.01. When this filter is reset the filter array is initialized to
|
|
0. This filter typically cannot be run forever, because the output grows monotonically
|
|
and will lead to overflow. However, if AutoResetFilter is enabled then the filter
|
|
will be reset when NumFiltered=NumFilter. If ArrayCallbacks is "Array N only" then
|
|
callbacks will be done only with the final averaged value.
|
|
</p>
|
|
<h4>
|
|
Sum</h4>
|
|
<p>
|
|
The sum filter does input array summing. It is defined as:</p>
|
|
<pre>
|
|
O[n] = F[n] = F[n-1] + I[n]
|
|
</pre>
|
|
<p>
|
|
This filter simply computes the sum of input arrays. When this filter is reset the
|
|
filter array is initialized to 0. It is often necessary to set the output data type
|
|
to one with a larger maximum value than the input array to prevent overflow. If
|
|
AutoResetFilter is enabled then the filter will be reset when NumFiltered=NumFilter.
|
|
If ArrayCallbacks is "Array N only" then callbacks will be done only with the final
|
|
summed value.
|
|
</p>
|
|
<h4>
|
|
Difference</h4>
|
|
<p>
|
|
The difference filter computes the difference between frame N and frame N-1. It
|
|
is defined as:</p>
|
|
<pre>
|
|
O[n] = -F[n-1] + I[n]
|
|
F[n] = I[n]
|
|
</pre>
|
|
<p>
|
|
Note that the difference will often be a small signed number. If the output datatype
|
|
is unsigned, or if a display client expects unsigned numbers, then it can be useful
|
|
to set OOffset to a non-zero value to add an offset to the result. For example,
|
|
if the output data type is UInt8 (unsigned 8-bit), then setting OOffset to 128 will
|
|
produce an unsigned image centered at 128. Similarly OScale can be used to increase
|
|
the range of the difference by multiplying by a factor greater than 1, although
|
|
this will not increase the dynamic range of the result, only the absolute range.
|
|
</p>
|
|
<h4>
|
|
Recursive Average Difference</h4>
|
|
<p>
|
|
This filter computes the difference between frame N and the recursive average of
|
|
previous frames. It is a combination of the Difference and Recursive Average filters
|
|
described above. The new filter is a recursive average, but the output is the difference
|
|
between the current frame and that recursive average. It is defined as:</p>
|
|
<pre>
|
|
O[n] = -F[n-1] + I[n]
|
|
F[n] = (1-1/N)*F[n-1] + 1/N*I[n]
|
|
</pre>
|
|
<p>
|
|
N is again the characteristic number of arrays in the average.
|
|
</p>
|
|
<h4>
|
|
Copy to Filter</h4>
|
|
<p>
|
|
This filter simply copies the input array to the filter array and the output array.
|
|
It is defined as:</p>
|
|
<pre>
|
|
O[n] = F[n] = I[n]
|
|
</pre>
|
|
<p>
|
|
This filter can be used to load the filter (F) with a certain array, which is then
|
|
subsequently used for some other filter type.</p>
|
|
<h2 id="Configuration">
|
|
Configuration</h2>
|
|
<p>
|
|
The NDPluginProcess plugin is created with the NDProcessConfigure command, either
|
|
from C/C++ or from the EPICS IOC shell.</p>
|
|
<pre>
|
|
NDProcessConfigure(const char *portName, int queueSize, int blockingCallbacks,
|
|
const char *NDArrayPort, int NDArrayAddr,
|
|
int maxBuffers, size_t maxMemory,
|
|
int priority, int stackSize)
|
|
</pre>
|
|
<p>
|
|
For details on the meaning of the parameters to this function refer to the detailed
|
|
documentation on the NDProcessConfigure function in the <a href="areaDetectorDoxygenHTML/_n_d_plugin_process_8cpp.html">
|
|
NDPluginProcess.cpp documentation</a> and in the documentation for the constructor
|
|
for the <a href="areaDetectorDoxygenHTML/class_n_d_plugin_process.html">NDPluginProcess
|
|
class</a>.
|
|
</p>
|
|
<h2 id="Screens">
|
|
Screen shots</h2>
|
|
<p>
|
|
The following is the MEDM screen that provides access to the parameters in NDPluginDriver.h
|
|
and NDPluginProcess.h through records in NDPluginBase.template and NDProcess.template.
|
|
In this example the input image is first offset by -4 and scaled by 35. That result
|
|
is then clipped to a minimum of 0 and a maximum of 255. The image is then run through
|
|
a recursive averaging filter with N=100.
|
|
</p>
|
|
<div style="text-align: center">
|
|
<h3>
|
|
NDProcess.adl</h3>
|
|
<img alt="NDProcess.png" src="NDProcess.png" />
|
|
</div>
|
|
<p>
|
|
Image collected with 30 microsecond exposure time, so it is very noisy. This is
|
|
the image output from the NDPlugProcess plugin with Offset and Scale as shown above,
|
|
but with the recursive filter disabled.</p>
|
|
<div style="text-align: center">
|
|
<img alt="NDProcess_unfilted.jpg" src="NDProcess_unfiltered.jpg" />
|
|
</div>
|
|
<p>
|
|
NDPluginStats plugin connected to the NDPluginProcess filter for the noisy image
|
|
above. Note that there are only 6 non-zero intensities in the histogram, because
|
|
the brightest pixels are only 6 A/D units above background.</p>
|
|
<div style="text-align: center">
|
|
<img alt="NDStats_unfiltered.png" src="NDStats_unfiltered.png" />
|
|
</div>
|
|
<p>
|
|
Same image collected with 30 microsecond exposure time. This is the image output
|
|
from the NDPlugProcess plugin with Offset and Scale as shown above, with the recursive
|
|
filter enabled. Note the dramatic improvement in signal to noise.</p>
|
|
<div style="text-align: center">
|
|
<img alt="NDProcess_filtered.jpg" src="NDProcess_filtered.jpg" />
|
|
</div>
|
|
<p>
|
|
NDPluginStats plugin connected to the NDPluginProcess filter for the filtered image
|
|
above. Note that there are many non-zero intensities in the histogram, because the
|
|
filtering is improving the dynamic range significantly.</p>
|
|
<div style="text-align: center">
|
|
<img alt="NDStats_filtered.png" src="NDStats_filtered.png" />
|
|
</div>
|
|
</body>
|
|
</html>
|