[Libreoffice-commits] core.git: sc/inc sc/source
Dennis Francis (via logerrit)
logerrit at kemper.freedesktop.org
Tue Mar 26 13:30:33 UTC 2019
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.francis at collabora.com>
AuthorDate: Tue Mar 12 21:38:14 2019 +0530
Commit: Dennis Francis <dennis.francis at 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.francis at 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 }
};
More information about the Libreoffice-commits
mailing list