Classes | Public Slots | Public Member Functions | Public Attributes | Static Protected Member Functions | Protected Attributes | Static Protected Attributes
DampingResults Class Reference

#include <DampingResults.h>

Inheritance diagram for DampingResults:
SciFigs::GraphicSheetMenu

List of all members.

Classes

struct  Result

Public Slots

void save (QString fileName=QString::null)

Public Member Functions

bool compute (int ig, const Signal *sig, const Parameters &param)
void createObjects (SubSignalPool *subPool)
 DampingResults (QWidget *parent=0)
void setWindowTitle (QString title)
 ~DampingResults ()

Public Attributes

QMenu * menuTools

Static Protected Member Functions

static double misfitFunk (double x[])

Protected Attributes

LineLayer ** _averageCurveLayers
TextEdit ** _comments
LineLayer ** _fitCurveLayers
QString _log
QVector< Result_results
LineLayer ** _stddevCurveLayers

Static Protected Attributes

static Curve< Point2D_aveCurve
static double _fitW = 0
static int _nSampFit = 0

Constructor & Destructor Documentation

DampingResults::DampingResults ( QWidget *  parent = 0)

References SciFigs::GraphicSheetMenu::addMenu(), menuTools, save(), QGpCoreTools::tr(), and TRACE.

                                              :
    GraphicSheetMenu(parent)
{
  TRACE;
  Settings::getSize(this, "DampingResults" );

  QAction * a;

  menuTools=addMenu(tr( "&Tools" ));

  a=new QAction(tr( "&Save results" ), this);
  a->setStatusTip(tr( "Save results of spectral analysis in a text file with process information (.log file)" ));
  connect(a, SIGNAL(triggered()), this, SLOT(save()) );
  menuTools->addAction(a);
}

References _averageCurveLayers, _comments, _fitCurveLayers, _stddevCurveLayers, and TRACE.

{
  TRACE;
  Settings::setSize(this, "DampingResults" );
  delete [] _comments;
  delete [] _averageCurveLayers;
  delete [] _stddevCurveLayers;
  delete [] _fitCurveLayers;
}

Member Function Documentation

bool DampingResults::compute ( int  ig,
const Signal sig,
const Parameters param 
)

References _aveCurve, _averageCurveLayers, _comments, _fitCurveLayers, _fitW, _log, _nSampFit, _results, _stddevCurveLayers, GeopsyCore::TimeRangeParameters::absoluteRange(), SciFigs::LineLayer::addLine(), QGpCoreTools::amoeba(), QGpCoreTools::Curve< pointType >::at(), SciFigs::GraphContent::boundingRect(), SciFigs::LineLayer::clear(), QGpCoreTools::Curve< pointType >::clear(), CONST_LOCK_SAMPLES, GeopsyCore::DoubleSignal::copySamplesFrom(), SciFigs::AxisWindow::deepUpdate(), GeopsyCore::DoubleSignal::deltaT(), GeopsyCore::TimeRange::end(), QGpCoreTools::endl(), QGpCoreTools::exp(), Parameters::filter(), GeopsyCore::DoubleSignal::filter(), Parameters::fitLength(), SciFigs::GraphContent::graph(), SciFigs::GraphContentLayer::graphContent(), GeopsyCore::SignalTemplate< sampleType >::initValues(), Parameters::isFilter(), GeopsyCore::TimeRange::lengthSeconds(), misfitFunk(), MSG_ID, GeopsyCore::Signal::nameComponent(), QGpCoreTools::Curve< pointType >::resize(), GeopsyCore::DoubleSignal::restoreType(), GeopsyCore::DoubleSignal::saveType(), GeopsyCore::DoubleSignal::setDeltaT(), SciFigs::Axis::setRange(), SciFigs::TextEdit::setText(), QGpCoreTools::sin(), QGpCoreTools::sqrt(), GeopsyCore::TimeRange::start(), GeopsyCore::DoubleSignal::subtractValue(), GeopsyCore::Signal::t0(), Parameters::timeRange(), Parameters::toString(), QGpCoreTools::tr(), TRACE, UNLOCK_SAMPLES, SciFigs::TextEdit::update(), w, Parameters::windowLength(), QGpCoreTools::Point2D::x(), QGpCoreTools::Rect::x1(), QGpCoreTools::Rect::x2(), SciFigs::AxisWindow::xAxis(), QGpCoreTools::Point2D::y(), QGpCoreTools::Rect::y1(), QGpCoreTools::Rect::y2(), and SciFigs::AxisWindow::yAxis().

