[Kst] branches/work/kst/pluginify/kst/src/plugins/crossspectrum

Adam Treat treat at kde.org
Thu Sep 14 20:36:55 CEST 2006


SVN commit 584407 by treat:

* Implement the crosspectrum as new plugin


 M  +275 -11   crosspowerspectrum.cpp  
 M  +26 -6     crosspowerspectrum.h  


--- branches/work/kst/pluginify/kst/src/plugins/crossspectrum/crosspowerspectrum.cpp #584406:584407
@@ -16,10 +16,29 @@
  ***************************************************************************/
 #include "crosspowerspectrum.h"
 
+#include <qstylesheet.h>
+
 #include <kdebug.h>
 #include <kmessagebox.h>
 #include <kgenericfactory.h>
 
+#include <kstdatacollection.h>
+
+#define KSTPSDMAXLEN 27
+
+extern "C" void rdft(int n, int isgn, double *a); //fast fourier transform...
+
+static const QString& VECTOR_ONE = KGlobal::staticQString("Vector One");
+static const QString& VECTOR_TWO = KGlobal::staticQString("Vector Two");
+
+//in scalars
+static const QString& FFT_LENGTH = KGlobal::staticQString("FFT Length = 2^");
+static const QString& SAMPLE_RATE = KGlobal::staticQString("Sample Rate");
+
+static const QString& REAL = KGlobal::staticQString("Cross Spectrum: Real");
+static const QString& IMAGINARY = KGlobal::staticQString("Cross Spectrum: Imaginary");
+static const QString& FREQUENCY = KGlobal::staticQString("Frequency");
+
 K_EXPORT_COMPONENT_FACTORY( kst_crossspectrum,
     KGenericFactory<CrossPowerSpectrum>( "kst_crossspectrum" ) )
 
@@ -30,29 +49,274 @@
 CrossPowerSpectrum::~CrossPowerSpectrum() {
 }
 
