1 /***************************************************************************
2 * *
3 * copyright : (C) 2007 The University of Toronto *
4 * netterfield@astro.utoronto.ca *
5 * copyright : (C) 2005 by University of British Columbia *
6 * dscott@phas.ubc.ca *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 ***************************************************************************/
14
15 /** A class for handling spectrograms for kst
16 */
17
18 #include "csd.h"
19
20 #include <assert.h>
21 #include <math.h>
22
23 #include <QXmlStreamWriter>
24 #include <QLatin1String>
25
26
27
28 #include "dialoglauncher.h"
29 #include "datacollection.h"
30 #include "debug.h"
31 #include "psdcalculator.h"
32 #include "objectstore.h"
33
34 extern "C" void rdft(int n, int isgn, double *a);
35
36 namespace Kst {
37
38 const QString CSD::staticTypeString = "Spectrogram";
39 const QString CSD::staticTypeTag = "csd";
40
41 static const QLatin1String CSD_INVECTOR = QLatin1String("I");
42 static const QLatin1String& OUTMATRIX = QLatin1String("M");
43
44 #define KSTCSDMAXLEN 27
CSD(ObjectStore * store)45 CSD::CSD(ObjectStore *store)
46 : DataObject(store) {
47 _typeString = staticTypeString;
48 _type = "Spectrogram";
49
50 _initializeShortName();
51
52 Q_ASSERT(store);
53 MatrixPtr outMatrix = store->createObject<Matrix>();
54 outMatrix->setProvider(this);
55 outMatrix->setSlaveName("SG");
56 outMatrix->change(2, 2);
57 _outMatrix = _outputMatrices.insert(OUTMATRIX, outMatrix).value();
58 }
59
_initializeShortName()60 void CSD::_initializeShortName() {
61 _shortName = 'G'+QString::number(_csdnum);
62 if (_csdnum>max_csdnum)
63 max_csdnum = _csdnum;
64 _csdnum++;
65 }
66
change(VectorPtr in_V,double in_freq,bool in_average,bool in_removeMean,bool in_apodize,ApodizeFunction in_apodizeFxn,int in_windowSize,int in_length,double in_gaussianSigma,PSDType in_outputType,const QString & in_vectorUnits,const QString & in_rateUnits)67 void CSD::change(VectorPtr in_V, double in_freq, bool in_average,
68 bool in_removeMean, bool in_apodize, ApodizeFunction in_apodizeFxn,
69 int in_windowSize, int in_length, double in_gaussianSigma,
70 PSDType in_outputType, const QString& in_vectorUnits,
71 const QString& in_rateUnits) {
72
73 _inputVectors[CSD_INVECTOR] = in_V;
74 QString vecName = in_V ? in_V->Name() : QString();
75 _frequency = in_freq;
76 _average = in_average;
77 _apodize = in_apodize;
78 _windowSize = in_windowSize;
79 _apodizeFxn = in_apodizeFxn;
80 _gaussianSigma = in_gaussianSigma;
81 _removeMean = in_removeMean;
82 _averageLength = in_length;
83 _vectorUnits = in_vectorUnits;
84 _rateUnits = in_rateUnits;
85 _outputType = in_outputType;
86
87 if (_frequency <= 0.0) {
88 _frequency = 1.0;
89 }
90
91 updateMatrixLabels();
92 }
93
94
~CSD()95 CSD::~CSD() {
96 _outMatrix = 0L;
97 }
98
internalUpdate()99 void CSD::internalUpdate() {
100
101 VectorPtr inVector = _inputVectors[CSD_INVECTOR];
102
103 writeLockInputsAndOutputs();
104
105 double *tempOutput;//, *input;
106 int tempOutputLen = PSDCalculator::calculateOutputVectorLength(_windowSize, _average, _averageLength);
107 _length = tempOutputLen;
108 tempOutput = new double[tempOutputLen];
109
110 double const *input = inVector->noNanValue();
111
112 int xSize = 0;
113 for (int i=0; i < inVector->length(); i+= _windowSize) {
114 //ensure there is enough data left.
115 if (i + _windowSize >= inVector->length()) {
116 break; //If there isn't enough left for a complete window.
117 }
118
119 _psdCalculator.calculatePowerSpectrum(input + i, _windowSize, tempOutput, tempOutputLen, _removeMean, _average, _averageLength, _apodize, _apodizeFxn, _gaussianSigma, _outputType, _frequency);
120
121 // resize output matrix
122 _outMatrix->resize(xSize+1, tempOutputLen);
123
124 if (_outMatrix->sampleCount() == (xSize+1)*tempOutputLen) { // all is well.
125 // copy elements to output matrix
126 for (int j=0; j < tempOutputLen; j++) {
127 _outMatrix->setValueRaw(xSize, j, tempOutput[j]);
128 }
129 } else {
130 Debug::self()->log(tr("Could not allocate sufficient memory for Spectrogram."), Debug::Error);
131 break;
132 }
133
134 xSize++;
135 }
136
137 delete[] tempOutput;
138
139 double frequencyStep = .5*_frequency/(double)(tempOutputLen-1);
140
141 _outMatrix->change(xSize, tempOutputLen, 0, 0, _windowSize/_frequency, frequencyStep);
142
143 unlockInputsAndOutputs();
144
145 return;
146 }
147
148
save(QXmlStreamWriter & s)149 void CSD::save(QXmlStreamWriter &s) {
150 s.writeStartElement(staticTypeTag);
151 s.writeAttribute("vector", _inputVectors[CSD_INVECTOR]->Name());
152 s.writeAttribute("samplerate", QString::number(_frequency));
153 s.writeAttribute("gaussiansigma", QString::number(_gaussianSigma));
154 s.writeAttribute("average", QVariant(_average).toString());
155 s.writeAttribute("fftlength", QString::number(int(ceil(log(double(_length*2)) / log(2.0)))));
156 s.writeAttribute("removemean", QVariant(_removeMean).toString());
157 s.writeAttribute("apodize", QVariant(_apodize).toString());
158 s.writeAttribute("apodizefunction", QString::number(_apodizeFxn));
159 s.writeAttribute("windowsize", QString::number(_windowSize));
160 s.writeAttribute("vectorunits", _vectorUnits);
161 s.writeAttribute("rateunits", _rateUnits);
162 s.writeAttribute("outputtype", QString::number(_outputType));
163 saveNameInfo(s,VECTORNUM|SCALARNUM|MATRIXNUM|CSDNUM);
164
165 s.writeEndElement();
166 }
167
168
setVector(VectorPtr new_v)169 void CSD::setVector(VectorPtr new_v) {
170 VectorPtr v = _inputVectors[CSD_INVECTOR];
171 if (v) {
172 if (v == new_v) {
173 return;
174 }
175 v->unlock();
176 }
177
178 _inputVectors.remove(CSD_INVECTOR);
179 new_v->writeLock();
180 _inputVectors[CSD_INVECTOR] = new_v;
181 }
182
183
vector() const184 VectorPtr CSD::vector() const {
185 return _inputVectors[CSD_INVECTOR];
186 }
187
188
slaveVectorsUsed() const189 bool CSD::slaveVectorsUsed() const {
190 return true;
191 }
192
193
propertyString() const194 QString CSD::propertyString() const {
195 return tr("Spectrogram: %1").arg(_inputVectors[CSD_INVECTOR]->Name());
196 }
197
198
showNewDialog()199 void CSD::showNewDialog() {
200 DialogLauncher::self()->showCSDDialog();
201 }
202
203
showEditDialog()204 void CSD::showEditDialog() {
205 DialogLauncher::self()->showCSDDialog(this);
206 }
207
208
apodize() const209 bool CSD::apodize() const {
210 return _apodize;
211 }
212
213
output() const214 PSDType CSD::output() const {
215 return _outputType;
216 }
217
218
setOutput(PSDType in_outputType)219 void CSD::setOutput(PSDType in_outputType) {
220 _outputType = in_outputType;
221
222 updateMatrixLabels();
223 }
224
225
setApodize(bool in_apodize)226 void CSD::setApodize(bool in_apodize) {
227 _apodize = in_apodize;
228 }
229
230
removeMean() const231 bool CSD::removeMean() const {
232 return _removeMean;
233 }
234
235
setRemoveMean(bool in_removeMean)236 void CSD::setRemoveMean(bool in_removeMean) {
237 _removeMean = in_removeMean;
238 }
239
240
average() const241 bool CSD::average() const {
242 return _average;
243 }
244
245
setAverage(bool in_average)246 void CSD::setAverage(bool in_average) {
247 _average = in_average;
248 }
249
250
frequency() const251 double CSD::frequency() const {
252 return _frequency;
253 }
254
255
setFrequency(double in_frequency)256 void CSD::setFrequency(double in_frequency) {
257 if (in_frequency > 0.0) {
258 _frequency = in_frequency;
259 } else {
260 _frequency = 1.0;
261 }
262 }
263
apodizeFxn() const264 ApodizeFunction CSD::apodizeFxn() const {
265 return _apodizeFxn;
266 }
267
setApodizeFxn(ApodizeFunction in_fxn)268 void CSD::setApodizeFxn(ApodizeFunction in_fxn) {
269 _apodizeFxn = in_fxn;
270 }
271
length() const272 int CSD::length() const {
273 return _averageLength;
274 }
275
setLength(int in_length)276 void CSD::setLength(int in_length) {
277 _averageLength = in_length;
278 }
279
280
windowSize() const281 int CSD::windowSize() const {
282 return _windowSize;
283 }
284
285
setWindowSize(int in_size)286 void CSD::setWindowSize(int in_size) {
287 _windowSize = in_size;
288 }
289
gaussianSigma() const290 double CSD::gaussianSigma() const {
291 return _gaussianSigma;
292 }
293
setGaussianSigma(double in_sigma)294 void CSD::setGaussianSigma(double in_sigma) {
295 _gaussianSigma = in_sigma;
296 }
297
298
outputMatrix() const299 MatrixPtr CSD::outputMatrix() const {
300 return _outMatrix;
301 }
302
303
vectorUnits() const304 const QString& CSD::vectorUnits() const {
305 return _vectorUnits;
306 }
307
308
setVectorUnits(const QString & units)309 void CSD::setVectorUnits(const QString& units) {
310 _vectorUnits = units;
311 }
312
313
rateUnits() const314 const QString& CSD::rateUnits() const {
315 return _rateUnits;
316 }
317
318
setRateUnits(const QString & units)319 void CSD::setRateUnits(const QString& units) {
320 _rateUnits = units;
321 }
322
323
makeDuplicate() const324 DataObjectPtr CSD::makeDuplicate() const{
325
326 CSDPtr csd = store()->createObject<CSD>();
327 csd->change(_inputVectors[CSD_INVECTOR],
328 _frequency,
329 _average,
330 _removeMean,
331 _apodize,
332 _apodizeFxn,
333 _windowSize,
334 _averageLength,
335 _gaussianSigma,
336 _outputType,
337 _vectorUnits,
338 _rateUnits);
339 if (descriptiveNameIsManual()) {
340 csd->setDescriptiveName(descriptiveName());
341 }
342 csd->writeLock();
343 csd->registerChange();
344 csd->unlock();
345
346 return DataObjectPtr(csd);
347 }
348
updateMatrixLabels(void)349 void CSD::updateMatrixLabels(void) {
350
351 LabelInfo label_info;
352
353 switch (_outputType) {
354 default:
355 case 0: // amplitude spectral density (default) [V/Hz^1/2]
356 label_info.quantity = tr("Amplitude Spectral Density");
357 label_info.units = QString("%1/%2^{1/2}").arg(_vectorUnits).arg(_rateUnits);
358 break;
359 case 1: // power spectral density [V^2/Hz]
360 label_info.quantity = tr("Power Spectral Density");
361 label_info.units = QString("%1^2/%2").arg(_vectorUnits).arg(_rateUnits);
362 break;
363 case 2: // amplitude spectrum [V]
364 label_info.quantity = tr("Amplitude Spectrum");
365 label_info.units = QString("%1").arg(_vectorUnits);
366 break;
367 case 3: // power spectrum [V^2]
368 label_info.quantity = tr("Power Spectrum");
369 label_info.units = QString("%1^2").arg(_vectorUnits);
370 break;
371 }
372 label_info.name = _inputVectors[CSD_INVECTOR]->descriptiveName();
373 _outMatrix->setTitleInfo(label_info);
374
375 label_info.name.clear();
376 label_info.units = _rateUnits;
377 label_info.quantity = tr("Frequency");
378 _outMatrix->setYLabelInfo(label_info);
379
380 label_info.quantity = tr("Time");
381 label_info.units = QString('s');
382 _outMatrix->setXLabelInfo(label_info);
383
384 }
385
_automaticDescriptiveName() const386 QString CSD::_automaticDescriptiveName() const {
387 return vector()->descriptiveName();
388 }
389
descriptionTip() const390 QString CSD::descriptionTip() const {
391 QString tip;
392
393 tip = tr("Spectrogram: %1\n FFT Length: 2^%2").arg(Name()).arg(length());
394
395 if (average() || apodize() || removeMean()) {
396 tip += "\n ";
397 if (average()) tip += tr("Average; ");
398 if (apodize()) tip += tr("Apodize; ");
399 if (removeMean()) tip += tr("Remove Mean;");
400 }
401 tip += tr("\nInput: %1").arg(_inputVectors[CSD_INVECTOR]->descriptionTip());
402 return tip;
403
404 }
405 }
406
407 // vim: ts=2 sw=2 et
408