{
  TRACE;
  _log=param.toString();
  _averageCurveLayers[ig]->clear();
  _stddevCurveLayers[ig]->clear();
  _fitCurveLayers[ig]->clear();
  // Cut the time window to process
  TimeRange tw=param.timeRange().absoluteRange(sig);
  double dt=sig->deltaT();
  int nSampSig=(int)round((tw.end()-tw.start())/dt);
  int nSampWin=(int)ceil(param.windowLength()/dt);
  _nSampFit=(int)ceil(param.fitLength()/dt);
  if(nSampWin>nSampSig) nSampWin=nSampSig;
  if(_nSampFit>nSampWin) {
    Message::warning(MSG_ID, tr("Damping toolbox"),
                     tr("The fitting length cannot be greater than the window length. "
                       "Continuing with a fitting length reduced to window length"), Message::ok(), true);
    _nSampFit=nSampWin;
  }
  // Get result vectors ready
  _aveCurve.clear();
  Curve<Point2D> minCurve, maxCurve, fitCurve;
  _aveCurve.resize(nSampWin);
  minCurve.resize(nSampWin);
  maxCurve.resize(nSampWin);
  fitCurve.resize(_nSampFit);
  // Set x coordinates for curves, and init y
  double t=0;
  int iw;
  for(iw=0;iw < _nSampFit;iw++, t += dt) {
    _aveCurve[iw].setX(t);
    _aveCurve[iw].setY(0);
    minCurve[iw].setX(t);
    minCurve[iw].setY(0);
    maxCurve[iw].setX(t);
    maxCurve[iw].setY(0);
    fitCurve[iw].setX(t);
    fitCurve[iw].setY(0);
  }
  for( ;iw < nSampWin;iw++, t += dt) {
    _aveCurve[iw].setX(t);
    _aveCurve[iw].setY(0);
    minCurve[iw].setX(t);
    minCurve[iw].setY(0);
    maxCurve[iw].setX(t);
    maxCurve[iw].setY(0);
  }
  int nWin=0;
  double tau, val; // time shift relative to signal sampling

  const DoubleSignal * sigfft=sig->saveType(DoubleSignal::Waveform);
  DoubleSignal * tSig=new DoubleSignal(nSampSig);
  tSig->initValues(0.0, 0, nSampSig);
  tSig->setDeltaT(dt);
  tSig->copySamplesFrom(sigfft, tw.start()-sig->t0(), 0.0, tw.lengthSeconds());
  tSig->subtractValue();
  sig->restoreType(sigfft);
  if(param.isFilter()) {
    tSig->filter(param.filter());
  }
  CONST_LOCK_SAMPLES(double, samp, tSig)
    // Stack windows (sum for ave, sum2 for min)
    int ns=nSampSig - nSampWin - 1;
    for(int is=0;is < ns;is++ ) {
      if(samp[ is ] <= 0 && samp[ is + 1 ] >= 0) {
        nWin++;
        if(samp[ is ]==0)
          tau=0;
        else
          tau=samp[ is ]/(samp[ is ] - samp[ is + 1 ] );
        for(iw=1;iw < nSampWin;iw++ ) {
          val=samp[ is + iw ] + tau * (samp[ is + iw + 1 ] - samp[ is + iw ] );
          _aveCurve[iw].setY(_aveCurve.at(iw).y() + val);
          minCurve[iw].setY(minCurve.at(iw).y() + val * val);
        }
      }
    }
  UNLOCK_SAMPLES(tSig);
  delete tSig;
  // Compute average and std deviation
  for(iw=1;iw < nSampWin;iw++ ) {
    val=_aveCurve.at(iw).y()/(double) nWin;
    _aveCurve[iw].setY(val);
    tau=sqrt(minCurve[iw].y()/(double) nWin - val * val);
    minCurve[iw].setY(val - tau);
    maxCurve[iw].setY(val + tau);
  }
  // Fit function A/w*e^(-Zwt)*sin(wt), A, w, Z are the unknowns
  // Use the downhill simplex algorithm to find the minimum
  // Init the algorithm with good estimates. Estimate the amplitude of signal
  // average at the first absolute maximum
  double z=0.01, a=0;
  int iw0=0, nw0=0;
  int nw=_nSampFit - 1;
  for(iw=1;iw < nw;iw++ ) {
    if(_aveCurve[iw].y() < 0 && _aveCurve[iw + 1].y() > 0) {
      nw0++;
      iw0=iw;
    }
  }
  if(iw0==0) {
    Message::warning(MSG_ID, tr("Damping"), tr("For signal %1, the first maximum cannot be found. This is "
                         "likely that the specified time range contains no signal at all. Check the time "
                         "limits.").arg(sig->nameComponent()), Message::cancel()); 
    return false;
  }
  _fitW=2 * nw0 * M_PI/(iw0 * dt);
  // a=aveCurve->at(1).y/dt;
  for(iw=1;iw < _nSampFit;iw++ ) {
    if(fabs( _aveCurve.at(iw).y()) > a) {
      a=fabs(_aveCurve.at(iw).y());
      iw0=iw;
    }
  }
  a *= _fitW/exp( -z * _fitW * iw0 * dt);
  // Init an initial tetrahedron
  double * p[ 3 ], pv[ 6 ], y[ 3 ];

  p[ 0 ]=pv;
  p[ 1 ]=pv + 2;
  p[ 2 ]=pv + 4;
  //  p[0][0]=a;
  //  p[0][1]=w;
  //  p[0][2]=z;
  //  y[0]=misfitFunk(p[0]);
  //  p[1][0]=a*1.01;
  //  p[1][1]=w*1.1;
  //  p[1][2]=z*1.5;
  //  y[1]=misfitFunk(p[1]);
  //  p[2][0]=a*0.99;
  //  p[2][1]=w*0.9;
  //  p[2][2]=z*0.5;
  //  y[2]=misfitFunk(p[2]);
  //  p[3][0]=a*1.005;
  //  p[3][1]=w*1.05;
  //  p[3][2]=z*1.2;
  //  y[3]=misfitFunk(p[3]);
  //  p[0][0]=a*0.9;
  //  p[0][1]=w;
  //  p[0][2]=z*0.5;
  //  y[0]=misfitFunk(p[0]);
  //  p[1][0]=a*1.1;
  //  p[1][1]=p[0][1];
  //  p[1][2]=p[0][2];
  //  y[1]=misfitFunk(p[1]);
  //  p[2][0]=a;
  //  p[2][1]=w;
  //  p[2][2]=p[0][2];
  //  y[2]=misfitFunk(p[2]);
  //  p[3][0]=a;
  //  p[3][1]=w;
  //  p[3][2]=z*1.5;
  //  y[3]=misfitFunk(p[3]);
  p[ 0 ][ 0 ]=a * 0.9;
  p[ 0 ][ 1 ]=z * 0.9;
  y[ 0 ]=misfitFunk(p[ 0 ] );
  p[ 1 ][ 0 ]=a * 0.9;
  p[ 1 ][ 1 ]=z * 1.1;
  y[ 1 ]=misfitFunk(p[ 1 ] );
  p[ 2 ][ 0 ]=a * 1.1;
  p[ 2 ][ 1 ]=z;
  y[ 2 ]=misfitFunk(p[ 2 ] );
  int nfunk;
  amoeba(p, y, 2, 2.5e-8, misfitFunk, &nfunk);
  App::stream() << tr( "%1 function evaluations were necessary to converge").arg(nfunk) << endl;
  // Get the mean a,w and z
  a=0.25 * (p[ 0 ][ 0 ] + p[ 1 ][ 0 ] + p[ 2 ][ 0 ] );
  z=0.25 * (p[ 0 ][ 1 ] + p[ 1 ][ 1 ] + p[ 2 ][ 1 ] );
  // get the fitCurve
  for(iw=1;iw < _nSampFit;iw++ ) {
    t=fitCurve.at(iw).x();
    fitCurve[iw].setY(a/_fitW * exp( -z * _fitW * t) * sin(_fitW * t) );
  }
  // Set comments
  _comments[ ig ] ->setText(tr("f=%1 Hz\nz=%2%\nN win=%3")
                             .arg(_fitW/(2 * M_PI), 0, 'f', 2)
                             .arg(z * 100.0, 0, 'f', 4)
                             .arg(nWin));
  _comments[ ig ] ->update();
  // Add curves to graph
  static_cast<PlotLine2D *>(_averageCurveLayers[ig]->addLine())->setCurve(_aveCurve);
  static_cast<PlotLine2D *>(_stddevCurveLayers[ig]->addLine())->setCurve(minCurve);
  static_cast<PlotLine2D *>(_stddevCurveLayers[ig]->addLine())->setCurve(maxCurve);
  static_cast<PlotLine2D *>(_fitCurveLayers[ig]->addLine())->setCurve(fitCurve);
  // Set limits correctly
  GraphContent * gc=_averageCurveLayers[ig]->graphContent();
  AxisWindow * w=gc->graph();
  Rect r=gc->boundingRect();
  w->xAxis()->setRange(r.x1(), r.x2());
  double maxY=-r.y1();
  if(r.y2()>maxY) maxY=r.y2();
  maxY*=1.05;
  w->yAxis()->setRange(-maxY, maxY);
  w->deepUpdate();
  // Keep results
  _results[ig].frequency=_fitW/(2*M_PI);
  _results[ig].damping=z*100.0;
  _results[ig].nWindows=nWin;
  return true;
}

