##// END OF EJS Templates
Implements methods for generating spectrograms in the plugin
Alexandre Leroux -
r896:ba6dbb64fae0
parent child
Show More
@@ -1,263 +1,274
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2 #include "MockDefs.h"
2 #include "MockDefs.h"
3
3
4 #include <Data/DataProviderParameters.h>
4 #include <Data/DataProviderParameters.h>
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <Data/SpectrogramSeries.h>
6 #include <Data/SpectrogramSeries.h>
7 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
8
8
9 #include <cmath>
9 #include <cmath>
10
10
11 #include <QFuture>
11 #include <QFuture>
12 #include <QThread>
12 #include <QThread>
13 #include <QtConcurrent/QtConcurrent>
13 #include <QtConcurrent/QtConcurrent>
14
14
15 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
15 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
16
16
17 namespace {
17 namespace {
18
18
19 /// Number of bands generated for a spectrogram
19 /// Number of bands generated for a spectrogram
20 const auto SPECTROGRAM_NUMBER_BANDS = 30;
20 const auto SPECTROGRAM_NUMBER_BANDS = 30;
21
21
22 /// Abstract cosinus type
22 /// Abstract cosinus type
23 struct ICosinusType {
23 struct ICosinusType {
24 virtual ~ICosinusType() = default;
24 virtual ~ICosinusType() = default;
25 /// @return the number of components generated for the type
25 /// @return the number of components generated for the type
26 virtual int componentCount() const = 0;
26 virtual int componentCount() const = 0;
27 /// @return the data series created for the type
27 /// @return the data series created for the type
28 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
28 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
29 std::vector<double> valuesData,
29 std::vector<double> valuesData,
30 Unit xAxisUnit,
30 Unit xAxisUnit,
31 Unit valuesUnit) const = 0;
31 Unit valuesUnit) const = 0;
32 /// Generates values (one value per component)
32 /// Generates values (one value per component)
33 /// @param x the x-axis data used to generate values
33 /// @param x the x-axis data used to generate values
34 /// @param values the vector in which to insert the generated values
34 /// @param values the vector in which to insert the generated values
35 /// @param dataIndex the index of insertion of the generated values
35 /// @param dataIndex the index of insertion of the generated values
36 ///
36 ///
37 virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
37 virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
38 };
38 };
39
39
40 struct ScalarCosinus : public ICosinusType {
40 struct ScalarCosinus : public ICosinusType {
41 int componentCount() const override { return 1; }
41 int componentCount() const override { return 1; }
42
42
43 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
43 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
44 std::vector<double> valuesData, Unit xAxisUnit,
44 std::vector<double> valuesData, Unit xAxisUnit,
45 Unit valuesUnit) const override
45 Unit valuesUnit) const override
46 {
46 {
47 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
47 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
48 xAxisUnit, valuesUnit);
48 xAxisUnit, valuesUnit);
49 }
49 }
50
50
51 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
51 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
52 {
52 {
53 values[dataIndex] = std::cos(x);
53 values[dataIndex] = std::cos(x);
54 }
54 }
55 };
55 };
56
56
57 struct SpectrogramCosinus : public ICosinusType {
57 struct SpectrogramCosinus : public ICosinusType {
58 /// Ctor with y-axis
58 /// Ctor with y-axis
59 explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit)
59 explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit)
60 : m_YAxisData{std::move(yAxisData)}, m_YAxisUnit{std::move(yAxisUnit)}
60 : m_YAxisData{std::move(yAxisData)}, m_YAxisUnit{std::move(yAxisUnit)}
61 {
61 {
62 }
62 }
63
63
64 int componentCount() const override { return m_YAxisData.size(); }
64 int componentCount() const override { return m_YAxisData.size(); }
65
65
66 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
66 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
67 std::vector<double> valuesData, Unit xAxisUnit,
67 std::vector<double> valuesData, Unit xAxisUnit,
68 Unit valuesUnit) const override
68 Unit valuesUnit) const override
69 {
69 {
70 return std::make_shared<SpectrogramSeries>(std::move(xAxisData), m_YAxisData,
71 std::move(valuesData), xAxisUnit, m_YAxisUnit,
72 valuesUnit);
70 }
73 }
71
74
72 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
75 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
73 {
76 {
77 auto componentCount = this->componentCount();
78 for (int i = 0; i < componentCount; ++i) {
79 auto y = m_YAxisData[i];
80 auto r = 3 * std::sqrt(x * x + y * y) + 1e-2;
81 auto value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r);
82
83 values[componentCount * dataIndex + i] = value;
84 }
74 }
85 }
75
86
76 std::vector<double> m_YAxisData;
87 std::vector<double> m_YAxisData;
77 Unit m_YAxisUnit;
88 Unit m_YAxisUnit;
78 };
89 };
79
90
80 struct VectorCosinus : public ICosinusType {
91 struct VectorCosinus : public ICosinusType {
81 int componentCount() const override { return 3; }
92 int componentCount() const override { return 3; }
82
93
83 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
94 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
84 std::vector<double> valuesData, Unit xAxisUnit,
95 std::vector<double> valuesData, Unit xAxisUnit,
85 Unit valuesUnit) const override
96 Unit valuesUnit) const override
86 {
97 {
87 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
98 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
88 xAxisUnit, valuesUnit);
99 xAxisUnit, valuesUnit);
89 }
100 }
90
101
91 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
102 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
92 {
103 {
93 // Generates value for each component: cos(x), cos(x)/2, cos(x)/3
104 // Generates value for each component: cos(x), cos(x)/2, cos(x)/3
94 auto xValue = std::cos(x);
105 auto xValue = std::cos(x);
95 auto componentCount = this->componentCount();
106 auto componentCount = this->componentCount();
96 for (auto i = 0; i < componentCount; ++i) {
107 for (auto i = 0; i < componentCount; ++i) {
97 values[componentCount * dataIndex + i] = xValue / (i + 1);
108 values[componentCount * dataIndex + i] = xValue / (i + 1);
98 }
109 }
99 }
110 }
100 };
111 };
101
112
102 /// Converts string to cosinus type
113 /// Converts string to cosinus type
103 /// @return the cosinus type if the string could be converted, nullptr otherwise
114 /// @return the cosinus type if the string could be converted, nullptr otherwise
104 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
115 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
105 {
116 {
106 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
117 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
107 return std::make_unique<ScalarCosinus>();
118 return std::make_unique<ScalarCosinus>();
108 }
119 }
109 else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
120 else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
110 // Generates default y-axis data for spectrogram [0., 1., 2., ...]
121 // Generates default y-axis data for spectrogram [0., 1., 2., ...]
111 std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
122 std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
112 std::iota(yAxisData.begin(), yAxisData.end(), 0.);
123 std::iota(yAxisData.begin(), yAxisData.end(), 0.);
113
124
114 return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"});
125 return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"});
115 }
126 }
116 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
127 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
117 return std::make_unique<VectorCosinus>();
128 return std::make_unique<VectorCosinus>();
118 }
129 }
119 else {
130 else {
120 return nullptr;
131 return nullptr;
121 }
132 }
122 }
133 }
123
134
124 } // namespace
135 } // namespace
125
136
126 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
137 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
127 {
138 {
128 // No copy is made in clone
139 // No copy is made in clone
129 return std::make_shared<CosinusProvider>();
140 return std::make_shared<CosinusProvider>();
130 }
141 }
131
142
132 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
143 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
133 const SqpRange &dataRangeRequested,
144 const SqpRange &dataRangeRequested,
134 const QVariantHash &data)
145 const QVariantHash &data)
135 {
146 {
136 // TODO: Add Mutex
147 // TODO: Add Mutex
137 auto dataIndex = 0;
148 auto dataIndex = 0;
138
149
139 // Retrieves cosinus type
150 // Retrieves cosinus type
140 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
151 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
141 if (!typeVariant.canConvert<QString>()) {
152 if (!typeVariant.canConvert<QString>()) {
142 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
153 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
143 return nullptr;
154 return nullptr;
144 }
155 }
145
156
146 auto type = cosinusType(typeVariant.toString());
157 auto type = cosinusType(typeVariant.toString());
147 if (!type) {
158 if (!type) {
148 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
159 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
149 return nullptr;
160 return nullptr;
150 }
161 }
151
162
152 // Retrieves frequency
163 // Retrieves frequency
153 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
164 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
154 if (!freqVariant.canConvert<double>()) {
165 if (!freqVariant.canConvert<double>()) {
155 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
166 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
156 return nullptr;
167 return nullptr;
157 }
168 }
158
169
159 // Gets the timerange from the parameters
170 // Gets the timerange from the parameters
160 double freq = freqVariant.toDouble();
171 double freq = freqVariant.toDouble();
161 double start = std::ceil(dataRangeRequested.m_TStart * freq);
172 double start = std::ceil(dataRangeRequested.m_TStart * freq);
162 double end = std::floor(dataRangeRequested.m_TEnd * freq);
173 double end = std::floor(dataRangeRequested.m_TEnd * freq);
163
174
164 // We assure that timerange is valid
175 // We assure that timerange is valid
165 if (end < start) {
176 if (end < start) {
166 std::swap(start, end);
177 std::swap(start, end);
167 }
178 }
168
179
169 // Generates scalar series containing cosinus values (one value per second, end value is
180 // Generates scalar series containing cosinus values (one value per second, end value is
170 // included)
181 // included)
171 auto dataCount = end - start + 1;
182 auto dataCount = end - start + 1;
172
183
173 // Number of components (depending on the cosinus type)
184 // Number of components (depending on the cosinus type)
174 auto componentCount = type->componentCount();
185 auto componentCount = type->componentCount();
175
186
176 auto xAxisData = std::vector<double>{};
187 auto xAxisData = std::vector<double>{};
177 xAxisData.resize(dataCount);
188 xAxisData.resize(dataCount);
178
189
179 auto valuesData = std::vector<double>{};
190 auto valuesData = std::vector<double>{};
180 valuesData.resize(dataCount * componentCount);
191 valuesData.resize(dataCount * componentCount);
181
192
182 int progress = 0;
193 int progress = 0;
183 auto progressEnd = dataCount;
194 auto progressEnd = dataCount;
184 for (auto time = start; time <= end; ++time, ++dataIndex) {
195 for (auto time = start; time <= end; ++time, ++dataIndex) {
185 auto it = m_VariableToEnableProvider.find(acqIdentifier);
196 auto it = m_VariableToEnableProvider.find(acqIdentifier);
186 if (it != m_VariableToEnableProvider.end() && it.value()) {
197 if (it != m_VariableToEnableProvider.end() && it.value()) {
187 const auto x = time / freq;
198 const auto x = time / freq;
188
199
189 xAxisData[dataIndex] = x;
200 xAxisData[dataIndex] = x;
190
201
191 // Generates values (depending on the type)
202 // Generates values (depending on the type)
192 type->generateValues(x, valuesData, dataIndex);
203 type->generateValues(x, valuesData, dataIndex);
193
204
194 // progression
205 // progression
195 int currentProgress = (time - start) * 100.0 / progressEnd;
206 int currentProgress = (time - start) * 100.0 / progressEnd;
196 if (currentProgress != progress) {
207 if (currentProgress != progress) {
197 progress = currentProgress;
208 progress = currentProgress;
198
209
199 emit dataProvidedProgress(acqIdentifier, progress);
210 emit dataProvidedProgress(acqIdentifier, progress);
200 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
211 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
201 << QThread::currentThread()->objectName()
212 << QThread::currentThread()->objectName()
202 << progress;
213 << progress;
203 // NOTE: Try to use multithread if possible
214 // NOTE: Try to use multithread if possible
204 }
215 }
205 }
216 }
206 else {
217 else {
207 if (!it.value()) {
218 if (!it.value()) {
208 qCDebug(LOG_CosinusProvider())
219 qCDebug(LOG_CosinusProvider())
209 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
220 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
210 << end - time;
221 << end - time;
211 }
222 }
212 }
223 }
213 }
224 }
214 if (progress != 100) {
225 if (progress != 100) {
215 // We can close progression beacause all data has been retrieved
226 // We can close progression beacause all data has been retrieved
216 emit dataProvidedProgress(acqIdentifier, 100);
227 emit dataProvidedProgress(acqIdentifier, 100);
217 }
228 }
218 return type->createDataSeries(std::move(xAxisData), std::move(valuesData),
229 return type->createDataSeries(std::move(xAxisData), std::move(valuesData),
219 Unit{QStringLiteral("t"), true}, Unit{});
230 Unit{QStringLiteral("t"), true}, Unit{});
220 }
231 }
221
232
222 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
233 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
223 const DataProviderParameters &parameters)
234 const DataProviderParameters &parameters)
224 {
235 {
225 // TODO: Add Mutex
236 // TODO: Add Mutex
226 m_VariableToEnableProvider[acqIdentifier] = true;
237 m_VariableToEnableProvider[acqIdentifier] = true;
227 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
238 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
228 << QThread::currentThread()->objectName();
239 << QThread::currentThread()->objectName();
229 // NOTE: Try to use multithread if possible
240 // NOTE: Try to use multithread if possible
230 const auto times = parameters.m_Times;
241 const auto times = parameters.m_Times;
231
242
232 for (const auto &dateTime : qAsConst(times)) {
243 for (const auto &dateTime : qAsConst(times)) {
233 if (m_VariableToEnableProvider[acqIdentifier]) {
244 if (m_VariableToEnableProvider[acqIdentifier]) {
234 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
245 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
235 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
246 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
236 }
247 }
237 }
248 }
238 }
249 }
239
250
240 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
251 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
241 {
252 {
242 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
253 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
243 << QThread::currentThread()->objectName();
254 << QThread::currentThread()->objectName();
244 auto it = m_VariableToEnableProvider.find(acqIdentifier);
255 auto it = m_VariableToEnableProvider.find(acqIdentifier);
245 if (it != m_VariableToEnableProvider.end()) {
256 if (it != m_VariableToEnableProvider.end()) {
246 it.value() = false;
257 it.value() = false;
247 }
258 }
248 else {
259 else {
249 qCDebug(LOG_CosinusProvider())
260 qCDebug(LOG_CosinusProvider())
250 << tr("Aborting progression of inexistant identifier detected !!!");
261 << tr("Aborting progression of inexistant identifier detected !!!");
251 }
262 }
252 }
263 }
253
264
254 std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const SqpRange &dataRangeRequested,
265 std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const SqpRange &dataRangeRequested,
255 const QVariantHash &data)
266 const QVariantHash &data)
256 {
267 {
257 auto uid = QUuid::createUuid();
268 auto uid = QUuid::createUuid();
258 m_VariableToEnableProvider[uid] = true;
269 m_VariableToEnableProvider[uid] = true;
259 auto dataSeries = this->retrieveData(uid, dataRangeRequested, data);
270 auto dataSeries = this->retrieveData(uid, dataRangeRequested, data);
260
271
261 m_VariableToEnableProvider.remove(uid);
272 m_VariableToEnableProvider.remove(uid);
262 return dataSeries;
273 return dataSeries;
263 }
274 }
General Comments 0
You need to be logged in to leave comments. Login now