sc/inc/scfuncs.hrc                   |    4 +
 sc/source/core/data/funcdesc.cxx     |    2 
 sc/source/core/tool/interpr3.cxx     |   79 +++++++++++++++++++++++++----------
 sc/source/core/tool/parclass.cxx     |    2 
 sc/source/filter/excel/xlformula.cxx |    2 
 sc/source/filter/oox/formulabase.cxx |    2 
 6 files changed, 64 insertions(+), 27 deletions(-)

New commits:
commit 88b52d4ecc908a817211a5beb908df378cbf5fae
Author:     Dennis Francis <dennis.fran...@collabora.com>
AuthorDate: Tue Mar 12 21:38:14 2019 +0530
Commit:     Dennis Francis <dennis.fran...@collabora.com>
CommitDate: Tue Mar 26 14:30:09 2019 +0100

    tdf#74664: FOURIER: add 5th optional parameter MinimumMagnitude
    
    This parameter is used only if Polar=TRUE.
    All frequency components with magnitude less than MinimumMagnitude
    will be suppressed with a zero magnitude-phase entry.
    This is very useful when looking at the magnitude-phase spectrum
    of a signal because there is always some very tiny amount of rounding
    error when doing FFT algorithms and results in incorrect non-zero
    phase for non-existent frequencies. By providing a suitable value to
    this parameter, these non-existent frequency components can be filtered
    out. By default the value of this 5th parameter is 0.0, so *no*
    suppression is done by default.
    
    Change-Id: I422ad1bf91f42b320e98e58a19c99bf8528e4708
    Reviewed-on: https://gerrit.libreoffice.org/69471
    Tested-by: Jenkins
    Reviewed-by: Dennis Francis <dennis.fran...@collabora.com>

diff --git a/sc/inc/scfuncs.hrc b/sc/inc/scfuncs.hrc
index f0f06eee6427..e17eb9250c65 100644
--- a/sc/inc/scfuncs.hrc
+++ b/sc/inc/scfuncs.hrc
@@ -4129,7 +4129,9 @@ const char* SC_OPCODE_FOURIER_ARY[] =
     NC_("SC_OPCODE_FOURIER", "Inverse"),
     NC_("SC_OPCODE_FOURIER", "Flag to indicate whether an inverse DFT is to be 
computed (default FALSE)."),
     NC_("SC_OPCODE_FOURIER", "Polar"),
-    NC_("SC_OPCODE_FOURIER", "Flag to indicate whether to return the results 
in polar form (default FALSE).")
+    NC_("SC_OPCODE_FOURIER", "Flag to indicate whether to return the results 
in polar form (default FALSE)."),
+    NC_("SC_OPCODE_FOURIER", "MinimumMagnitude"),
+    NC_("SC_OPCODE_FOURIER", "In case of Polar=TRUE, the frequency components 
below this magnitude are clipped out (default 0.0).")
 };
 
 #endif
diff --git a/sc/source/core/data/funcdesc.cxx b/sc/source/core/data/funcdesc.cxx
index a5cc499e44df..4679f3e029b4 100644
--- a/sc/source/core/data/funcdesc.cxx
+++ b/sc/source/core/data/funcdesc.cxx
@@ -788,7 +788,7 @@ ScFunctionList::ScFunctionList()
         { SC_OPCODE_FINDB, ENTRY(SC_OPCODE_FINDB_ARY), 0, 
ID_FUNCTION_GRP_TEXT, HID_FUNC_FINDB, 3, { 0, 0, 1 } },
         { SC_OPCODE_SEARCHB, ENTRY(SC_OPCODE_SEARCHB_ARY), 0, 
ID_FUNCTION_GRP_TEXT, HID_FUNC_SEARCHB, 3, { 0, 0, 1 } },
         { SC_OPCODE_REGEX, ENTRY(SC_OPCODE_REGEX_ARY), 0, 
ID_FUNCTION_GRP_TEXT, HID_FUNC_REGEX, 4, { 0, 0, 1, 1 } },
-        { SC_OPCODE_FOURIER, ENTRY(SC_OPCODE_FOURIER_ARY), 0, 
ID_FUNCTION_GRP_MATRIX, HID_FUNC_FOURIER, 4, { 0, 0, 1, 1 } }
+        { SC_OPCODE_FOURIER, ENTRY(SC_OPCODE_FOURIER_ARY), 0, 
ID_FUNCTION_GRP_MATRIX, HID_FUNC_FOURIER, 5, { 0, 0, 1, 1, 1 } }
     };
 
     ScFuncDesc* pDesc = nullptr;
diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx
index bd21be239f92..517e2d258f70 100644
--- a/sc/source/core/tool/interpr3.cxx
+++ b/sc/source/core/tool/interpr3.cxx
@@ -4902,12 +4902,14 @@ class ScComplexFFT2
 public:
     // rfArray.size() would always be even and a power of 2. (asserted in 
prepare())
     // rfArray's first half contains the real parts and the later half 
contains the imaginary parts.
-    ScComplexFFT2(std::vector<double>& raArray, bool bInverse, bool bPolar, 
ScTwiddleFactors& rTF, bool bSubSampleTFs = false, bool bDisableNormalize = 
false) :
+    ScComplexFFT2(std::vector<double>& raArray, bool bInverse, bool bPolar, 
double fMinMag,
+                  ScTwiddleFactors& rTF, bool bSubSampleTFs = false, bool 
bDisableNormalize = false) :
         mrArray(raArray),
         mfWReal(rTF.mfWReal),
         mfWImag(rTF.mfWImag),
         mnPoints(raArray.size()/2),
         mnStages(0),
+        mfMinMag(fMinMag),
         mbInverse(bInverse),
         mbPolar(bPolar),
         mbDisableNormalize(bDisableNormalize),
@@ -4977,6 +4979,7 @@ private:
     std::vector<double>& mfWImag;
     SCSIZE mnPoints;
     SCSIZE mnStages;
+    double mfMinMag;
     bool mbInverse:1;
     bool mbPolar:1;
     bool mbDisableNormalize:1;
@@ -5023,7 +5026,7 @@ static void lcl_normalize(std::vector<double>& 
rCmplxArray, bool bScaleOnlyReal)
     }
 }
 