References _averageCurveLayers, _comments, _fitCurveLayers, _results, _stddevCurveLayers, SciFigs::GraphicSheetMenu::addGraph(), SciFigs::GraphicSheetMenu::addText(), GeopsyCore::SubSignalPool::at(), GeopsyCore::SubSignalPool::count(), geopsyGui, GeopsyCore::Signal::nameComponent(), SciFigs::GraphicSheetMenu::setGraphGeometry(), SciFigs::Axis::setNumberPrecision(), SciFigs::Axis::setNumberPrecisionInversedScale(), SciFigs::Axis::setNumberType(), SciFigs::AbstractLine::setPen(), SciFigs::LineLayer::setReferenceLine(), SciFigs::GraphicSheet::setStatusBar(), SciFigs::Axis::setTitle(), SciFigs::Axis::setTitleInversedScale(), SciFigs::GraphicSheetMenu::sheet(), TRACE, w, SciFigs::AxisWindow::xAxis(), and SciFigs::AxisWindow::yAxis().

{
  TRACE;
  sheet()->setStatusBar(geopsyGui->statusBar());
  double y=0.5;

  // Resize containers to fit the number of signals
  int n=subPool->count();
  _comments=new TextEdit* [n];
  _averageCurveLayers=new LineLayer* [n];
  _stddevCurveLayers=new LineLayer* [n];
  _fitCurveLayers=new LineLayer* [n];
  _results.resize(n);

  for(int ig=0; ig<n; ig++) {
    AxisWindow * w=addGraph();
    setGraphGeometry(w, 0.5, 15.0, y, 6.0);
    Signal * sig=subPool->at(ig);
    w->xAxis()->setTitle("Time (s)");
    w->xAxis()->setNumberPrecision(2);
    w->xAxis()->setTitleInversedScale("1/Time (1/s)");
    w->xAxis()->setNumberPrecisionInversedScale(2);
    w->yAxis()->setTitle(sig->nameComponent());
    w->yAxis()->setNumberType(Number::Scientific);
    w->yAxis()->setNumberPrecision(1);
    w->yAxis()->setTitleInversedScale(sig->nameComponent());
    w->yAxis()->setNumberPrecisionInversedScale(1);

    PlotLine2D * line;
    LineLayer * layer;

    layer=new LineLayer(w);
    line=new PlotLine2D;
    line->setPen(Pen(Qt::black, 0.6, Qt::SolidLine));
    layer->setReferenceLine(line);
    layer->setObjectName("average");
    _averageCurveLayers[ig]=layer;

    layer=new LineLayer(w);
    line=new PlotLine2D;
    line->setPen(Pen(Qt::black, 0.6, Qt::DotLine));
    layer->setReferenceLine(line);
    layer->setObjectName("stddev");
    _stddevCurveLayers[ig]=layer;

    layer=new LineLayer(w);
    line=new PlotLine2D;
    line->setPen(Pen(Qt::red, 0.3, Qt::SolidLine));
    layer->setReferenceLine(line);
    layer->setObjectName("fit");
    _fitCurveLayers[ig]=layer;

    _comments[ig]=addText(16, y, 4, 5.0);
    _results[ig].name=sig->nameComponent();
    y+=6.0;
  }
}
double DampingResults::misfitFunk ( double  x[]) [static, protected]

