2
#include <qwt_scale_engine.h>
3
#include <qwt_symbol.h>
4
#include <qwt_plot_grid.h>
5
#include <qwt_plot_marker.h>
6
#include <qwt_plot_curve.h>
7
#include <qwt_legend.h>
10
#include "bode_plot.h"
12
static void logSpace(double *array, int size, double xmin, double xmax)
14
if ((xmin <= 0.0) || (xmax <= 0.0) || (size <= 0))
17
const int imax = size -1;
22
const double lxmin = log(xmin);
23
const double lxmax = log(xmax);
24
const double lstep = (lxmax - lxmin) / double(imax);
26
for (int i = 1; i < imax; i++)
27
array[i] = exp(lxmin + double(i) * lstep);
30
BodePlot::BodePlot(QWidget *parent):
35
setTitle("Frequency Response of a Second-Order System");
37
setCanvasBackground(QColor(Qt::darkBlue));
40
QwtLegend *legend = new QwtLegend;
41
legend->setFrameStyle(QFrame::Box|QFrame::Sunken);
42
legend->setItemMode(QwtLegend::ClickableItem);
43
insertLegend(legend, QwtPlot::BottomLegend);
46
QwtPlotGrid *grid = new QwtPlotGrid;
47
grid->enableXMin(true);
48
grid->setMajPen(QPen(Qt::white, 0, Qt::DotLine));
49
grid->setMinPen(QPen(Qt::gray, 0 , Qt::DotLine));
53
enableAxis(QwtPlot::yRight);
54
setAxisTitle(QwtPlot::xBottom, "Normalized Frequency");
55
setAxisTitle(QwtPlot::yLeft, "Amplitude [dB]");
56
setAxisTitle(QwtPlot::yRight, "Phase [deg]");
58
setAxisMaxMajor(QwtPlot::xBottom, 6);
59
setAxisMaxMinor(QwtPlot::xBottom, 10);
60
setAxisScaleEngine(QwtPlot::xBottom, new QwtLog10ScaleEngine);
63
d_crv1 = new QwtPlotCurve("Amplitude");
64
#if QT_VERSION >= 0x040000
65
d_crv1->setRenderHint(QwtPlotItem::RenderAntialiased);
67
d_crv1->setPen(QPen(Qt::yellow));
68
d_crv1->setYAxis(QwtPlot::yLeft);
71
d_crv2 = new QwtPlotCurve("Phase");
72
#if QT_VERSION >= 0x040000
73
d_crv2->setRenderHint(QwtPlotItem::RenderAntialiased);
75
d_crv2->setPen(QPen(Qt::cyan));
76
d_crv2->setYAxis(QwtPlot::yRight);
80
d_mrk1 = new QwtPlotMarker();
81
d_mrk1->setValue(0.0, 0.0);
82
d_mrk1->setLineStyle(QwtPlotMarker::VLine);
83
d_mrk1->setLabelAlignment(Qt::AlignRight | Qt::AlignBottom);
84
d_mrk1->setLinePen(QPen(Qt::green, 0, Qt::DashDotLine));
87
d_mrk2 = new QwtPlotMarker();
88
d_mrk2->setLineStyle(QwtPlotMarker::HLine);
89
d_mrk2->setLabelAlignment(Qt::AlignRight | Qt::AlignBottom);
90
d_mrk2->setLinePen(QPen(QColor(200,150,0), 0, Qt::DashDotLine));
91
d_mrk2->setSymbol( QwtSymbol(QwtSymbol::Diamond,
92
QColor(Qt::yellow), QColor(Qt::green), QSize(7,7)));
100
void BodePlot::showData(double *frequency, double *amplitude,
101
double *phase, int count)
103
d_crv1->setData(frequency, amplitude, count);
104
d_crv2->setData(frequency, phase, count);
107
void BodePlot::showPeak(double freq, double amplitude)
110
label.sprintf("Peak: %.3g dB", amplitude);
113
text.setFont(QFont("Helvetica", 10, QFont::Bold));
114
text.setColor(QColor(200,150,0));
116
d_mrk2->setValue(freq, amplitude);
117
d_mrk2->setLabel(text);
120
void BodePlot::show3dB(double freq)
123
label.sprintf("-3 dB at f = %.3g", freq);
126
text.setFont(QFont("Helvetica", 10, QFont::Bold));
127
text.setColor(Qt::green);
129
d_mrk1->setValue(freq, 0.0);
130
d_mrk1->setLabel(text);
134
// re-calculate frequency response
136
void BodePlot::setDamp(double damping)
138
const bool doReplot = autoReplot();
139
setAutoReplot(false);
141
const int ArraySize = 200;
143
double frequency[ArraySize];
144
double amplitude[ArraySize];
145
double phase[ArraySize];
147
// build frequency vector with logarithmic division
148
logSpace(frequency, ArraySize, 0.01, 100);
152
double amax = -1000.0;
154
for (int i = 0; i < ArraySize; i++)
156
double f = frequency[i];
157
cplx g = cplx(1.0) / cplx(1.0 - f * f, 2.0 * damping * f);
158
amplitude[i] = 20.0 * log10(sqrt( g.real()*g.real() + g.imag()*g.imag()));
159
phase[i] = atan2(g.imag(), g.real()) * (180.0 / M_PI);
161
if ((i3 <= 1) && (amplitude[i] < -3.0))
163
if (amplitude[i] > amax)
171
double f3 = frequency[i3] -
172
(frequency[i3] - frequency[i3 - 1])
173
/ (amplitude[i3] - amplitude[i3 -1]) * (amplitude[i3] + 3);
175
showPeak(fmax, amax);
177
showData(frequency, amplitude, phase, ArraySize);
179
setAutoReplot(doReplot);