-KstObject::UpdateType CrossPowerSpectrum::update(int)
-{
-  return UPDATE;
+KstVectorPtr CrossPowerSpectrum::v1() const {
+  return *_inputVectors.find(VECTOR_ONE);
 }
 
-QString CrossPowerSpectrum::propertyString() const
+KstVectorPtr CrossPowerSpectrum::v2() const {
+  return *_inputVectors.find(VECTOR_TWO);
+}
+
+KstScalarPtr CrossPowerSpectrum::fft() const {
+  return *_inputScalars.find(FFT_LENGTH);
+}
+
+KstScalarPtr CrossPowerSpectrum::sample() const {
+  return *_inputScalars.find(SAMPLE_RATE);
+}
+
+KstVectorPtr CrossPowerSpectrum::real() const {
+  return *_outputVectors.find(REAL);
+}
+
+KstVectorPtr CrossPowerSpectrum::imaginary() const {
+  return *_outputVectors.find(IMAGINARY);
+}
+
+KstVectorPtr CrossPowerSpectrum::frequency() const {
+  return *_outputVectors.find(FREQUENCY);
+}
+
+KstObject::UpdateType CrossPowerSpectrum::update(int updateCounter)
 {
-  return "";
+  bool force = dirty();
+  setDirty(false);
+
+  if (KstObject::checkUpdateCounter(updateCounter) && !force) {
+    return lastUpdateResult();
+  }
+
+  if (v1() || !v2() || !fft() || !sample()) {
+    return setLastUpdateResult(NO_CHANGE);
+  }
+
+  bool depUpdated = force;
+
+  depUpdated = UPDATE == v1()->update(updateCounter) || depUpdated;
+  depUpdated = UPDATE == v2()->update(updateCounter) || depUpdated;
+
+  depUpdated = UPDATE == fft()->update(updateCounter) || depUpdated;
+  depUpdated = UPDATE == sample()->update(updateCounter) || depUpdated;
+
+  crossspectrum();
+
+  vectorRealloced(real(), real()->value(), 2);
+  real()->setDirty();
+  real()->setNewAndShift(real()->length(), real()->numShift());
+  real()->update(updateCounter);
+
+  vectorRealloced(imaginary(), imaginary()->value(), 2);
+  imaginary()->setDirty();
+  imaginary()->setNewAndShift(imaginary()->length(), imaginary()->numShift());
+  imaginary()->update(updateCounter);
+
+  vectorRealloced(frequency(), frequency()->value(), 2);
+  frequency()->setDirty();
+  frequency()->setNewAndShift(frequency()->length(), frequency()->numShift());
+  frequency()->update(updateCounter);
+
+  return setLastUpdateResult(depUpdated ? UPDATE : NO_CHANGE);
 }
 
-KstDataObjectPtr CrossPowerSpectrum::makeDuplicate(KstDataObjectDataObjectMap&)
-{
+void CrossPowerSpectrum::crossspectrum() {
+  double SR = sample()->value(); // sample rate
+  double df;
+  int i,  xps_len;
+  double *a,  *b;
+  double mean_a,  mean_b;
+  int dv0,  dv1,  v_len;
+  int i_subset,  n_subsets;
+  int i_samp,  copyLen;
+  double norm_factor;
+
+  /* parse fft length */
+  xps_len = int( fft()->value() - 0.99);
+  if ( xps_len > KSTPSDMAXLEN ) xps_len = KSTPSDMAXLEN;
+  if ( xps_len<2 ) xps_len = 2;
+  xps_len = int ( pow( 2,  xps_len ) );
+
+  /* input vector lengths */
+  v_len = ( ( v1()->length() < v2()->length() ) ?
+      v1()->length() : v2()->length() );
+  dv0 = v_len/v1()->length();
+  dv1 = v_len/v2()->length();
+
+  while ( xps_len > v_len ) xps_len/=2;
+
+  // allocate the lengths
+  if ( real()->length() != xps_len ) {
+    real()->resize( xps_len, false );
+    imaginary()->resize( xps_len, false );
+    frequency()->resize( xps_len, false );
+  }
+
+  /* Fill the frequency and zero the xps */
+  df = SR/( 2.0*double( xps_len-1 ) );
+  for ( i=0; i<xps_len; i++ ) {
+    frequency()->value()[i] = double( i ) * df;
+    real()->value()[i] = 0.0;
+    imaginary()->value()[i] = 0.0;
+  }
+
+  /* allocate input arrays */
+  int ALen = xps_len * 2;
+  a = new double[ALen];
+  b = new double[ALen];
+
+  /* do the fft's */
+  n_subsets = v_len/xps_len + 1;
+
+  for ( i_subset=0; i_subset<n_subsets; i_subset++ ) {
+    /* copy each chunk into a[] and find mean */
+    if (i_subset*xps_len + ALen <= v_len) {
+      copyLen = ALen;
+    } else {
+      copyLen = v_len - i_subset*xps_len;
+    }
+    mean_b = mean_a = 0;
+    for (i_samp = 0; i_samp < copyLen; i_samp++) {
+      i = ( i_samp + i_subset*xps_len )/dv0;
+      mean_a += (
+          a[i_samp] = v1()->value()[i]
+                );
+      i = ( i_samp + i_subset*xps_len )/dv1;
+      mean_b += (
+          b[i_samp] = v2()->value()[i]
+                );
+    }
+    if (copyLen>1) {
+      mean_a/=(double)copyLen;
+      mean_b/=(double)copyLen;
+    }
+
+    /* Remove Mean and apodize */
+    for (i_samp=0; i_samp<copyLen; i_samp++) {
+      a[i_samp] -= mean_a;
+      b[i_samp] -= mean_b;
+    }
+
+    for (;i_samp < ALen; i_samp++) {
+      a[i_samp] = 0.0;
+      b[i_samp] = 0.0;
+    }
+
+    /* fft */
+    rdft(ALen, 1, a);
+    rdft(ALen, 1, b);
+
+    /* sum each bin into psd[] */
+    real()->value()[0] += ( a[0]*b[0] );
+    real()->value()[xps_len-1] += ( a[1]*b[1] );
+    for (i_samp=1; i_samp<xps_len-1; i_samp++) {
+      real()->value()[i_samp]+= ( a[i_samp*2] * b[i_samp*2] -
+          a[i_samp*2+1] * b[i_samp*2+1] );
+      imaginary()->value()[i_samp]+= ( -a[i_samp*2] * b[i_samp*2+1] +
+          a[i_samp*2+1] * b[i_samp*2] );
+    }// (a+ci)(b+di)* = ab+cd +i(-ad + cb)
+  }
+
+  /* renormalize */
+  norm_factor = 1.0/((double(SR)*double(xps_len))*double(n_subsets));
+  for ( i=0; i<xps_len; i++ ) {
+    real()->value()[i]*=norm_factor;
+    imaginary()->value()[i]*=norm_factor;
+  }
+
+  /* free */
+  delete[] b;
+  delete[] a;
+//   return 0;
+}
+
+QString CrossPowerSpectrum::propertyString() const {
+  return "crosspowerspectrum";
+}
+
+KstDataObjectPtr CrossPowerSpectrum::makeDuplicate(KstDataObjectDataObjectMap&) {
   return 0;
 }
 
-void CrossPowerSpectrum::showNewDialog()
-{
+void CrossPowerSpectrum::showNewDialog() {
   KMessageBox::information( 0, "insert testplugin config widget here :)", "testpluginconfig" );
 }
 
-void CrossPowerSpectrum::showEditDialog()
-{
+void CrossPowerSpectrum::showEditDialog() {
   KMessageBox::information( 0, "insert testplugin config widget here :)", "testpluginconfig" );
 }
 
+void CrossPowerSpectrum::load(const QDomElement &e) {
+  QDomNode n = e.firstChild();
+
+  while (!n.isNull()) {
+    QDomElement e = n.toElement();
+    if (!e.isNull()) {
+      if (e.tagName() == "tag") {
+        setTagName(e.text());
+      } else if (e.tagName() == "ivector") {
+        _inputVectorLoadQueue.append(qMakePair(e.attribute("name"), e.text()));
+      } else if (e.tagName() == "iscalar") {
+        _inputScalarLoadQueue.append(qMakePair(e.attribute("name"), e.text()));
+      } else if (e.tagName() == "istring") {
+        _inputStringLoadQueue.append(qMakePair(e.attribute("name"), e.text()));
+      } else if (e.tagName() == "ovector") {
+        KstVectorPtr v;
+        if (e.attribute("scalarList", "0").toInt()) {
+          v = new KstVector(e.text(), 0, this, true);
+        } else {
+          v = new KstVector(e.text(), 0, this, false);
+        }
+        _outputVectors.insert(e.attribute("name"), v);
+        KST::addVectorToList(v);
+      } else if (e.tagName() == "oscalar") {
+        KstScalarPtr sp = new KstScalar(e.text(), this);
+        _outputScalars.insert(e.attribute("name"), sp);
+      } else if (e.tagName() == "ostring") {
+        KstStringPtr sp = new KstString(e.text(), this);
+        _outputStrings.insert(e.attribute("name"), sp);
+      }
+    }
+    n = n.nextSibling();
+  }
+}
+
+void CrossPowerSpectrum::save(QTextStream& ts, const QString& indent) {
+  QString l2 = indent + "  ";
+  ts << indent << "<plugin name=\"Cross Power Spectrum\">" << endl;
+  ts << l2 << "<tag>" << QStyleSheet::escape(tagName()) << "</tag>" << endl;
+  for (KstVectorMap::Iterator i = _inputVectors.begin(); i != _inputVectors.end(); ++i) {
+    ts << l2 << "<ivector name=\"" << QStyleSheet::escape(i.key()) << "\">"
+        << QStyleSheet::escape(i.data()->tagName())
+        << "</ivector>" << endl;
+  }
+  for (KstScalarMap::Iterator i = _inputScalars.begin(); i != _inputScalars.end(); ++i) {
+    ts << l2 << "<iscalar name=\"" << QStyleSheet::escape(i.key()) << "\">"
+        << QStyleSheet::escape(i.data()->tagName())
+        << "</iscalar>" << endl;
+  }
+  for (KstStringMap::Iterator i = _inputStrings.begin(); i != _inputStrings.end(); ++i) {
+    ts << l2 << "<istring name=\"" << QStyleSheet::escape(i.key()) << "\">"
+        << QStyleSheet::escape(i.data()->tagName())
+        << "</istring>" << endl;
+  }
+  for (KstVectorMap::Iterator i = _outputVectors.begin(); i != _outputVectors.end(); ++i) {
+    ts << l2 << "<ovector name=\"" << QStyleSheet::escape(i.key());
+    if (i.data()->isScalarList()) {
+      ts << "\" scalarList=\"1";
+    }
+    ts << "\">" << QStyleSheet::escape(i.data()->tagName())
+        << "</ovector>" << endl;
+  }
+  for (KstScalarMap::Iterator i = _outputScalars.begin(); i != _outputScalars.end(); ++i) {
+    ts << l2 << "<oscalar name=\"" << QStyleSheet::escape(i.key()) << "\">"
+        << QStyleSheet::escape(i.data()->tagName())
+        << "</oscalar>" << endl;
+  }
+  for (KstStringMap::Iterator i = _outputStrings.begin(); i != _outputStrings.end(); ++i) {
+    ts << l2 << "<ostring name=\"" << QStyleSheet::escape(i.key()) << "\">"
+        << QStyleSheet::escape(i.data()->tagName())
+        << "</ostring>" << endl;
+  }
+  ts << indent << "</plugin>" << endl;
+}
+
 #include "crosspowerspectrum.moc"
--- branches/work/kst/pluginify/kst/src/plugins/crossspectrum/crosspowerspectrum.h #584406:584407
@@ -23,16 +23,36 @@
   Q_OBJECT
 public:
 
-    CrossPowerSpectrum(QObject *parent, const char *name, const QStringList &args);
-    virtual ~CrossPowerSpectrum();
+  CrossPowerSpectrum(QObject *parent, const char *name, const QStringList &args);
+  virtual ~CrossPowerSpectrum();
 
-    virtual KstObject::UpdateType update(int);
-    virtual QString propertyString() const;
-    virtual KstDataObjectPtr makeDuplicate(KstDataObjectDataObjectMap&);
+  //algorithm
+  void crossspectrum();
 
-protected slots:
+  KstVectorPtr v1() const;
+  KstVectorPtr v2() const;
+  KstScalarPtr fft() const;
+  KstScalarPtr sample() const;
+  KstVectorPtr real() const;
+  KstVectorPtr imaginary() const;
+  KstVectorPtr frequency() const;
+
+  //Pure virtual methods from KstDataObject
+  virtual KstObject::UpdateType update(int updateCounter = -1);
+  virtual QString propertyString() const;
+  virtual KstDataObjectPtr makeDuplicate(KstDataObjectDataObjectMap&);
+
+  //Regular virtual methods from KstDataObject
+  virtual void load(const QDomElement &e);
+  virtual void save(QTextStream& ts, const QString& indent = QString::null);
+
+  protected slots:
+  //Pure virtual slots from KstDataObject
   virtual void showNewDialog();
   virtual void showEditDialog();
 };
 
+typedef KstSharedPtr<CrossPowerSpectrum> CrossPowerSpectrumPtr;
+typedef KstObjectList<CrossPowerSpectrumPtr> CrossPowerSpectrumList;
+
 #endif


More information about the Kst mailing list