diff --git a/Clients/ParaView/Testing/Data/Baseline/TableFFT1.png.sha512 b/Clients/ParaView/Testing/Data/Baseline/TableFFT1.png.sha512
index e2979f1687a..3a7540c1fa7 100644
--- a/Clients/ParaView/Testing/Data/Baseline/TableFFT1.png.sha512
+++ b/Clients/ParaView/Testing/Data/Baseline/TableFFT1.png.sha512
@@ -1 +1 @@
-183e7d3a8d12b137501347a604682898b8c702ee65f531bd309955eecee4715aebeca91c7dcf7b29c68804376187c2223b777c4c7e4a5f50676e57d5c2a5c356
+19b1416d47a2e25c28e35e773f1b444dfd7763a2e16f287992383b3b657af89d74e67e750415217a6f713c343e0ec35a0e508691c58707d56645a4b42182632a
diff --git a/Clients/ParaView/Testing/Data/Baseline/TableFFT2.png.sha512 b/Clients/ParaView/Testing/Data/Baseline/TableFFT2.png.sha512
index 672398b511b..e2451348a86 100644
--- a/Clients/ParaView/Testing/Data/Baseline/TableFFT2.png.sha512
+++ b/Clients/ParaView/Testing/Data/Baseline/TableFFT2.png.sha512
@@ -1 +1 @@
-da0cc9e935afbea212c2795bcb7b292c77376b497edfd1ef335b480a42f755684ee7a8a11e9cf509a2045b37e499717482208916d37571145cee483a55f55c77
+3c3b63fa16bad315c21d8a4d2d7aca11e13057752f3e35497db874533e185621a73b724f04957b990891b7a36aee69e4750160712707a0271ee706e6699d609f
diff --git a/Clients/ParaView/Testing/XML/CMakeLists.txt b/Clients/ParaView/Testing/XML/CMakeLists.txt
index af8a26775a0..4e4ed43c980 100644
--- a/Clients/ParaView/Testing/XML/CMakeLists.txt
+++ b/Clients/ParaView/Testing/XML/CMakeLists.txt
@@ -1469,7 +1469,6 @@ if(PARAVIEW_USE_PYTHON)
SelectionLinkScripting.xml
SelectPointsTrace.xml
SplitViewTrace.xml
- TestTableFFT.xml
TraceMultiViews.xml
)
set(SelectCellsTrace_DISABLE_CRS TRUE)
@@ -1525,7 +1524,9 @@ if(PARAVIEW_USE_PYTHON)
list(APPEND TESTS_WITH_INLINE_COMPARES
FindDataTrace.xml
- FindDataQueries.xml)
+ FindDataQueries.xml
+ TestTableFFT.xml # needs programmable filter + numpy
+ )
# PythonAlgorithm plugin tests.
configure_file(
diff --git a/Clients/ParaView/Testing/XML/TestTableFFT.xml b/Clients/ParaView/Testing/XML/TestTableFFT.xml
index 533bb3a5013..ea37b157cf4 100644
--- a/Clients/ParaView/Testing/XML/TestTableFFT.xml
+++ b/Clients/ParaView/Testing/XML/TestTableFFT.xml
@@ -5,27 +5,14 @@
+ arguments="time = numpy.linspace(0, 1, 10000, endpoint=False)
signal = numpy.sin(2 * numpy.pi * 1000 * time)
output.RowData.append(time, "Time")
output.RowData.append(signal, "Signal")"/>
@@ -36,7 +23,7 @@ if gc.GetLocalProcessId() == 0:
-
+
diff --git a/Remoting/Application/Resources/filters_filtersgeneral.xml b/Remoting/Application/Resources/filters_filtersgeneral.xml
index 371dae65e74..2c6612ef24f 100644
--- a/Remoting/Application/Resources/filters_filtersgeneral.xml
+++ b/Remoting/Application/Resources/filters_filtersgeneral.xml
@@ -2647,8 +2647,19 @@
+
+
+
+ If the "Time" column is not found then this value will be used as the sample rate of the input.
+
+
+
@@ -2660,14 +2671,13 @@
Specify the windowing function to apply on the input. This allows to better process
- data that is not periodic. When NumberOfBlocks > 1, the windowing function is applied
- to each block.
+ data that is not periodic. When Welch method is used, the window is applied to each frame.
-
@@ -2684,59 +2694,92 @@
default_values="0">
- Specify if the output should be normalized.
+ Specify if the output should be normalized. Only used if UseWelchMethod is false.
+
+
+
-
- Specify if the input should be split in multiple blocks to compute
- an average fft across all blocks.
+ Specify if filter should use the Welch / periodogram method. If true the
+ input will be split in multiple segment to compute an average fft across
+ all segments / blocks. This can be faster for input with lots of samples
+ and also remove some noise.
-
+ default_values="1024">
- Specify the number of blocks to use when computing the average fft over
- the whole input sample array. If NumberOfBlock == 1, no average is done
- and we only compute the fft on the first BlockSize samples of the input data.
+ Specify the number of samples to use for each block / segment in the Welch method.
+ This should be a power of 2 in order to achieve better performance.
+
-
-
-
+
+
+ Specify the number of samples which will overlap between each block / segment.
+ If value is not in a valid range (ie inferior to 0 or superior to BlockSize) then the
+ value BlockSize / 2 will be used. Only used if UseWelchMethod is true.
+
-
+ default_values="0">
+
+
+
+
+
+ Set what scaling should be used when applying the Welch method.
+
+
+
+
+
- Specify the number of samples to use for each block. This should be a power of 2.
- If not, the closest power of two will be used anyway.
+ Remove trend on each segment before applying the FFT. This is a constant
+ detrend where the mean of the signal is substracted to the signal.
+ Only used if UseWelchMethod is true.
+
+
+
+
+
+
-
+
diff --git a/Remoting/ServerManager/vtkSMStateVersionController.cxx b/Remoting/ServerManager/vtkSMStateVersionController.cxx
index 37eaa61f131..4a15fb1d309 100644
--- a/Remoting/ServerManager/vtkSMStateVersionController.cxx
+++ b/Remoting/ServerManager/vtkSMStateVersionController.cxx
@@ -1449,6 +1449,39 @@ struct Process_5_10_to_5_11
}
};
+struct Process_5_11_to_5_12
+{
+ bool operator()(xml_document& document) { return ConvertTableFFT(document); }
+
+ static bool ConvertTableFFT(xml_document& document)
+ {
+ pugi::xpath_node_set xpath_set =
+ document.select_nodes("//ServerManagerState/Proxy[@group='filters' and @type='TableFFT']");
+
+ for (auto xpath_node : xpath_set)
+ {
+ auto node = xpath_node.node();
+
+ if (auto averageNode = node.find_child_by_attribute("name", "AverageFft"))
+ {
+ averageNode.attribute("name").set_value("UseWelchMethod");
+ }
+
+ if (auto optimizeNode = node.find_child_by_attribute("name", "OptimizeForRealInput"))
+ {
+ optimizeNode.attribute("name").set_value("OneSidedSpectrum");
+ }
+
+ if (auto nblockNode = node.find_child_by_attribute("name", "NumberOfBlock"))
+ {
+ node.remove_child(nblockNode);
+ }
+ }
+
+ return true;
+ }
+};
+
} // end of namespace
vtkStandardNewMacro(vtkSMStateVersionController);
@@ -1563,6 +1596,13 @@ bool vtkSMStateVersionController::Process(vtkPVXMLElement* parent, vtkSMSession*
version = vtkSMVersion(5, 11, 0);
}
+ if (status && (version < vtkSMVersion(5, 12, 0)))
+ {
+ Process_5_11_to_5_12 converter;
+ status = converter(document);
+ version = vtkSMVersion(5, 12, 0);
+ }
+
if (status)
{
std::ostringstream stream2;
diff --git a/Remoting/Views/vtkSMChartSeriesListDomain.cxx b/Remoting/Views/vtkSMChartSeriesListDomain.cxx
index 85d2b4c0569..a147f19f944 100644
--- a/Remoting/Views/vtkSMChartSeriesListDomain.cxx
+++ b/Remoting/Views/vtkSMChartSeriesListDomain.cxx
@@ -152,7 +152,7 @@ int vtkSMChartSeriesListDomain::ReadXMLAttributes(vtkSMProperty* prop, vtkPVXMLE
const char** vtkSMChartSeriesListDomain::GetKnownSeriesNames()
{
static const char* strings_to_check[] = { "bin_extents", "Time", "time", "arc_length", "XArray",
- "x_array", nullptr };
+ "x_array", "Frequency", nullptr };
return strings_to_check;
}
//----------------------------------------------------------------------------
diff --git a/Remoting/Views/vtkSMChartSeriesSelectionDomain.cxx b/Remoting/Views/vtkSMChartSeriesSelectionDomain.cxx
index 0eef98f2274..5b8b4df9689 100644
--- a/Remoting/Views/vtkSMChartSeriesSelectionDomain.cxx
+++ b/Remoting/Views/vtkSMChartSeriesSelectionDomain.cxx
@@ -58,7 +58,7 @@ static void InitSeriesVisibilityDefaults()
const char* defaults[] = { "^arc_length", "^bin_extents", "^FileId", "^GlobalElementId",
"^GlobalNodeId", "^ObjectId", "^object_id", "^Pedigree.*", "^Points_.*", "^Time",
"^vtkOriginal.*", "^ids$", "^ids .*", "^vtkValidPointMask", "^N .*", "^X$", "^X .*", "^Y$",
- "^Y .*", "^Z$", "^Z .*", "^vtkGhostType$", nullptr };
+ "^Y .*", "^Z$", "^Z .*", "^vtkGhostType$", "^Frequency$", nullptr };
for (int cc = 0; defaults[cc] != nullptr; cc++)
{
SeriesVisibilityDefaults.push_back(
diff --git a/Wrapping/Python/paraview/_backwardscompatibilityhelper.py b/Wrapping/Python/paraview/_backwardscompatibilityhelper.py
index 2744cf69e80..835c927ec36 100644
--- a/Wrapping/Python/paraview/_backwardscompatibilityhelper.py
+++ b/Wrapping/Python/paraview/_backwardscompatibilityhelper.py
@@ -407,6 +407,27 @@ def setattr(proxy, pname, value):
raise NotSupportedException("'StaticMesh' is obsolete. Use 'MeshOverTime' property of " +
proxy.SMProxy.GetXMLName() + " filter instead.")
+ # 5.11 -> 5.12 breaking changes on "TableFFT" properties
+ # Renamed AverageFFTperblock into UseWelchMethod
+ # Renamed OptimizeForRealInput into OneSidedSpectrum
+ # Removed NumberOfBlock
+ if proxy.SMProxy and proxy.SMProxy.GetXMLName() == "TableFFT":
+ isOldVersion = paraview.compatibility.GetVersion() < (5, 12)
+ if pname == "AverageFFTperblock":
+ if isOldVersion:
+ proxy.GetProperty("UseWelchMethod").SetData(value)
+ raise Continue()
+ else:
+ raise NotSupportedException("'AverageFFTperblock' is obsolete. Use 'UseWelchMethod' property instead.")
+ elif pname == "OptimizeForRealInput":
+ if isOldVersion:
+ proxy.GetProperty("OneSidedSpectrum").SetData(value)
+ raise Continue()
+ else:
+ raise NotSupportedException("'OptimizeForRealInput' is obsolete. Use 'OneSidedSpectrum' property instead.")
+ elif pname == "NumberOfBlock" and not isOldVersion:
+ raise NotSupportedException("'NumberOfBlock' is obsolete. See 'BlockOverlap' property instead.")
+
if not hasattr(proxy, pname):
raise AttributeError()
proxy.__dict__[pname] = value
@@ -859,6 +880,25 @@ def getattr(proxy, pname):
raise NotSupportedException(
"Since ParaView 5.11, 'UseGeometryFilter' has been removed. ")
+ # 5.11 -> 5.12 breaking changes on "TableFFT" properties
+ # Renamed AverageFFTperblock into UseWelchMethod
+ # Renamed OptimizeForRealInput into OneSidedSpectrum
+ # Removed NumberOfBlock
+ if proxy.SMProxy and proxy.SMProxy.GetXMLName() == "TableFFT":
+ isOldVersion = paraview.compatibility.GetVersion() < (5, 12)
+ if pname == "AverageFFTperblock":
+ if isOldVersion:
+ return proxy.GetProperty("UseWelchMethod").GetData()
+ else:
+ raise NotSupportedException("'AverageFft' is obsolete. Use 'UseWelchMethod' property instead.")
+ elif pname == "OptimizeForRealInput":
+ if isOldVersion:
+ return proxy.GetProperty("OneSidedSpectrum").GetData()
+ else:
+ raise NotSupportedException("'OptimizeForRealInput' is obsolete. Use 'OneSidedSpectrum' property instead.")
+ elif pname == "NumberOfBlock" and not isOldVersion:
+ raise NotSupportedException("'NumberOfBlock' is obsolete. See 'BlockOverlap' property instead.")
+
raise Continue()
# Depending on the compatibility version that has been set, older functionalities