File indexing completed on 2024-11-10 09:31:54
0001 /* 0002 File : FourierTest.cpp 0003 Project : LabPlot 0004 Description : Tests for fourier filtering 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2022 Martin Marmsoler <martin.marmsoler@gmail.com> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "FourierTest.h" 0012 #include "backend/core/column/Column.h" 0013 #include "backend/worksheet/plots/cartesian/XYFourierFilterCurve.h" 0014 // #include "backend/worksheet/plots/cartesian/XYFourierFilterCurvePrivate.h" 0015 0016 // ############################################################################## 0017 0018 const QString dataPath = QStringLiteral("data/"); // relative path 0019 0020 #define READ_DATA(filename) \ 0021 auto filepath = QFINDTESTDATA(dataPath + filename); \ 0022 QVector<QVector<double>> data; \ 0023 do { \ 0024 QFile f(filepath); \ 0025 QCOMPARE(f.open(QIODevice::ReadOnly), true); \ 0026 \ 0027 while (!f.atEnd()) { \ 0028 const QString line = QLatin1String(f.readLine().simplified()); \ 0029 const auto entries = line.split(QLatin1Char(',')); \ 0030 QVector<double> values; \ 0031 for (const auto& entry : entries) { \ 0032 bool ok; \ 0033 double v = entry.toDouble(&ok); \ 0034 QVERIFY(ok); \ 0035 values.append(v); \ 0036 } \ 0037 data.append(values); \ 0038 } \ 0039 QVERIFY(data.count() > 0); \ 0040 /* Check that all rows have the same number of values */ \ 0041 const auto length = data.at(0).length(); \ 0042 for (const auto& v : data) \ 0043 QCOMPARE(v.length(), length); \ 0044 } while (false); 0045 0046 /*! 0047 * Writing the results to a file to validate them 0048 */ 0049 #define WRITE_RESULT_DATA(xData, yData, filteredDataRef, filteredData) \ 0050 do { \ 0051 QFile f(filepath + QStringLiteral("_testOutput.csv")); \ 0052 QCOMPARE(f.open(QIODevice::WriteOnly), true); \ 0053 \ 0054 f.write("x,y,filtered_reference, filtered_calculated\n"); /* header */ \ 0055 for (int i = 0; i < xData.length(); i++) { \ 0056 f.write(QStringLiteral("%1,%2,%3,%4\n").arg(xData.at(i)).arg(yData.at(i)).arg(filteredDataRef.at(i)).arg(filteredData.at(i)).toLatin1()); \ 0057 } \ 0058 } while (false); 0059 0060 void FourierTest::lowPassButterWorth() { 0061 const QString filename = QStringLiteral("butterworth.csv"); 0062 READ_DATA(filename); 0063 0064 // data 0065 const auto xData = data.at(0); 0066 const auto yData = data.at(1); 0067 const auto filteredDataRef = data.at(2); 0068 0069 // data source columns 0070 Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double); 0071 xDataColumn.replaceValues(0, xData); 0072 0073 Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double); 0074 yDataColumn.replaceValues(0, yData); 0075 0076 XYFourierFilterCurve curve(QStringLiteral("fourierFiltering")); 0077 curve.setXDataColumn(&xDataColumn); 0078 curve.setYDataColumn(&yDataColumn); 0079 0080 // prepare the filtering 0081 auto filterData = curve.filterData(); 0082 filterData.type = nsl_filter_type_low_pass; 0083 filterData.form = nsl_filter_form_butterworth; 0084 filterData.autoRange = true; // use complete data range 0085 filterData.cutoff = 100; // [Hz] 0086 // filterData.cutoff2; // Not relevant for lowpass filter 0087 filterData.order = 1; 0088 filterData.unit = nsl_filter_cutoff_unit_frequency; 0089 // filterData.unit2; // Not relevant for lowpass filter 0090 // filterData.xRange; // Not relevant because autoRange is true 0091 curve.setFilterData(filterData); 0092 0093 // perform the differentiation 0094 curve.recalculate(); 0095 const XYFourierFilterCurve::FilterResult& results = curve.filterResult(); 0096 0097 QVERIFY(results.available); 0098 QVERIFY(results.valid); 0099 0100 // This does not work yet, because the implementation uses two side filtering, 0101 // considering knowing of future values (values after the current processed index) 0102 // Octave is using an IIR filter 0103 // const auto xVec = *(curve.d_func()->xVector); 0104 // const auto yVec = *(curve.d_func()->yVector); 0105 // WRITE_RESULT_DATA(xData, yData, filteredDataRef, yVec); 0106 0107 // COMPARE_DOUBLE_VECTORS(xVec, xData); 0108 // COMPARE_DOUBLE_VECTORS(yVec, filteredDataRef); 0109 } 0110 0111 QTEST_MAIN(FourierTest)