-static void lcl_convertToPolar(std::vector<double>& rCmplxArray)
+static void lcl_convertToPolar(std::vector<double>& rCmplxArray, double 
fMinMag)
 {
     const SCSIZE nPoints = rCmplxArray.size()/2;
     double fMag, fPhase, fR, fI;
@@ -5031,8 +5034,16 @@ static void lcl_convertToPolar(std::vector<double>& 
rCmplxArray)
     {
         fR = rCmplxArray[nIdx];
         fI = rCmplxArray[nPoints+nIdx];
-        fPhase = atan2(fI, fR);
         fMag = sqrt(fR*fR + fI*fI);
+        if (fMag < fMinMag)
+        {
+            fMag = 0.0;
+            fPhase = 0.0;
+        }
+        else
+        {
+            fPhase = atan2(fI, fR);
+        }
 
         rCmplxArray[nIdx] = fMag;
         rCmplxArray[nPoints+nIdx] = fPhase;
@@ -5066,7 +5077,7 @@ void ScComplexFFT2::Compute()
     }
 
     if (mbPolar)
-        lcl_convertToPolar(mrArray);
+        lcl_convertToPolar(mrArray, mfMinMag);
 
     // Normalize after converting to polar, so we have a chance to
     // save O(mnPoints) flops.
@@ -5080,9 +5091,11 @@ class ScComplexBluesteinFFT
 {
 public:
 
-    ScComplexBluesteinFFT(std::vector<double>& rArray, bool bReal, bool 
bInverse, bool bPolar, bool bDisableNormalize = false) :
+    ScComplexBluesteinFFT(std::vector<double>& rArray, bool bReal, bool 
bInverse,
+                          bool bPolar, double fMinMag, bool bDisableNormalize 
= false) :
         mrArray(rArray),
         mnPoints(rArray.size()/2), // rArray should have space for imaginary 
parts even if real input.
+        mfMinMag(fMinMag),
         mbReal(bReal),
         mbInverse(bInverse),
         mbPolar(bPolar),
@@ -5094,6 +5107,7 @@ public:
 private:
     std::vector<double>& mrArray;
     const SCSIZE mnPoints;
+    double mfMinMag;
     bool mbReal:1;
     bool mbInverse:1;
     bool mbPolar:1;
@@ -5144,10 +5158,12 @@ void ScComplexBluesteinFFT::Compute()
         aTF.Compute();
 
         // Do complex-FFT2 of both A and B signal.
-        ScComplexFFT2 aFFT2A(aASignal, false /*not inverse*/, false /*no 
polar*/, aTF, false /*no subsample*/, true /* disable normalize */);
+        ScComplexFFT2 aFFT2A(aASignal, false /*not inverse*/, false /*no 
polar*/, 0.0 /* no clipping */,
+                             aTF, false /*no subsample*/, true /* disable 
normalize */);
         aFFT2A.Compute();
 
-        ScComplexFFT2 aFFT2B(aBSignal, false /*not inverse*/, false /*no 
polar*/, aTF, false /*no subsample*/, true /* disable normalize */);
+        ScComplexFFT2 aFFT2B(aBSignal, false /*not inverse*/, false /*no 
polar*/, 0.0 /* no clipping */,
+                             aTF, false /*no subsample*/, true /* disable 
normalize */);
         aFFT2B.Compute();
 
         double fAR, fAI, fBR, fBI;
@@ -5165,7 +5181,7 @@ void ScComplexBluesteinFFT::Compute()
 
         // Do complex-inverse-FFT2 of aASignal.
         aTF.Conjugate();
-        ScComplexFFT2 aFFT2AI(aASignal, true /*inverse*/, false /*no polar*/, 
aTF); // Need normalization here.
+        ScComplexFFT2 aFFT2AI(aASignal, true /*inverse*/, false /*no polar*/, 
0.0 /* no clipping */, aTF); // Need normalization here.
         aFFT2AI.Compute();
     }
 
@@ -5180,7 +5196,7 @@ void ScComplexBluesteinFFT::Compute()
 
     // Normalize/Polar operations
     if (mbPolar)
-        lcl_convertToPolar(mrArray);
+        lcl_convertToPolar(mrArray, mfMinMag);
 
     // Normalize after converting to polar, so we have a chance to
     // save O(mnPoints) flops.
@@ -5195,9 +5211,11 @@ class ScRealFFT
 {
 public:
 
-    ScRealFFT(std::vector<double>& rInArray, std::vector<double>& rOutArray, 
bool bInverse, bool bPolar) :
+    ScRealFFT(std::vector<double>& rInArray, std::vector<double>& rOutArray, 
bool bInverse,
+              bool bPolar, double fMinMag) :
         mrInArray(rInArray),
         mrOutArray(rOutArray),
+        mfMinMag(fMinMag),
         mbInverse(bInverse),
         mbPolar(bPolar)
     {}
@@ -5207,6 +5225,7 @@ public:
 private:
     std::vector<double>& mrInArray;
     std::vector<double>& mrOutArray;
+    double mfMinMag;
     bool mbInverse:1;
     bool mbPolar:1;
 };
@@ -5244,14 +5263,14 @@ void ScRealFFT::Compute()
 
     if (nNextPow2 == nN)
     {
-        ScComplexFFT2 aFFT2(aWorkArray, mbInverse, false /*disable polar*/,
+        ScComplexFFT2 aFFT2(aWorkArray, mbInverse, false /*disable polar*/, 
0.0 /* no clipping */,
                             aTFs, true /*subsample tf*/, true /*disable 
normalize*/);
         aFFT2.Compute();
     }
     else
     {
         ScComplexBluesteinFFT aFFT(aWorkArray, false /*complex input*/, 
mbInverse, false /*disable polar*/,
-                                   true /*disable normalize*/);
+                                   0.0 /* no clipping */, true /*disable 
normalize*/);
         aFFT.Compute();
     }
 
@@ -5300,7 +5319,7 @@ void ScRealFFT::Compute()
 
     // Normalize/Polar operations
     if (mbPolar)
-        lcl_convertToPolar(mrOutArray);
+        lcl_convertToPolar(mrOutArray, mfMinMag);
 
     // Normalize after converting to polar, so we have a chance to
     // save O(mnPoints) flops.
@@ -5315,8 +5334,9 @@ class ScFFT
 {
 public:
 
-    ScFFT(ScMatrixRef& pMat, bool bReal, bool bInverse, bool bPolar) :
+    ScFFT(ScMatrixRef& pMat, bool bReal, bool bInverse, bool bPolar, double 
fMinMag) :
         mpInputMat(pMat),
+        mfMinMag(fMinMag),
         mbReal(bReal),
         mbInverse(bInverse),
         mbPolar(bPolar)
@@ -5326,6 +5346,7 @@ public:
 
 private:
     ScMatrixRef& mpInputMat;
+    double mfMinMag;
     bool mbReal:1;
     bool mbInverse:1;
     bool mbPolar:1;
@@ -5345,7 +5366,7 @@ ScMatrixRef 
ScFFT::Compute(std::function<ScMatrixGenerator>& rMatGenFunc)
     if (mbReal && (nPoints % 2) == 0)
     {
         std::vector<double> aOutArray(nPoints*2);
-        ScRealFFT aFFT(aArray, aOutArray, mbInverse, mbPolar);
+        ScRealFFT aFFT(aArray, aOutArray, mbInverse, mbPolar, mfMinMag);
         aFFT.Compute();
         return rMatGenFunc(2, nPoints, aOutArray);
     }
@@ -5356,14 +5377,14 @@ ScMatrixRef 
ScFFT::Compute(std::function<ScMatrixGenerator>& rMatGenFunc)
     {
         ScTwiddleFactors aTF(nPoints, mbInverse);
         aTF.Compute();
-        ScComplexFFT2 aFFT2(aArray, mbInverse, mbPolar, aTF);
+        ScComplexFFT2 aFFT2(aArray, mbInverse, mbPolar, mfMinMag, aTF);
         aFFT2.Compute();
         return rMatGenFunc(2, nPoints, aArray);
     }
 
     if (mbReal)
         aArray.resize(nPoints*2, 0.0);
-    ScComplexBluesteinFFT aFFT(aArray, mbReal, mbInverse, mbPolar);
+    ScComplexBluesteinFFT aFFT(aArray, mbReal, mbInverse, mbPolar, mfMinMag);
     aFFT.Compute();
     return rMatGenFunc(2, nPoints, aArray);
 }
@@ -5371,16 +5392,30 @@ ScMatrixRef 
ScFFT::Compute(std::function<ScMatrixGenerator>& rMatGenFunc)
 void ScInterpreter::ScFourier()
 {
     sal_uInt8 nParamCount = GetByte();
-    if ( !MustHaveParamCount( nParamCount, 2, 4 ) )
+    if ( !MustHaveParamCount( nParamCount, 2, 5 ) )
         return;
 
     bool bInverse = false;
     bool bPolar = false;
+    double fMinMag = 0.0;
 
-    if (nParamCount == 4)
-        bPolar = GetBool();
+    if (nParamCount == 5)
+    {
+        if (IsMissing())
+            Pop();
+        else
+            fMinMag = GetDouble();
+    }
+
+    if (nParamCount >= 4)
+    {
+        if (IsMissing())
+            Pop();
+        else
+            bPolar = GetBool();
+    }
 
-    if (nParamCount > 2)
+    if (nParamCount >= 3)
     {
         if (IsMissing())
             Pop();
@@ -5425,7 +5460,7 @@ void ScInterpreter::ScFourier()
         bRealInput = (nC == 1);
     }
 
-    ScFFT aFFT(pInputMat, bRealInput, bInverse, bPolar);
+    ScFFT aFFT(pInputMat, bRealInput, bInverse, bPolar, fMinMag);
     std::function<ScMatrixGenerator> aFunc = [this](SCSIZE nCol, SCSIZE nRow, 
std::vector<double>& rVec) -> ScMatrixRef
     {
         return this->GetNewMat(nCol, nRow, rVec);
diff --git a/sc/source/core/tool/parclass.cxx b/sc/source/core/tool/parclass.cxx
index b8428191842e..18c4ad5b84f7 100644
--- a/sc/source/core/tool/parclass.cxx
+++ b/sc/source/core/tool/parclass.cxx
@@ -146,7 +146,7 @@ const ScParameterClassification::RawData 
ScParameterClassification::pRawData[] =
     { ocForecast_ETS_STA, {{ ForceArray, ForceArray, ForceArray, Value, Value, 
Value        }, 0, Value }},
     { ocForecast_ETS_STM, {{ ForceArray, ForceArray, ForceArray, Value, Value, 
Value        }, 0, Value }},
     { ocFormula,         {{ Reference                                          
  }, 0, Value }},
-    { ocFourier,         {{ ForceArray, Value, Value, Value                    
  }, 0, Value }},
+    { ocFourier,         {{ ForceArray, Value, Value, Value, Value             
  }, 0, Value }},
     { ocFrequency,       {{ ReferenceOrForceArray, ReferenceOrForceArray       
  }, 0, ForceArrayReturn }},
     { ocGCD,             {{ Reference                                          
  }, 1, Value }},
     { ocGeoMean,         {{ Reference                                          
  }, 1, Value }},
diff --git a/sc/source/filter/excel/xlformula.cxx 
b/sc/source/filter/excel/xlformula.cxx
index 8cdf9806896f..99fb54a530d0 100644
--- a/sc/source/filter/excel/xlformula.cxx
+++ b/sc/source/filter/excel/xlformula.cxx
@@ -638,7 +638,7 @@ static const XclFunctionInfo saFuncTable_OOoLO[] =
     EXC_FUNCENTRY_OOO( ocForecast_ETS_STM, 3,  6,  0,  
"ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT" ),
     EXC_FUNCENTRY_OOO( ocRoundSig,      2,  2,  0,  "ORG.LIBREOFFICE.ROUNDSIG" 
),
     EXC_FUNCENTRY_OOO( ocRegex,         2,  4,  0,  "ORG.LIBREOFFICE.REGEX" ),
-    EXC_FUNCENTRY_OOO( ocFourier,       2,  4,  0,  "ORG.LIBREOFFICE.FOURIER" )
+    EXC_FUNCENTRY_OOO( ocFourier,       2,  5,  0,  "ORG.LIBREOFFICE.FOURIER" )
 };
 
 #undef EXC_FUNCENTRY_OOO_IBR
diff --git a/sc/source/filter/oox/formulabase.cxx 
b/sc/source/filter/oox/formulabase.cxx
index e4cefc504b06..1a7822e7942f 100644
--- a/sc/source/filter/oox/formulabase.cxx
+++ b/sc/source/filter/oox/formulabase.cxx
@@ -911,7 +911,7 @@ static const FunctionData saFuncTableOOoLO[] =
     { "ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT", 
"ORG.LIBREOFFICE.FORECAST.ETS.STAT.MULT", NOID,   NOID,   3,  6,  V, { VR, VA, 
VR }, FuncFlags::MACROCALL_NEW },
     { "ORG.LIBREOFFICE.ROUNDSIG",   "ORG.LIBREOFFICE.ROUNDSIG", NOID, NOID,  
2,  2,  V, { RX }, FuncFlags::MACROCALL_NEW },
     { "ORG.LIBREOFFICE.REGEX",      "ORG.LIBREOFFICE.REGEX", NOID, NOID,  2,  
4,  V, { RX }, FuncFlags::MACROCALL_NEW },
-    { "ORG.LIBREOFFICE.FOURIER",    "ORG.LIBREOFFICE.FOURIER", NOID, NOID,  2, 
 4,  A, { RX }, FuncFlags::MACROCALL_NEW }
+    { "ORG.LIBREOFFICE.FOURIER",    "ORG.LIBREOFFICE.FOURIER", NOID, NOID,  2, 
 5,  A, { RX }, FuncFlags::MACROCALL_NEW }
 
 };
 
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to