Hello again!
I build the project:
bode.pro
################################################################
# Qwt Widget Library
# Copyright (C) 1997 Josef Wilgen
# Copyright (C) 2002 Uwe Rathmann
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the Qwt License, Version 1.0
################################################################
TARGET = bode
HEADERS = \
mainwindow.h \
plot.h \
complexnumber.h \
pixmaps.h
SOURCES = \
plot.cpp \
mainwindow.cpp \
main.cpp
QWT_LOCATION = c:/Qwt-6.0.2
INCLUDEPATH += $${QWT_LOCATION}/include
LIBS = -L$${QWT_LOCATION}/lib \
-lqwt
if(!debug_and_release|build_pass):CONFIG(debug, debug|release) {
win32:LIBS = $$member(LIBS, 0) \
$$member(LIBS, 1)d
}
################################################################
# Qwt Widget Library
# Copyright (C) 1997 Josef Wilgen
# Copyright (C) 2002 Uwe Rathmann
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the Qwt License, Version 1.0
################################################################
TARGET = bode
HEADERS = \
mainwindow.h \
plot.h \
complexnumber.h \
pixmaps.h
SOURCES = \
plot.cpp \
mainwindow.cpp \
main.cpp
QWT_LOCATION = c:/Qwt-6.0.2
INCLUDEPATH += $${QWT_LOCATION}/include
LIBS = -L$${QWT_LOCATION}/lib \
-lqwt
if(!debug_and_release|build_pass):CONFIG(debug, debug|release) {
win32:LIBS = $$member(LIBS, 0) \
$$member(LIBS, 1)d
}
To copy to clipboard, switch view to plain text mode
main.cpp
#include <qapplication.h>
#include "mainwindow.h"
int main ( int argc, char **argv )
{
MainWindow w;
w.resize( 540, 400 );
w.show();
return a.exec();
}
#include <qapplication.h>
#include "mainwindow.h"
int main ( int argc, char **argv )
{
QApplication a( argc, argv );
MainWindow w;
w.resize( 540, 400 );
w.show();
return a.exec();
}
To copy to clipboard, switch view to plain text mode
mainwindow.h
#include <qmainwindow.h>
class Plot;
{
Q_OBJECT
public:
private Q_SLOTS:
#ifndef QT_NO_PRINTER
void print();
#endif
void exportDocument();
void enableZoomMode( bool );
private:
Plot *d_plot;
};
#include <qmainwindow.h>
class QwtPlotZoomer;
class QwtPlotPicker;
class QwtPlotPanner;
class Plot;
class QPolygon;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow( QWidget *parent = 0 );
private Q_SLOTS:
void moved( const QPoint & );
void selected( const QPolygon & );
#ifndef QT_NO_PRINTER
void print();
#endif
void exportDocument();
void enableZoomMode( bool );
private:
void showInfo( QString text = QString::null );
Plot *d_plot;
QwtPlotZoomer *d_zoomer[2];
QwtPlotPicker *d_picker;
QwtPlotPanner *d_panner;
};
To copy to clipboard, switch view to plain text mode
mainwindow.cpp
#include <qregexp.h>
#include <qtoolbar.h>
#include <qtoolbutton.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qstatusbar.h>
#include <qprinter.h>
#include <qpicture.h>
#include <qpainter.h>
#include <qfiledialog.h>
#include <qimagewriter.h>
#include <qprintdialog.h>
#include <qfileinfo.h>
#include <qwt_counter.h>
#include <qwt_picker_machine.h>
#include <qwt_plot_zoomer.h>
#include <qwt_plot_panner.h>
#include <qwt_plot_renderer.h>
#include <qwt_text.h>
#include <qwt_math.h>
#include "pixmaps.h"
#include "plot.h"
#include "mainwindow.h"
{
public:
{
// RightButton: zoom out by 1
// Ctrl+RightButton: zoom out to full size
Qt::RightButton, Qt::ControlModifier );
Qt::RightButton );
}
};
//-----------------------------------------------------------------
//
// bode.cpp -- A demo program featuring QwtPlot and QwtCounter
//
// This example demonstrates the mapping of different curves
// to different axes in a QwtPlot widget. It also shows how to
// display the cursor position and how to implement zooming.
//
//-----------------------------------------------------------------
MainWindow
::MainWindow( QWidget *parent
):{
d_plot = new Plot( this );
const int margin = 5;
d_plot->setContentsMargins( margin, margin, margin, 0 );
setContextMenuPolicy( Qt::NoContextMenu );
d_plot->canvas() );
d_zoomer
[0]->setRubberBand
( QwtPicker::RectRubberBand );
d_zoomer
[0]->setRubberBandPen
( QColor( Qt
::green ) );
d_zoomer
[0]->setTrackerMode
( QwtPicker::ActiveOnly );
d_zoomer
[0]->setTrackerPen
( QColor( Qt
::white ) );
d_plot->canvas() );
d_panner->setMouseButton( Qt::MidButton );
d_plot->canvas() );
d_picker
->setRubberBandPen
( QColor( Qt
::green ) );
d_picker
->setRubberBand
( QwtPicker::CrossRubberBand );
d_picker
->setTrackerPen
( QColor( Qt
::white ) );
setCentralWidget( d_plot );
btnZoom->setText( "Zoom" );
btnZoom
->setIcon
( QPixmap( zoom_xpm
) );
btnZoom->setCheckable( true );
btnZoom->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
toolBar->addWidget( btnZoom );
connect( btnZoom, SIGNAL( toggled( bool ) ), SLOT( enableZoomMode( bool ) ) );
#ifndef QT_NO_PRINTER
btnPrint->setText( "Print" );
btnPrint
->setIcon
( QPixmap( print_xpm
) );
btnPrint->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
toolBar->addWidget( btnPrint );
connect( btnPrint, SIGNAL( clicked() ), SLOT( print() ) );
#endif
btnExport->setText( "Export" );
btnExport
->setIcon
( QPixmap( print_xpm
) );
btnExport->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
toolBar->addWidget( btnExport );
connect( btnExport, SIGNAL( clicked() ), SLOT( exportDocument() ) );
toolBar->addSeparator();
layout->setSpacing( 0 );
layout
->addWidget
( new QWidget( hBox
),
10 );
// spacer layout
->addWidget
( new QLabel( "Damping Factor", hBox
),
0 );
layout->addSpacing( 10 );
cntDamp->setRange( 0.0, 5.0, 0.01 );
cntDamp->setValue( 0.0 );
layout->addWidget( cntDamp, 0 );
( void )toolBar->addWidget( hBox );
addToolBar( toolBar );
#ifndef QT_NO_STATUSBAR
( void )statusBar();
#endif
enableZoomMode( false );
showInfo();
connect( cntDamp, SIGNAL( valueChanged( double ) ),
d_plot, SLOT( setDamp( double ) ) );
connect( d_picker,
SIGNAL( moved
( const QPoint & ) ),
SLOT( moved
( const QPoint & ) ) );
connect( d_picker,
SIGNAL( selected
( const QPolygon & ) ),
}
#ifndef QT_NO_PRINTER
void MainWindow::print()
{
QString docName
= d_plot
->title
().
text();
if ( !docName.isEmpty() )
{
docName.
replace ( QRegExp ( QString::fromLatin1 ( "\n" ) ), tr
( " -- " ) );
printer.setDocName ( docName );
}
printer.setCreator( "Bode example" );
printer.
setOrientation( QPrinter::Landscape );
if ( dialog.exec() )
{
QwtPlotRenderer renderer;
if ( printer.
colorMode() == QPrinter::GrayScale ) {
renderer.setDiscardFlag( QwtPlotRenderer::DiscardCanvasBackground );
renderer.setLayoutFlag( QwtPlotRenderer::FrameWithScales );
}
renderer.renderTo( d_plot, printer );
}
}
#endif
void MainWindow::exportDocument()
{
#ifndef QT_NO_PRINTER
#else
#endif
#ifndef QT_NO_FILEDIALOG
const QList<QByteArray> imageFormats =
filter += "PDF Documents (*.pdf)";
#ifndef QWT_NO_SVG
filter += "SVG Documents (*.svg)";
#endif
filter += "Postscript Documents (*.ps)";
if ( imageFormats.size() > 0 )
{
for ( int i = 0; i < imageFormats.size(); i++ )
{
if ( i > 0 )
imageFilter += " ";
imageFilter += "*.";
imageFilter += imageFormats[i];
}
imageFilter += ")";
filter += imageFilter;
}
this, "Export File Name", fileName,
filter.
join( ";;" ),
NULL,
QFileDialog::DontConfirmOverwrite );
#endif
if ( !fileName.isEmpty() )
{
QwtPlotRenderer renderer;
// flags to make the document look like the widget
renderer.setDiscardFlag( QwtPlotRenderer::DiscardBackground, false );
renderer.setLayoutFlag( QwtPlotRenderer::KeepFrames, true );
renderer.
renderDocument( d_plot, fileName,
QSizeF( 300,
200 ),
85 );
}
}
void MainWindow::enableZoomMode( bool on )
{
d_panner->setEnabled( on );
d_zoomer[0]->setEnabled( on );
d_zoomer[0]->zoom( 0 );
d_zoomer[1]->setEnabled( on );
d_zoomer[1]->zoom( 0 );
d_picker->setEnabled( !on );
showInfo();
}
void MainWindow
::showInfo( QString text
) {
{
if ( d_picker->rubberBand() )
text = "Cursor Pos: Press left mouse button in plot region";
else
text = "Zoom: Press mouse button and drag";
}
#ifndef QT_NO_STATUSBAR
statusBar()->showMessage( text );
#endif
}
void MainWindow
::moved( const QPoint &pos
) {
info.sprintf( "Freq=%g, Ampl=%g, Phase=%g",
d_plot
->invTransform
( QwtPlot::xBottom, pos.
x() ),
d_plot
->invTransform
( QwtPlot::yLeft, pos.
y() ),
d_plot
->invTransform
( QwtPlot::yRight, pos.
y() ) );
showInfo( info );
}
void MainWindow
::selected( const QPolygon & ) {
showInfo();
}
#include <qregexp.h>
#include <qtoolbar.h>
#include <qtoolbutton.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qstatusbar.h>
#include <qprinter.h>
#include <qpicture.h>
#include <qpainter.h>
#include <qfiledialog.h>
#include <qimagewriter.h>
#include <qprintdialog.h>
#include <qfileinfo.h>
#include <qwt_counter.h>
#include <qwt_picker_machine.h>
#include <qwt_plot_zoomer.h>
#include <qwt_plot_panner.h>
#include <qwt_plot_renderer.h>
#include <qwt_text.h>
#include <qwt_math.h>
#include "pixmaps.h"
#include "plot.h"
#include "mainwindow.h"
class Zoomer: public QwtPlotZoomer
{
public:
Zoomer( int xAxis, int yAxis, QwtPlotCanvas *canvas ):
QwtPlotZoomer( xAxis, yAxis, canvas )
{
setTrackerMode( QwtPicker::AlwaysOff );
setRubberBand( QwtPicker::NoRubberBand );
// RightButton: zoom out by 1
// Ctrl+RightButton: zoom out to full size
setMousePattern( QwtEventPattern::MouseSelect2,
Qt::RightButton, Qt::ControlModifier );
setMousePattern( QwtEventPattern::MouseSelect3,
Qt::RightButton );
}
};
//-----------------------------------------------------------------
//
// bode.cpp -- A demo program featuring QwtPlot and QwtCounter
//
// This example demonstrates the mapping of different curves
// to different axes in a QwtPlot widget. It also shows how to
// display the cursor position and how to implement zooming.
//
//-----------------------------------------------------------------
MainWindow::MainWindow( QWidget *parent ):
QMainWindow( parent )
{
d_plot = new Plot( this );
const int margin = 5;
d_plot->setContentsMargins( margin, margin, margin, 0 );
setContextMenuPolicy( Qt::NoContextMenu );
d_zoomer[0] = new Zoomer( QwtPlot::xBottom, QwtPlot::yLeft,
d_plot->canvas() );
d_zoomer[0]->setRubberBand( QwtPicker::RectRubberBand );
d_zoomer[0]->setRubberBandPen( QColor( Qt::green ) );
d_zoomer[0]->setTrackerMode( QwtPicker::ActiveOnly );
d_zoomer[0]->setTrackerPen( QColor( Qt::white ) );
d_zoomer[1] = new Zoomer( QwtPlot::xTop, QwtPlot::yRight,
d_plot->canvas() );
d_panner = new QwtPlotPanner( d_plot->canvas() );
d_panner->setMouseButton( Qt::MidButton );
d_picker = new QwtPlotPicker( QwtPlot::xBottom, QwtPlot::yLeft,
QwtPlotPicker::CrossRubberBand, QwtPicker::AlwaysOn,
d_plot->canvas() );
d_picker->setStateMachine( new QwtPickerDragPointMachine() );
d_picker->setRubberBandPen( QColor( Qt::green ) );
d_picker->setRubberBand( QwtPicker::CrossRubberBand );
d_picker->setTrackerPen( QColor( Qt::white ) );
setCentralWidget( d_plot );
QToolBar *toolBar = new QToolBar( this );
QToolButton *btnZoom = new QToolButton( toolBar );
btnZoom->setText( "Zoom" );
btnZoom->setIcon( QPixmap( zoom_xpm ) );
btnZoom->setCheckable( true );
btnZoom->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
toolBar->addWidget( btnZoom );
connect( btnZoom, SIGNAL( toggled( bool ) ), SLOT( enableZoomMode( bool ) ) );
#ifndef QT_NO_PRINTER
QToolButton *btnPrint = new QToolButton( toolBar );
btnPrint->setText( "Print" );
btnPrint->setIcon( QPixmap( print_xpm ) );
btnPrint->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
toolBar->addWidget( btnPrint );
connect( btnPrint, SIGNAL( clicked() ), SLOT( print() ) );
#endif
QToolButton *btnExport = new QToolButton( toolBar );
btnExport->setText( "Export" );
btnExport->setIcon( QPixmap( print_xpm ) );
btnExport->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
toolBar->addWidget( btnExport );
connect( btnExport, SIGNAL( clicked() ), SLOT( exportDocument() ) );
toolBar->addSeparator();
QWidget *hBox = new QWidget( toolBar );
QHBoxLayout *layout = new QHBoxLayout( hBox );
layout->setSpacing( 0 );
layout->addWidget( new QWidget( hBox ), 10 ); // spacer
layout->addWidget( new QLabel( "Damping Factor", hBox ), 0 );
layout->addSpacing( 10 );
QwtCounter *cntDamp = new QwtCounter( hBox );
cntDamp->setRange( 0.0, 5.0, 0.01 );
cntDamp->setValue( 0.0 );
layout->addWidget( cntDamp, 0 );
( void )toolBar->addWidget( hBox );
addToolBar( toolBar );
#ifndef QT_NO_STATUSBAR
( void )statusBar();
#endif
enableZoomMode( false );
showInfo();
connect( cntDamp, SIGNAL( valueChanged( double ) ),
d_plot, SLOT( setDamp( double ) ) );
connect( d_picker, SIGNAL( moved( const QPoint & ) ),
SLOT( moved( const QPoint & ) ) );
connect( d_picker, SIGNAL( selected( const QPolygon & ) ),
SLOT( selected( const QPolygon & ) ) );
}
#ifndef QT_NO_PRINTER
void MainWindow::print()
{
QPrinter printer( QPrinter::HighResolution );
QString docName = d_plot->title().text();
if ( !docName.isEmpty() )
{
docName.replace ( QRegExp ( QString::fromLatin1 ( "\n" ) ), tr ( " -- " ) );
printer.setDocName ( docName );
}
printer.setCreator( "Bode example" );
printer.setOrientation( QPrinter::Landscape );
QPrintDialog dialog( &printer );
if ( dialog.exec() )
{
QwtPlotRenderer renderer;
if ( printer.colorMode() == QPrinter::GrayScale )
{
renderer.setDiscardFlag( QwtPlotRenderer::DiscardCanvasBackground );
renderer.setLayoutFlag( QwtPlotRenderer::FrameWithScales );
}
renderer.renderTo( d_plot, printer );
}
}
#endif
void MainWindow::exportDocument()
{
#ifndef QT_NO_PRINTER
QString fileName = "bode.pdf";
#else
QString fileName = "bode.png";
#endif
#ifndef QT_NO_FILEDIALOG
const QList<QByteArray> imageFormats =
QImageWriter::supportedImageFormats();
QStringList filter;
filter += "PDF Documents (*.pdf)";
#ifndef QWT_NO_SVG
filter += "SVG Documents (*.svg)";
#endif
filter += "Postscript Documents (*.ps)";
if ( imageFormats.size() > 0 )
{
QString imageFilter( "Images (" );
for ( int i = 0; i < imageFormats.size(); i++ )
{
if ( i > 0 )
imageFilter += " ";
imageFilter += "*.";
imageFilter += imageFormats[i];
}
imageFilter += ")";
filter += imageFilter;
}
fileName = QFileDialog::getSaveFileName(
this, "Export File Name", fileName,
filter.join( ";;" ), NULL, QFileDialog::DontConfirmOverwrite );
#endif
if ( !fileName.isEmpty() )
{
QwtPlotRenderer renderer;
// flags to make the document look like the widget
renderer.setDiscardFlag( QwtPlotRenderer::DiscardBackground, false );
renderer.setLayoutFlag( QwtPlotRenderer::KeepFrames, true );
renderer.renderDocument( d_plot, fileName, QSizeF( 300, 200 ), 85 );
}
}
void MainWindow::enableZoomMode( bool on )
{
d_panner->setEnabled( on );
d_zoomer[0]->setEnabled( on );
d_zoomer[0]->zoom( 0 );
d_zoomer[1]->setEnabled( on );
d_zoomer[1]->zoom( 0 );
d_picker->setEnabled( !on );
showInfo();
}
void MainWindow::showInfo( QString text )
{
if ( text == QString::null )
{
if ( d_picker->rubberBand() )
text = "Cursor Pos: Press left mouse button in plot region";
else
text = "Zoom: Press mouse button and drag";
}
#ifndef QT_NO_STATUSBAR
statusBar()->showMessage( text );
#endif
}
void MainWindow::moved( const QPoint &pos )
{
QString info;
info.sprintf( "Freq=%g, Ampl=%g, Phase=%g",
d_plot->invTransform( QwtPlot::xBottom, pos.x() ),
d_plot->invTransform( QwtPlot::yLeft, pos.y() ),
d_plot->invTransform( QwtPlot::yRight, pos.y() )
);
showInfo( info );
}
void MainWindow::selected( const QPolygon & )
{
showInfo();
}
To copy to clipboard, switch view to plain text mode
plot.h
#ifndef _PLOT_H_
#define _PLOT_H_
#include <qwt_plot.h>
{
Q_OBJECT
public:
public Q_SLOTS:
void setDamp( double damping );
private:
void showData( const double *frequency, const double *amplitude,
const double *phase, int count );
void showPeak( double freq, double amplitude );
void show3dB( double freq );
};
#endif
#ifndef _PLOT_H_
#define _PLOT_H_
#include <qwt_plot.h>
class QwtPlotCurve;
class QwtPlotMarker;
class Plot: public QwtPlot
{
Q_OBJECT
public:
Plot( QWidget *parent );
public Q_SLOTS:
void setDamp( double damping );
private:
void showData( const double *frequency, const double *amplitude,
const double *phase, int count );
void showPeak( double freq, double amplitude );
void show3dB( double freq );
QwtPlotCurve *d_curve1;
QwtPlotCurve *d_curve2;
QwtPlotMarker *d_marker1;
QwtPlotMarker *d_marker2;
};
#endif
To copy to clipboard, switch view to plain text mode
plot.cpp
#include <qwt_math.h>
#include <qwt_scale_engine.h>
#include <qwt_symbol.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_marker.h>
#include <qwt_plot_curve.h>
#include <qwt_legend.h>
#include <qwt_text.h>
#include <qmath.h>
#include "complexnumber.h"
#include "plot.h"
#if QT_VERSION < 0x040601
#define qExp(x) ::exp(x)
#define qAtan2(y, x) ::atan2(y, x)
#endif
static void logSpace( double *array, int size, double xmin, double xmax )
{
if ( ( xmin <= 0.0 ) || ( xmax <= 0.0 ) || ( size <= 0 ) )
return;
const int imax = size - 1;
array[0] = xmin;
array[imax] = xmax;
const double lxmin = log( xmin );
const double lxmax = log( xmax );
const double lstep = ( lxmax - lxmin ) / double( imax );
for ( int i = 1; i < imax; i++ )
array[i] = qExp( lxmin + double( i ) * lstep );
}
{
setAutoReplot( false );
setTitle( "Frequency Response of a Second-Order System" );
setCanvasBackground
( QColor( Qt
::darkBlue ) );
// legend
insertLegend
( legend,
QwtPlot::BottomLegend );
// grid
grid->enableXMin( true );
grid
->setMajPen
( QPen( Qt
::white,
0, Qt
::DotLine ) );
grid
->setMinPen
( QPen( Qt
::gray,
0 , Qt
::DotLine ) );
grid->attach( this );
// axes
setAxisTitle
( QwtPlot::xBottom,
"Normalized Frequency" );
setAxisTitle
( QwtPlot::yLeft,
"Amplitude [dB]" );
setAxisTitle
( QwtPlot::yRight,
"Phase [deg]" );
setAxisMaxMajor
( QwtPlot::xBottom,
6 );
setAxisMaxMinor
( QwtPlot::xBottom,
10 );
// curves
d_curve1
->setRenderHint
( QwtPlotItem::RenderAntialiased );
d_curve1
->setPen
( QPen( Qt
::yellow ) );
d_curve1
->setLegendAttribute
( QwtPlotCurve::LegendShowLine );
d_curve1
->setYAxis
( QwtPlot::yLeft );
d_curve1->attach( this );
d_curve2
->setRenderHint
( QwtPlotItem::RenderAntialiased );
d_curve2
->setPen
( QPen( Qt
::cyan ) );
d_curve2
->setLegendAttribute
( QwtPlotCurve::LegendShowLine );
d_curve2
->setYAxis
( QwtPlot::yRight );
d_curve2->attach( this );
// marker
d_marker1->setValue( 0.0, 0.0 );
d_marker1->setLabelAlignment( Qt::AlignRight | Qt::AlignBottom );
d_marker1
->setLinePen
( QPen( Qt
::green,
0, Qt
::DashDotLine ) );
d_marker1->attach( this );
d_marker2->setLabelAlignment( Qt::AlignRight | Qt::AlignBottom );
d_marker2
->setLinePen
( QPen( QColor( 200,
150,
0 ),
0, Qt
::DashDotLine ) );
d_marker2->attach( this );
setDamp( 0.0 );
setAutoReplot( true );
}
void Plot::showData( const double *frequency, const double *amplitude,
const double *phase, int count )
{
d_curve1->setSamples( frequency, amplitude, count );
d_curve2->setSamples( frequency, phase, count );
}
void Plot::showPeak( double freq, double amplitude )
{
label.sprintf( "Peak: %.3g dB", amplitude );
text.
setFont( QFont( "Helvetica",
10,
QFont::Bold ) );
text.
setColor( QColor( 200,
150,
0 ) );
d_marker2->setValue( freq, amplitude );
d_marker2->setLabel( text );
}
void Plot::show3dB( double freq )
{
label.sprintf( "-3 dB at f = %.3g", freq );
text.
setFont( QFont( "Helvetica",
10,
QFont::Bold ) );
text.setColor( Qt::green );
d_marker1->setValue( freq, 0.0 );
d_marker1->setLabel( text );
}
//
// re-calculate frequency response
//
void Plot::setDamp( double damping )
{
const bool doReplot = autoReplot();
setAutoReplot( false );
const int ArraySize = 200;
double frequency[ArraySize];
double amplitude[ArraySize];
double phase[ArraySize];
// build frequency vector with logarithmic division
logSpace( frequency, ArraySize, 0.01, 100 );
int i3 = 1;
double fmax = 1;
double amax = -1000.0;
for ( int i = 0; i < ArraySize; i++ )
{
double f = frequency[i];
const ComplexNumber g =
ComplexNumber( 1.0 ) / ComplexNumber( 1.0 - f * f, 2.0 * damping * f );
amplitude[i] = 20.0 * log10( qSqrt( g.real() * g.real() + g.imag() * g.imag() ) );
phase[i] = qAtan2( g.imag(), g.real() ) * ( 180.0 / M_PI );
if ( ( i3 <= 1 ) && ( amplitude[i] < -3.0 ) )
i3 = i;
if ( amplitude[i] > amax )
{
amax = amplitude[i];
fmax = frequency[i];
}
}
double f3 = frequency[i3] - ( frequency[i3] - frequency[i3 - 1] )
/ ( amplitude[i3] - amplitude[i3 -1] ) * ( amplitude[i3] + 3 );
showPeak( fmax, amax );
show3dB( f3 );
showData( frequency, amplitude, phase, ArraySize );
setAutoReplot( doReplot );
replot();
}
#include <qwt_math.h>
#include <qwt_scale_engine.h>
#include <qwt_symbol.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_marker.h>
#include <qwt_plot_curve.h>
#include <qwt_legend.h>
#include <qwt_text.h>
#include <qmath.h>
#include "complexnumber.h"
#include "plot.h"
#if QT_VERSION < 0x040601
#define qExp(x) ::exp(x)
#define qAtan2(y, x) ::atan2(y, x)
#endif
static void logSpace( double *array, int size, double xmin, double xmax )
{
if ( ( xmin <= 0.0 ) || ( xmax <= 0.0 ) || ( size <= 0 ) )
return;
const int imax = size - 1;
array[0] = xmin;
array[imax] = xmax;
const double lxmin = log( xmin );
const double lxmax = log( xmax );
const double lstep = ( lxmax - lxmin ) / double( imax );
for ( int i = 1; i < imax; i++ )
array[i] = qExp( lxmin + double( i ) * lstep );
}
Plot::Plot( QWidget *parent ):
QwtPlot( parent )
{
setAutoReplot( false );
setTitle( "Frequency Response of a Second-Order System" );
setCanvasBackground( QColor( Qt::darkBlue ) );
// legend
QwtLegend *legend = new QwtLegend;
insertLegend( legend, QwtPlot::BottomLegend );
// grid
QwtPlotGrid *grid = new QwtPlotGrid;
grid->enableXMin( true );
grid->setMajPen( QPen( Qt::white, 0, Qt::DotLine ) );
grid->setMinPen( QPen( Qt::gray, 0 , Qt::DotLine ) );
grid->attach( this );
// axes
enableAxis( QwtPlot::yRight );
setAxisTitle( QwtPlot::xBottom, "Normalized Frequency" );
setAxisTitle( QwtPlot::yLeft, "Amplitude [dB]" );
setAxisTitle( QwtPlot::yRight, "Phase [deg]" );
setAxisMaxMajor( QwtPlot::xBottom, 6 );
setAxisMaxMinor( QwtPlot::xBottom, 10 );
setAxisScaleEngine( QwtPlot::xBottom, new QwtLog10ScaleEngine );
// curves
d_curve1 = new QwtPlotCurve( "Amplitude" );
d_curve1->setRenderHint( QwtPlotItem::RenderAntialiased );
d_curve1->setPen( QPen( Qt::yellow ) );
d_curve1->setLegendAttribute( QwtPlotCurve::LegendShowLine );
d_curve1->setYAxis( QwtPlot::yLeft );
d_curve1->attach( this );
d_curve2 = new QwtPlotCurve( "Phase" );
d_curve2->setRenderHint( QwtPlotItem::RenderAntialiased );
d_curve2->setPen( QPen( Qt::cyan ) );
d_curve2->setLegendAttribute( QwtPlotCurve::LegendShowLine );
d_curve2->setYAxis( QwtPlot::yRight );
d_curve2->attach( this );
// marker
d_marker1 = new QwtPlotMarker();
d_marker1->setValue( 0.0, 0.0 );
d_marker1->setLineStyle( QwtPlotMarker::VLine );
d_marker1->setLabelAlignment( Qt::AlignRight | Qt::AlignBottom );
d_marker1->setLinePen( QPen( Qt::green, 0, Qt::DashDotLine ) );
d_marker1->attach( this );
d_marker2 = new QwtPlotMarker();
d_marker2->setLineStyle( QwtPlotMarker::HLine );
d_marker2->setLabelAlignment( Qt::AlignRight | Qt::AlignBottom );
d_marker2->setLinePen( QPen( QColor( 200, 150, 0 ), 0, Qt::DashDotLine ) );
d_marker2->setSymbol( new QwtSymbol( QwtSymbol::Diamond,
QColor( Qt::yellow ), QColor( Qt::green ), QSize( 7, 7 ) ) );
d_marker2->attach( this );
setDamp( 0.0 );
setAutoReplot( true );
}
void Plot::showData( const double *frequency, const double *amplitude,
const double *phase, int count )
{
d_curve1->setSamples( frequency, amplitude, count );
d_curve2->setSamples( frequency, phase, count );
}
void Plot::showPeak( double freq, double amplitude )
{
QString label;
label.sprintf( "Peak: %.3g dB", amplitude );
QwtText text( label );
text.setFont( QFont( "Helvetica", 10, QFont::Bold ) );
text.setColor( QColor( 200, 150, 0 ) );
d_marker2->setValue( freq, amplitude );
d_marker2->setLabel( text );
}
void Plot::show3dB( double freq )
{
QString label;
label.sprintf( "-3 dB at f = %.3g", freq );
QwtText text( label );
text.setFont( QFont( "Helvetica", 10, QFont::Bold ) );
text.setColor( Qt::green );
d_marker1->setValue( freq, 0.0 );
d_marker1->setLabel( text );
}
//
// re-calculate frequency response
//
void Plot::setDamp( double damping )
{
const bool doReplot = autoReplot();
setAutoReplot( false );
const int ArraySize = 200;
double frequency[ArraySize];
double amplitude[ArraySize];
double phase[ArraySize];
// build frequency vector with logarithmic division
logSpace( frequency, ArraySize, 0.01, 100 );
int i3 = 1;
double fmax = 1;
double amax = -1000.0;
for ( int i = 0; i < ArraySize; i++ )
{
double f = frequency[i];
const ComplexNumber g =
ComplexNumber( 1.0 ) / ComplexNumber( 1.0 - f * f, 2.0 * damping * f );
amplitude[i] = 20.0 * log10( qSqrt( g.real() * g.real() + g.imag() * g.imag() ) );
phase[i] = qAtan2( g.imag(), g.real() ) * ( 180.0 / M_PI );
if ( ( i3 <= 1 ) && ( amplitude[i] < -3.0 ) )
i3 = i;
if ( amplitude[i] > amax )
{
amax = amplitude[i];
fmax = frequency[i];
}
}
double f3 = frequency[i3] - ( frequency[i3] - frequency[i3 - 1] )
/ ( amplitude[i3] - amplitude[i3 -1] ) * ( amplitude[i3] + 3 );
showPeak( fmax, amax );
show3dB( f3 );
showData( frequency, amplitude, phase, ArraySize );
setAutoReplot( doReplot );
replot();
}
To copy to clipboard, switch view to plain text mode
pixmaps.h
#ifndef PIXMAPS_H
#define PIXMAPS_H
static const char *print_xpm[] =
{
"32 32 12 1",
"a c #ffffff",
"h c #ffff00",
"c c #ffffff",
"f c #dcdcdc",
"b c #c0c0c0",
"j c #a0a0a4",
"e c #808080",
"g c #808000",
"d c #585858",
"i c #00ff00",
"# c #000000",
". c None",
"................................",
"................................",
"...........###..................",
"..........#abb###...............",
".........#aabbbbb###............",
".........#ddaaabbbbb###.........",
"........#ddddddaaabbbbb###......",
".......#deffddddddaaabbbbb###...",
"......#deaaabbbddddddaaabbbbb###",
".....#deaaaaaaabbbddddddaaabbbb#",
"....#deaaabbbaaaa#ddedddfggaaad#",
"...#deaaaaaaaaaa#ddeeeeafgggfdd#",
"..#deaaabbbaaaa#ddeeeeabbbbgfdd#",
".#deeefaaaaaaa#ddeeeeabbhhbbadd#",
"#aabbbeeefaaa#ddeeeeabbbbbbaddd#",
"#bbaaabbbeee#ddeeeeabbiibbadddd#",
"#bbbbbaaabbbeeeeeeabbbbbbaddddd#",
"#bjbbbbbbaaabbbbeabbbbbbadddddd#",
"#bjjjjbbbbbbaaaeabbbbbbaddddddd#",
"#bjaaajjjbbbbbbaaabbbbadddddddd#",
"#bbbbbaaajjjbbbbbbaaaaddddddddd#",
"#bjbbbbbbaaajjjbbbbbbddddddddd#.",
"#bjjjjbbbbbbaaajjjbbbdddddddd#..",
"#bjaaajjjbbbbbbjaajjbddddddd#...",
"#bbbbbaaajjjbbbjbbaabdddddd#....",
"###bbbbbbaaajjjjbbbbbddddd#.....",
"...###bbbbbbaaajbbbbbdddd#......",
"......###bbbbbbjbbbbbddd#.......",
".........###bbbbbbbbbdd#........",
"............###bbbbbbd#.........",
"...............###bbb#..........",
"..................###..........."
};
static const char *zoom_xpm[] =
{
"32 32 8 1",
"# c #000000",
"b c #c0c0c0",
"a c #ffffff",
"e c #585858",
"d c #a0a0a4",
"c c #0000ff",
"f c #00ffff",
". c None",
"..######################........",
".#a#baaaaaaaaaaaaaaaaaa#........",
"#aa#baaaaaaaaaaaaaccaca#........",
"####baaaaaaaaaaaaaaaaca####.....",
"#bbbbaaaaaaaaaaaacccaaa#da#.....",
"#aaaaaaaaaaaaaaaacccaca#da#.....",
"#aaaaaaaaaaaaaaaaaccaca#da#.....",
"#aaaaaaaaaabe###ebaaaaa#da#.....",
"#aaaaaaaaa#########aaaa#da#.....",
"#aaaaaaaa###dbbbb###aaa#da#.....",
"#aaaaaaa###aaaaffb###aa#da#.....",
"#aaaaaab##aaccaaafb##ba#da#.....",
"#aaaaaae#daaccaccaad#ea#da#.....",
"#aaaaaa##aaaaaaccaab##a#da#.....",
"#aaaaaa##aacccaaaaab##a#da#.....",
"#aaaaaa##aaccccaccab##a#da#.....",
"#aaaaaae#daccccaccad#ea#da#.....",
"#aaaaaab##aacccaaaa##da#da#.....",
"#aaccacd###aaaaaaa###da#da#.....",
"#aaaaacad###daaad#####a#da#.....",
"#acccaaaad##########da##da#.....",
"#acccacaaadde###edd#eda#da#.....",
"#aaccacaaaabdddddbdd#eda#a#.....",
"#aaaaaaaaaaaaaaaaaadd#eda##.....",
"#aaaaaaaaaaaaaaaaaaadd#eda#.....",
"#aaaaaaaccacaaaaaaaaadd#eda#....",
"#aaaaaaaaaacaaaaaaaaaad##eda#...",
"#aaaaaacccaaaaaaaaaaaaa#d#eda#..",
"########################dd#eda#.",
"...#dddddddddddddddddddddd##eda#",
"...#aaaaaaaaaaaaaaaaaaaaaa#.####",
"...########################..##."
};
#endif
#ifndef PIXMAPS_H
#define PIXMAPS_H
static const char *print_xpm[] =
{
"32 32 12 1",
"a c #ffffff",
"h c #ffff00",
"c c #ffffff",
"f c #dcdcdc",
"b c #c0c0c0",
"j c #a0a0a4",
"e c #808080",
"g c #808000",
"d c #585858",
"i c #00ff00",
"# c #000000",
". c None",
"................................",
"................................",
"...........###..................",
"..........#abb###...............",
".........#aabbbbb###............",
".........#ddaaabbbbb###.........",
"........#ddddddaaabbbbb###......",
".......#deffddddddaaabbbbb###...",
"......#deaaabbbddddddaaabbbbb###",
".....#deaaaaaaabbbddddddaaabbbb#",
"....#deaaabbbaaaa#ddedddfggaaad#",
"...#deaaaaaaaaaa#ddeeeeafgggfdd#",
"..#deaaabbbaaaa#ddeeeeabbbbgfdd#",
".#deeefaaaaaaa#ddeeeeabbhhbbadd#",
"#aabbbeeefaaa#ddeeeeabbbbbbaddd#",
"#bbaaabbbeee#ddeeeeabbiibbadddd#",
"#bbbbbaaabbbeeeeeeabbbbbbaddddd#",
"#bjbbbbbbaaabbbbeabbbbbbadddddd#",
"#bjjjjbbbbbbaaaeabbbbbbaddddddd#",
"#bjaaajjjbbbbbbaaabbbbadddddddd#",
"#bbbbbaaajjjbbbbbbaaaaddddddddd#",
"#bjbbbbbbaaajjjbbbbbbddddddddd#.",
"#bjjjjbbbbbbaaajjjbbbdddddddd#..",
"#bjaaajjjbbbbbbjaajjbddddddd#...",
"#bbbbbaaajjjbbbjbbaabdddddd#....",
"###bbbbbbaaajjjjbbbbbddddd#.....",
"...###bbbbbbaaajbbbbbdddd#......",
"......###bbbbbbjbbbbbddd#.......",
".........###bbbbbbbbbdd#........",
"............###bbbbbbd#.........",
"...............###bbb#..........",
"..................###..........."
};
static const char *zoom_xpm[] =
{
"32 32 8 1",
"# c #000000",
"b c #c0c0c0",
"a c #ffffff",
"e c #585858",
"d c #a0a0a4",
"c c #0000ff",
"f c #00ffff",
". c None",
"..######################........",
".#a#baaaaaaaaaaaaaaaaaa#........",
"#aa#baaaaaaaaaaaaaccaca#........",
"####baaaaaaaaaaaaaaaaca####.....",
"#bbbbaaaaaaaaaaaacccaaa#da#.....",
"#aaaaaaaaaaaaaaaacccaca#da#.....",
"#aaaaaaaaaaaaaaaaaccaca#da#.....",
"#aaaaaaaaaabe###ebaaaaa#da#.....",
"#aaaaaaaaa#########aaaa#da#.....",
"#aaaaaaaa###dbbbb###aaa#da#.....",
"#aaaaaaa###aaaaffb###aa#da#.....",
"#aaaaaab##aaccaaafb##ba#da#.....",
"#aaaaaae#daaccaccaad#ea#da#.....",
"#aaaaaa##aaaaaaccaab##a#da#.....",
"#aaaaaa##aacccaaaaab##a#da#.....",
"#aaaaaa##aaccccaccab##a#da#.....",
"#aaaaaae#daccccaccad#ea#da#.....",
"#aaaaaab##aacccaaaa##da#da#.....",
"#aaccacd###aaaaaaa###da#da#.....",
"#aaaaacad###daaad#####a#da#.....",
"#acccaaaad##########da##da#.....",
"#acccacaaadde###edd#eda#da#.....",
"#aaccacaaaabdddddbdd#eda#a#.....",
"#aaaaaaaaaaaaaaaaaadd#eda##.....",
"#aaaaaaaaaaaaaaaaaaadd#eda#.....",
"#aaaaaaaccacaaaaaaaaadd#eda#....",
"#aaaaaaaaaacaaaaaaaaaad##eda#...",
"#aaaaaacccaaaaaaaaaaaaa#d#eda#..",
"########################dd#eda#.",
"...#dddddddddddddddddddddd##eda#",
"...#aaaaaaaaaaaaaaaaaaaaaa#.####",
"...########################..##."
};
#endif
To copy to clipboard, switch view to plain text mode
But I get:
38.png
Added after 11 minutes:
Solution:
in bode.pro
include( $${PWD}/../examples.pri )
include( $${PWD}/../examples.pri )
To copy to clipboard, switch view to plain text mode
Bookmarks