/* -*- C++ -*- This file is part of ViPEC Copyright (C) 1991-2001 Johan Rossouw (jrossouw@alcatel.altech.co.za) This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include using namespace std; //---------------------------------------------------------------------------- GraphDefinition::GraphDefinition( GraphType viewType ) : type_( viewType ) { title_ = "Graph Title"; results_.setAutoDelete( TRUE ); } //---------------------------------------------------------------------------- GraphDefinition::~GraphDefinition() { results_.clear(); } //---------------------------------------------------------------------------- GraphDefinition::GraphType GraphDefinition::graphType() const { return type_; } //---------------------------------------------------------------------------- const QString& GraphDefinition::getName() const { return name_; } //---------------------------------------------------------------------------- void GraphDefinition::setName( const QString& name ) { name_ = name; } //---------------------------------------------------------------------------- void GraphDefinition::setTitle( const QString& title ) { title_ = title; } //---------------------------------------------------------------------------- const QString& GraphDefinition::getTitle() const { return title_; } //---------------------------------------------------------------------------- void GraphDefinition::show() { updateGraph(); getView()->show(); } //---------------------------------------------------------------------------- void GraphDefinition::reDraw() { updateGraph(); if ( getView()->isVisible() ) { getView()->reDraw(); } } //----------------------------------------------------------------- void GraphDefinition::addOutputDefinition( const ResultDefinition* definition ) { results_.append( definition ); } //----------------------------------------------------------------- void GraphDefinition::removeOutputDefinition( const ResultDefinition* definition ) { ASSERT( results_.remove( definition ) ); MainWindow::instance()->setFileChanged(); } //----------------------------------------------------------------- void GraphDefinition::fill() { getView()->emptySeries(); ResultDefinition* definition = 0; for ( definition = results_.first(); definition != 0; definition = results_.next() ) { const QString& source = definition->source(); Schematic* schematic = MainWindow::instance()->getSchematic( source ); if ( schematic == 0 ) { throw Exception::NoSuchCircuit(); } switch ( definition->type() ) { case ResultDefinition::portParameters: { QList* data = 0; switch ( definition->measurement() ) { case ResultDefinition::sParameters: data = &( schematic->getSData() ); break; case ResultDefinition::yParameters: data = &( schematic->getYData() ); break; case ResultDefinition::zParameters: data = &( schematic->getZData() ); break; case ResultDefinition::groupDelay: data = &( schematic->getSData() ); break; } addSeries( *definition, *data ); } break; case ResultDefinition::linvillStabilityFactor: case ResultDefinition::sternStabilityFactor: { QList* data = &( schematic->getYData() ); addSeries( *definition, *data ); } break; } } reDraw(); } //----------------------------------------------------------------- void GraphDefinition::addSeries( ResultDefinition& definition, QList& data ) { bool isSmith = ( graphType() == smithType ); QString legend = ResultDefinition::buildResultDefinitionStr( isSmith, definition ); uint size = data.count(); GraphView* graph = getView(); graph->addSeries( legend, size ); uint fromNode = definition.from(); uint toNode = definition.to(); TReal freqScale = Setup::instance()->getDimensionValue( Strings::FrequencyDim ); TReal timeScale = Setup::instance()->getDimensionValue( Strings::TimeDim ); const QString& source = definition.source(); Schematic* schematic = MainWindow::instance()->getSchematic( source ); DataPoint* entry = 0; TReal previousPhaseValue = 0; TReal previousFreqValue = 0; bool firstPoint = TRUE; for ( entry = data.first(); entry != 0; entry = data.next() ) { TReal freq = entry->frequency() / freqScale; Matrix& matrix = entry->data(); TComplex cvalue = matrix( toNode-1, fromNode-1 ); if ( isSmith ) { graph->addData( legend, real( cvalue ), imag( cvalue ), size ); } else { TReal rvalue = 0; switch ( definition.type() ) { case ResultDefinition::portParameters: if ( definition.measurement() == ResultDefinition::groupDelay ) { TReal currentPhase = atan2( imag( cvalue ), real( cvalue ) ); if ( firstPoint ) { previousPhaseValue = currentPhase; previousFreqValue = freq; firstPoint = FALSE; } TReal phaseDiff = currentPhase - previousPhaseValue; TReal freqDiff = (freq - previousFreqValue)*freqScale; if (phaseDiff >= 1.5*M_PI) // keep phase linear to one side ... { phaseDiff -= 2*M_PI; } if (phaseDiff <= -1.5*M_PI) // ...and to the other side { phaseDiff += 2*M_PI; } TReal tD; if ( freqDiff != 0 ) { tD = -1.0*(phaseDiff) / freqDiff; } else { tD = 0; } rvalue = tD / timeScale; previousPhaseValue = currentPhase; previousFreqValue = freq; } else { switch ( definition.format() ) { case ResultDefinition::realFormat: rvalue = real( cvalue ); break; case ResultDefinition::imagFormat: rvalue = imag( cvalue ); break; case ResultDefinition::magnitudeFormat: rvalue = abs( cvalue ); if ( definition.db() ) { rvalue = 20*log10( rvalue ); } break; case ResultDefinition::angleFormat: rvalue = atan2( imag( cvalue ), real( cvalue ) ); rvalue *= Setup::instance()->getDimensionValue( Strings::AngularDim ); break; } } break; case ResultDefinition::linvillStabilityFactor: if ( (schematic->getNumberOfPorts()) != 2 ) { throw Exception::StabilityFactorNotDefined(); } rvalue = Utils::linvill( matrix ); break; case ResultDefinition::sternStabilityFactor: if ( (schematic->getNumberOfPorts()) != 2 ) { throw Exception::StabilityFactorNotDefined(); } TComplex z1 = schematic->getPortImpedance( 0 ); TComplex z2 = schematic->getPortImpedance( 1 ); rvalue = Utils::stern( matrix, z1, z2 ); break; } graph->addData( legend, freq, rvalue, size ); } } } //----------------------------------------------------------------- void GraphDefinition::writeToStream( QTextStream& stream ) { QString tag = ""; switch ( type_ ) { case gridType: tag = "GRID"; break; case smithType: tag = "SMITH"; break; case tableType: tag = "TABLE"; break; default: ASSERT( "Unknown graph type!" == 0 ); } stream << "<" << tag << " NAME=\"" << name_ << "\" "; stream << " TITLE=\"" << title_ << "\" >" << endl; writeGraphSettingToStream( stream ); ResultDefinition* definition = 0; for ( definition = results_.first(); definition != 0; definition = results_.next() ) { definition->writeToStream( stream ); } stream << "" << endl; } //----------------------------------------------------------------- bool GraphDefinition::readFromDOM( QDomElement& element ) { readGraphSettingFromDOM( element ); QDomNode node = element.firstChild(); while( !node.isNull() ) { QDomElement childElement = node.toElement(); if( (!childElement.isNull()) && (childElement.tagName() == "OUTPUT") ) { ResultDefinition* definition = new ResultDefinition(); definition->readFromDOM( childElement ); addOutputDefinition( definition ); NavigationWindow::instance()->updateOutputDefinition( name_, *definition ); } node = node.nextSibling(); } return TRUE; }