File: FourierTest.cpp

package info (click to toggle)
labplot 2.12.1-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 78,624 kB
  • sloc: cpp: 241,048; ansic: 6,324; python: 915; xml: 400; yacc: 237; sh: 221; awk: 35; makefile: 11
file content (145 lines) | stat: -rw-r--r-- 8,803 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
	File                 : FourierTest.cpp
	Project              : LabPlot
	Description          : Tests for fourier filtering
	--------------------------------------------------------------------
	SPDX-FileCopyrightText: 2022 Martin Marmsoler <martin.marmsoler@gmail.com>

	SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "FourierTest.h"
#include "backend/core/Project.h"
#include "backend/core/column/Column.h"
#include "backend/spreadsheet/Spreadsheet.h"
#include "backend/worksheet/Worksheet.h"
#include "backend/worksheet/plots/cartesian/CartesianPlot.h"
#include "backend/worksheet/plots/cartesian/XYAnalysisCurvePrivate.h"
#include "backend/worksheet/plots/cartesian/XYCurvePrivate.h"
#include "backend/worksheet/plots/cartesian/XYFourierFilterCurve.h"

// ##############################################################################

const QString dataPath = QStringLiteral("data/"); // relative path

#define READ_DATA(filename)                                                                                                                                    \
	auto filepath = QFINDTESTDATA(dataPath + filename);                                                                                                        \
	QVector<QVector<double>> data;                                                                                                                             \
	do {                                                                                                                                                       \
		QFile f(filepath);                                                                                                                                     \
		QCOMPARE(f.open(QIODevice::ReadOnly), true);                                                                                                           \
                                                                                                                                                               \
		while (!f.atEnd()) {                                                                                                                                   \
			const QString line = QLatin1String(f.readLine().simplified());                                                                                     \
			const auto entries = line.split(QLatin1Char(','));                                                                                                 \
			QVector<double> values;                                                                                                                            \
			for (const auto& entry : entries) {                                                                                                                \
				bool ok;                                                                                                                                       \
				double v = entry.toDouble(&ok);                                                                                                                \
				QVERIFY(ok);                                                                                                                                   \
				values.append(v);                                                                                                                              \
			}                                                                                                                                                  \
			data.append(values);                                                                                                                               \
		}                                                                                                                                                      \
		QVERIFY(data.count() > 0);                                                                                                                             \
		/* Check that all rows have the same number of values */                                                                                               \
		const auto length = data.at(0).length();                                                                                                               \
		for (const auto& v : data)                                                                                                                             \
			QCOMPARE(v.length(), length);                                                                                                                      \
	} while (false);

/*!
 * Writing the results to a file to validate them
 */
#define WRITE_RESULT_DATA(xData, yData, filteredDataRef, filteredData)                                                                                         \
	do {                                                                                                                                                       \
		QFile f(filepath + QStringLiteral("_testOutput.csv"));                                                                                                 \
		QCOMPARE(f.open(QIODevice::WriteOnly), true);                                                                                                          \
                                                                                                                                                               \
		f.write("x,y,filtered_reference, filtered_calculated\n"); /* header */                                                                                 \
		for (int i = 0; i < xData.length(); i++) {                                                                                                             \
			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());          \
		}                                                                                                                                                      \
	} while (false);

void FourierTest::addCurve() {
	Project project;

	auto* ws = new Worksheet(QStringLiteral("Worksheet"));
	project.addChild(ws);

	auto* plot = new CartesianPlot(QStringLiteral("plot"));
	ws->addChild(plot);

	auto* sheet = new Spreadsheet(QStringLiteral("sheet"));
	project.addChild(sheet);
	sheet->setColumnCount(2);
	sheet->column(0)->setName(QStringLiteral("x"));
	sheet->column(1)->setName(QStringLiteral("y"));

	auto* curve = new XYCurve(QStringLiteral("curve"));
	plot->addChild(curve);

	curve->d_func()->setSelected(true);
	QCOMPARE(plot->currentCurve(), curve);

	plot->addFourierFilterCurve(); // Should not crash and curve should be assigned accordingly

	const auto& analysisCurves = plot->children<XYAnalysisCurve>();
	QCOMPARE(analysisCurves.count(), 1);

	QCOMPARE(analysisCurves.at(0)->d_func()->dataSourceCurve, curve);
}

void FourierTest::lowPassButterWorth() {
	const QString filename = QStringLiteral("butterworth.csv");
	READ_DATA(filename);

	// data
	const auto xData = data.at(0);
	const auto yData = data.at(1);
	const auto filteredDataRef = data.at(2);

	// data source columns
	Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
	xDataColumn.replaceValues(0, xData);

	Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
	yDataColumn.replaceValues(0, yData);

	XYFourierFilterCurve curve(QStringLiteral("fourierFiltering"));
	curve.setXDataColumn(&xDataColumn);
	curve.setYDataColumn(&yDataColumn);

	// prepare the filtering
	auto filterData = curve.filterData();
	filterData.type = nsl_filter_type_low_pass;
	filterData.form = nsl_filter_form_butterworth;
	filterData.autoRange = true; // use complete data range
	filterData.cutoff = 100; // [Hz]
	// filterData.cutoff2; // Not relevant for lowpass filter
	filterData.order = 1;
	filterData.unit = nsl_filter_cutoff_unit_frequency;
	// filterData.unit2; // Not relevant for lowpass filter
	// filterData.xRange; // Not relevant because autoRange is true
	curve.setFilterData(filterData);

	// perform the differentiation
	curve.recalculate();
	const XYFourierFilterCurve::FilterResult& results = curve.filterResult();

	QVERIFY(results.available);
	QVERIFY(results.valid);

	// This does not work yet, because the implementation uses two side filtering,
	// considering knowing of future values (values after the current processed index)
	// Octave is using an IIR filter
	//	const auto xVec = *(curve.d_func()->xVector);
	//	const auto yVec = *(curve.d_func()->yVector);
	//	WRITE_RESULT_DATA(xData, yData, filteredDataRef, yVec);

	//	COMPARE_DOUBLE_VECTORS(xVec, xData);
	//	COMPARE_DOUBLE_VECTORS(yVec, filteredDataRef);
}

QTEST_MAIN(FourierTest)