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