Damping sinusoide to fit to calculated data, returns a misfit Used with call back in amoeba

References _aveCurve, _nSampFit, A, QGpCoreTools::exp(), misfit(), QGpCoreTools::sin(), TRACE, w, and Z.

Referenced by compute().

{
  TRACE;
#define A x[0]
#define w _fitW
#define Z x[1]
  double misfit=0.0, t, y0;
  if(A < 0) return 1e99;
  for(int i=1;i < _nSampFit;i++ ) {
    t=_aveCurve[i].x();
    y0=_aveCurve[i].y();
    y0=y0 - A/w * exp( -Z * w * t) * sin(w * t);
    misfit += y0 * y0;
  }
  misfit /= (double) _nSampFit;
  return misfit;
}
void DampingResults::save ( QString  fileName = QString::null) [slot]

References _log, _results, QGpCoreTools::endl(), MSG_ID, QGpCoreTools::tr(), and TRACE.

Referenced by DampingResults().

{
  TRACE;
  if(fileName.isEmpty()) {
    fileName=Message::getSaveFileName(tr("Save results"), tr("Damping results (*.damping)"));
  }
  if(fileName.isEmpty()) {
    return;
  }
  QString message;
  QFileInfo fi(fileName);
  if(fi.exists()) {
     message += tr( "File %1 already exists.\n" ).arg(fi.filePath());
  }
  QDir d(fi.absolutePath());
  QFileInfo filog(d.absoluteFilePath(fi.baseName() + ".log" ));
  if(filog.exists()) {
    message += tr( "File %1 already exists.\n" ).arg(filog.filePath());
  }
  if(!message.isEmpty()) {
    if(Message::warning(MSG_ID, tr( "Saving result files" ),
                              tr( "%1\nDo you want to replace it(them)?" ).arg(message),
                              Message::no(), Message::yes(), true)==Message::Answer0) return;
  }
  // Save a log file with parameters
  QFile flog(filog.filePath());
  if( !flog.open(QIODevice::WriteOnly) ) {
    Message::warning(MSG_ID, tr( "Saving log file" ),
                          tr( "Unable to open file %1 for writing" ).arg(filog.filePath()), Message::cancel(), true);
    return;
  }
  QTextStream slog(&flog);
  slog << "### Parameters ###\n"
       << _log
       << "### End Parameters ###" << endl;
  // Save a result file with frequency, damping, number of windows
  QFile fres(fileName);
  if( !fres.open(QIODevice::WriteOnly) ) {
    Message::warning(MSG_ID, tr( "Saving result file" ),
                          tr( "Unable to open file %1 for writing" ).arg(fileName), Message::cancel(), true);
    return;
  }
  QTextStream sres(&fres);
  sres << "# Name | Frequency | Damping | Number of windows" << endl;
  for(QVector<Result>::iterator it=_results.begin();it!=_results.end(); it++) {
    sres << it->name << "\t"
         << QString::number(it->frequency) << "\t"
         << QString::number(it->damping) << "\t"
         << QString::number(it->nWindows) << endl;
  }
}
void DampingResults::setWindowTitle ( QString  title) [inline]

Member Data Documentation

Curve< Point2D > DampingResults::_aveCurve [static, protected]

Referenced by compute(), and misfitFunk().

double DampingResults::_fitW = 0 [static, protected]

Referenced by compute().

QString DampingResults::_log [protected]

Referenced by compute(), and save().

int DampingResults::_nSampFit = 0 [static, protected]

Referenced by compute(), and misfitFunk().

Referenced by compute(), createObjects(), and save().

Referenced by DampingResults().


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines