Split contrib module into config-store and tools
This commit is contained in:
113
src/tools/model/average.h
Normal file
113
src/tools/model/average.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 IITP RAS
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Authors: Pavel Boyko <boyko@iitp.ru>
|
||||
* Corrections and extensions: Timo Bingmann <tbns@idlebox.net>
|
||||
*/
|
||||
|
||||
#ifndef AVERAGE_H
|
||||
#define AVERAGE_H
|
||||
#include <cmath>
|
||||
#include <ostream>
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/// Simple average, min, max and std. deviation calculator
|
||||
template <typename T = double>
|
||||
class Average
|
||||
{
|
||||
public:
|
||||
Average ()
|
||||
: m_size (0), m_min (std::numeric_limits<T>::max ()), m_max (0),
|
||||
m_avg (0), m_avg2 (0)
|
||||
{
|
||||
}
|
||||
|
||||
/// Add new sample
|
||||
void Update (T const & x)
|
||||
{
|
||||
m_min = std::min (x, m_min);
|
||||
m_max = std::max (x, m_max);
|
||||
m_avg = (m_size * m_avg + x) / (m_size + 1);
|
||||
m_avg2 = (m_size * m_avg2 + x * x) / (m_size + 1);
|
||||
m_size++;
|
||||
}
|
||||
/// Reset statistics
|
||||
void Reset ()
|
||||
{
|
||||
m_size = 0;
|
||||
m_min = std::numeric_limits<T>::max ();
|
||||
m_max = 0;
|
||||
m_avg = 0;
|
||||
m_avg2 = 0;
|
||||
}
|
||||
|
||||
///\name Sample statistics
|
||||
//\{
|
||||
/// Sample size
|
||||
uint32_t Count () const { return m_size; }
|
||||
/// Minimum
|
||||
T Min () const { return m_min; }
|
||||
/// Maximum
|
||||
T Max () const { return m_max; }
|
||||
/// Sample average
|
||||
double Avg () const { return m_avg; }
|
||||
/// Estimate of mean, alias to Avg
|
||||
double Mean () const { return Avg (); }
|
||||
/// Unbiased estimate of variance
|
||||
double Var () const { return Count() / (double)(Count() - 1) * (m_avg2 - m_avg*m_avg); }
|
||||
/// Standard deviation
|
||||
double Stddev () const { return sqrt (Var ());}
|
||||
//\}
|
||||
|
||||
/**
|
||||
* \name Error of the mean estimates
|
||||
*
|
||||
* Note that estimates are valid for
|
||||
* - uncorrelated measurements,
|
||||
* - normal distribution and
|
||||
* - large enough sample size.
|
||||
*/
|
||||
//\{
|
||||
/// Margin of error of the mean for 90% confidence level
|
||||
double Error90() const { return 1.645 * sqrt (Var () / Count ()); }
|
||||
/// Margin of error of the mean for 95% confidence level
|
||||
double Error95() const { return 1.960 * sqrt (Var () / Count ()); }
|
||||
/// Margin of error of the mean for 99% confidence level
|
||||
double Error99() const { return 2.576 * sqrt (Var () / Count ()); }
|
||||
//\}
|
||||
|
||||
private:
|
||||
uint32_t m_size;
|
||||
T m_min, m_max;
|
||||
double m_avg, m_avg2;
|
||||
};
|
||||
|
||||
/// Print avg (err) [min, max]
|
||||
template <typename T>
|
||||
std::ostream & operator<< (std::ostream & os, Average<T> const & x)
|
||||
{
|
||||
if (x.Count () != 0)
|
||||
os << x.Avg () << " (" << x.Stddev () << ") [" << x.Min () << ", " << x.Max () << "]";
|
||||
else
|
||||
os << "NA"; // not available
|
||||
return os;
|
||||
}
|
||||
}
|
||||
#endif /* AVERAGE_H */
|
||||
118
src/tools/model/delay-jitter-estimation.cc
Normal file
118
src/tools/model/delay-jitter-estimation.cc
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
#include "delay-jitter-estimation.h"
|
||||
#include "ns3/tag.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/string.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class DelayJitterEstimationTimestampTag : public Tag
|
||||
{
|
||||
public:
|
||||
DelayJitterEstimationTimestampTag ();
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void Serialize (TagBuffer i) const;
|
||||
virtual void Deserialize (TagBuffer i);
|
||||
virtual void Print (std::ostream &os) const;
|
||||
|
||||
Time GetTxTime (void) const;
|
||||
private:
|
||||
uint64_t m_creationTime;
|
||||
};
|
||||
|
||||
DelayJitterEstimationTimestampTag::DelayJitterEstimationTimestampTag ()
|
||||
: m_creationTime (Simulator::Now ().GetTimeStep ())
|
||||
{}
|
||||
|
||||
TypeId
|
||||
DelayJitterEstimationTimestampTag::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("anon::DelayJitterEstimationTimestampTag")
|
||||
.SetParent<Tag> ()
|
||||
.AddConstructor<DelayJitterEstimationTimestampTag> ()
|
||||
.AddAttribute ("CreationTime",
|
||||
"The time at which the timestamp was created",
|
||||
StringValue ("0.0s"),
|
||||
MakeTimeAccessor (&DelayJitterEstimationTimestampTag::GetTxTime),
|
||||
MakeTimeChecker ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
TypeId
|
||||
DelayJitterEstimationTimestampTag::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DelayJitterEstimationTimestampTag::GetSerializedSize (void) const
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
void
|
||||
DelayJitterEstimationTimestampTag::Serialize (TagBuffer i) const
|
||||
{
|
||||
i.WriteU64 (m_creationTime);
|
||||
}
|
||||
void
|
||||
DelayJitterEstimationTimestampTag::Deserialize (TagBuffer i)
|
||||
{
|
||||
m_creationTime = i.ReadU64 ();
|
||||
}
|
||||
void
|
||||
DelayJitterEstimationTimestampTag::Print (std::ostream &os) const
|
||||
{
|
||||
os << "CreationTime=" << m_creationTime;
|
||||
}
|
||||
Time
|
||||
DelayJitterEstimationTimestampTag::GetTxTime (void) const
|
||||
{
|
||||
return TimeStep (m_creationTime);
|
||||
}
|
||||
|
||||
DelayJitterEstimation::DelayJitterEstimation ()
|
||||
: m_previousRx (Simulator::Now ()),
|
||||
m_previousRxTx (Simulator::Now ()),
|
||||
m_jitter (Seconds (0.0)),
|
||||
m_delay (Seconds (0.0))
|
||||
{}
|
||||
void
|
||||
DelayJitterEstimation::PrepareTx (Ptr<const Packet> packet)
|
||||
{
|
||||
DelayJitterEstimationTimestampTag tag;
|
||||
packet->AddByteTag (tag);
|
||||
}
|
||||
void
|
||||
DelayJitterEstimation::RecordRx (Ptr<const Packet> packet)
|
||||
{
|
||||
DelayJitterEstimationTimestampTag tag;
|
||||
bool found;
|
||||
found = packet->FindFirstMatchingByteTag (tag);
|
||||
if (!found)
|
||||
{
|
||||
return;
|
||||
}
|
||||
tag.GetTxTime ();
|
||||
|
||||
Time delta = (Simulator::Now () - m_previousRx) - (tag.GetTxTime () - m_previousRxTx);
|
||||
m_jitter += (Abs (delta) - m_jitter ) / Scalar (16.0);
|
||||
m_previousRx = Simulator::Now ();
|
||||
m_previousRxTx = tag.GetTxTime ();
|
||||
m_delay = Simulator::Now () - tag.GetTxTime ();
|
||||
}
|
||||
|
||||
Time
|
||||
DelayJitterEstimation::GetLastDelay (void) const
|
||||
{
|
||||
return m_delay;
|
||||
}
|
||||
Time
|
||||
DelayJitterEstimation::GetLastJitter (void) const
|
||||
{
|
||||
return m_jitter;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
59
src/tools/model/delay-jitter-estimation.h
Normal file
59
src/tools/model/delay-jitter-estimation.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef DELAY_JITTER_ESTIMATION_H
|
||||
#define DELAY_JITTER_ESTIMATION_H
|
||||
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/packet.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief quick and dirty delay and jitter estimation
|
||||
*
|
||||
*/
|
||||
class DelayJitterEstimation
|
||||
{
|
||||
public:
|
||||
DelayJitterEstimation ();
|
||||
|
||||
/**
|
||||
* \param packet the packet to send over a wire
|
||||
*
|
||||
* This method should be invoked once on each packet to
|
||||
* record within the packet the tx time which is used upon
|
||||
* packet reception to calculate the delay and jitter. The
|
||||
* tx time is stored in the packet as an ns3::Tag which means
|
||||
* that it does not use any network resources and is not
|
||||
* taken into account in transmission delay calculations.
|
||||
*/
|
||||
static void PrepareTx (Ptr<const Packet> packet);
|
||||
/**
|
||||
* \param packet the packet received
|
||||
*
|
||||
* Invoke this method to update the delay and jitter calculations
|
||||
* After a call to this method, \ref GetLastDelay and \ref GetLastJitter
|
||||
* will return an updated delay and jitter.
|
||||
*/
|
||||
void RecordRx (Ptr<const Packet> packet);
|
||||
|
||||
/**
|
||||
* \returns the updated delay.
|
||||
*/
|
||||
Time GetLastDelay (void) const;
|
||||
/**
|
||||
* The jitter is calculated using the RFC 1889 (RTP) jitter
|
||||
* definition.
|
||||
*
|
||||
* \returns the updated jitter.
|
||||
*/
|
||||
Time GetLastJitter (void) const;
|
||||
|
||||
private:
|
||||
Time m_previousRx;
|
||||
Time m_previousRxTx;
|
||||
Time m_jitter;
|
||||
Time m_delay;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* DELAY_JITTER_ESTIMATION_H */
|
||||
155
src/tools/model/event-garbage-collector.cc
Normal file
155
src/tools/model/event-garbage-collector.cc
Normal file
@@ -0,0 +1,155 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INESC Porto
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
|
||||
*/
|
||||
#include "event-garbage-collector.h"
|
||||
|
||||
#define CLEANUP_CHUNK_MIN_SIZE 8
|
||||
#define CLEANUP_CHUNK_MAX_SIZE 128
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
EventGarbageCollector::EventGarbageCollector () :
|
||||
m_nextCleanupSize (CLEANUP_CHUNK_MIN_SIZE)
|
||||
{}
|
||||
|
||||
void
|
||||
EventGarbageCollector::Track (EventId event)
|
||||
{
|
||||
m_events.insert (event);
|
||||
if (m_events.size () >= m_nextCleanupSize)
|
||||
Cleanup ();
|
||||
}
|
||||
|
||||
void
|
||||
EventGarbageCollector::Grow ()
|
||||
{
|
||||
m_nextCleanupSize += (m_nextCleanupSize < CLEANUP_CHUNK_MAX_SIZE?
|
||||
m_nextCleanupSize : CLEANUP_CHUNK_MAX_SIZE);
|
||||
}
|
||||
|
||||
void
|
||||
EventGarbageCollector::Shrink ()
|
||||
{
|
||||
while (m_nextCleanupSize > m_events.size ())
|
||||
m_nextCleanupSize >>= 1;
|
||||
Grow ();
|
||||
}
|
||||
|
||||
// Called when a new event was added and the cleanup limit was exceeded in consequence.
|
||||
void
|
||||
EventGarbageCollector::Cleanup ()
|
||||
{
|
||||
for (EventList::iterator iter = m_events.begin (); iter != m_events.end ();)
|
||||
{
|
||||
if ((*iter).IsExpired ())
|
||||
{
|
||||
m_events.erase (iter++);
|
||||
}
|
||||
else
|
||||
break; // EventIds are sorted by timestamp => further events are not expired for sure
|
||||
}
|
||||
|
||||
// If after cleanup we are still over the limit, increase the limit.
|
||||
if (m_events.size () >= m_nextCleanupSize)
|
||||
Grow ();
|
||||
else
|
||||
Shrink ();
|
||||
}
|
||||
|
||||
|
||||
EventGarbageCollector::~EventGarbageCollector ()
|
||||
{
|
||||
for (EventList::iterator event = m_events.begin ();
|
||||
event != m_events.end (); event++)
|
||||
{
|
||||
Simulator::Cancel (*event);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
#include "ns3/test.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class EventGarbageCollectorTestCase : public TestCase
|
||||
{
|
||||
int m_counter;
|
||||
EventGarbageCollector *m_events;
|
||||
|
||||
void EventGarbageCollectorCallback ();
|
||||
|
||||
public:
|
||||
|
||||
EventGarbageCollectorTestCase ();
|
||||
virtual ~EventGarbageCollectorTestCase ();
|
||||
virtual void DoRun (void);
|
||||
};
|
||||
|
||||
EventGarbageCollectorTestCase::EventGarbageCollectorTestCase ()
|
||||
: TestCase ("EventGarbageCollector"), m_counter (0), m_events (0)
|
||||
{}
|
||||
|
||||
EventGarbageCollectorTestCase::~EventGarbageCollectorTestCase ()
|
||||
{}
|
||||
|
||||
void
|
||||
EventGarbageCollectorTestCase::EventGarbageCollectorCallback ()
|
||||
{
|
||||
m_counter++;
|
||||
if (m_counter == 50)
|
||||
{
|
||||
// this should cause the remaining (50) events to be cancelled
|
||||
delete m_events;
|
||||
m_events = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void EventGarbageCollectorTestCase::DoRun (void)
|
||||
{
|
||||
m_events = new EventGarbageCollector ();
|
||||
|
||||
for (int n = 0; n < 100; n++)
|
||||
{
|
||||
m_events->Track (Simulator::Schedule
|
||||
(Simulator::Now (),
|
||||
&EventGarbageCollectorTestCase::EventGarbageCollectorCallback,
|
||||
this));
|
||||
}
|
||||
Simulator::Run ();
|
||||
NS_TEST_EXPECT_MSG_EQ (m_events, 0, "");
|
||||
NS_TEST_EXPECT_MSG_EQ (m_counter, 50, "");
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
static class EventGarbageCollectorTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
EventGarbageCollectorTestSuite ()
|
||||
: TestSuite ("event-garbage-collector", UNIT)
|
||||
{
|
||||
AddTestCase (new EventGarbageCollectorTestCase ());
|
||||
}
|
||||
} g_eventGarbageCollectorTests;
|
||||
|
||||
}
|
||||
|
||||
71
src/tools/model/event-garbage-collector.h
Normal file
71
src/tools/model/event-garbage-collector.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INESC Porto
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
|
||||
*/
|
||||
#ifndef EVENT_GARBAGE_COLLECTOR_H
|
||||
#define EVENT_GARBAGE_COLLECTOR_H
|
||||
|
||||
#include <set>
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief An object that tracks scheduled events and automatically
|
||||
* cancels them when it is destroyed. It is useful in situations
|
||||
* where multiple instances of the same type of event can
|
||||
* simultaneously be scheduled, and when the events should be limited
|
||||
* to the lifetime of a container object.
|
||||
*/
|
||||
class EventGarbageCollector
|
||||
{
|
||||
public:
|
||||
|
||||
EventGarbageCollector ();
|
||||
|
||||
/**
|
||||
* \brief Tracks a new event
|
||||
*/
|
||||
void Track (EventId event);
|
||||
|
||||
~EventGarbageCollector ();
|
||||
|
||||
private:
|
||||
|
||||
struct EventIdLessThanTs
|
||||
{
|
||||
bool operator () (const EventId &a, const EventId &b) const
|
||||
{
|
||||
return (a.GetTs () < b.GetTs ());
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::multiset<EventId, EventIdLessThanTs> EventList;
|
||||
|
||||
EventList::size_type m_nextCleanupSize;
|
||||
EventList m_events;
|
||||
|
||||
void Cleanup ();
|
||||
void Grow ();
|
||||
void Shrink ();
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* EVENT_GARBAGE_COLLECTOR_H */
|
||||
733
src/tools/model/gnuplot.cc
Normal file
733
src/tools/model/gnuplot.cc
Normal file
@@ -0,0 +1,733 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA, 2008 Timo Bingmann
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Original Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
* Enhancements: Timo Bingmann <timo.bingmann@student.kit.edu>
|
||||
*/
|
||||
#include "gnuplot.h"
|
||||
#include "ns3/assert.h"
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
// --- GnuplotDataset::Data ------------------------------------------------ //
|
||||
|
||||
struct GnuplotDataset::Data
|
||||
{
|
||||
// *** Data Variables ***
|
||||
|
||||
unsigned int m_references;
|
||||
|
||||
std::string m_title;
|
||||
std::string m_extra;
|
||||
|
||||
/**
|
||||
* Initializes the reference counter to 1 and sets m_title and m_extra.
|
||||
*/
|
||||
Data(const std::string& title);
|
||||
|
||||
/// Required.
|
||||
virtual ~Data();
|
||||
|
||||
/**
|
||||
* Returns "plot" or "splot".
|
||||
*/
|
||||
virtual std::string GetCommand() const = 0;
|
||||
|
||||
/**
|
||||
* Prints the plot description used as argument to (s)plot. Either the
|
||||
* function expression or a datafile description. Should include m_title and
|
||||
* m_extra in the output.
|
||||
*/
|
||||
virtual void PrintExpression(std::ostream &os) const = 0;
|
||||
|
||||
/**
|
||||
* Print the inline data file contents trailing the plot command. Empty for
|
||||
* functions.
|
||||
*/
|
||||
virtual void PrintDatafile(std::ostream &os) const = 0;
|
||||
};
|
||||
|
||||
GnuplotDataset::Data::Data(const std::string& title)
|
||||
: m_references(1),
|
||||
m_title(title),
|
||||
m_extra(m_defaultExtra)
|
||||
{
|
||||
}
|
||||
|
||||
GnuplotDataset::Data::~Data()
|
||||
{
|
||||
}
|
||||
|
||||
// --- GnuplotDataset ------------------------------------------------------ //
|
||||
|
||||
std::string GnuplotDataset::m_defaultExtra = "";
|
||||
|
||||
GnuplotDataset::GnuplotDataset (struct Data* data)
|
||||
: m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
GnuplotDataset::GnuplotDataset (const GnuplotDataset& original)
|
||||
: m_data(original.m_data)
|
||||
{
|
||||
++m_data->m_references;
|
||||
}
|
||||
|
||||
GnuplotDataset::~GnuplotDataset()
|
||||
{
|
||||
if (--m_data->m_references == 0)
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
GnuplotDataset& GnuplotDataset::operator= (const GnuplotDataset& original)
|
||||
{
|
||||
if (this != &original)
|
||||
{
|
||||
if (--m_data->m_references == 0)
|
||||
delete m_data;
|
||||
|
||||
m_data = original.m_data;
|
||||
++m_data->m_references;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
GnuplotDataset::SetTitle (const std::string& title)
|
||||
{
|
||||
m_data->m_title = title;
|
||||
}
|
||||
|
||||
void
|
||||
GnuplotDataset::SetDefaultExtra (const std::string& extra)
|
||||
{
|
||||
m_defaultExtra = extra;
|
||||
}
|
||||
void
|
||||
GnuplotDataset::SetExtra (const std::string& extra)
|
||||
{
|
||||
m_data->m_extra = extra;
|
||||
}
|
||||
|
||||
// --- Gnuplot2dDataset::Data2d -------------------------------------------- //
|
||||
|
||||
struct Gnuplot2dDataset::Data2d : public GnuplotDataset::Data
|
||||
{
|
||||
// *** Data Variables ***
|
||||
|
||||
enum Style m_style;
|
||||
enum ErrorBars m_errorBars;
|
||||
|
||||
PointSet m_pointset;
|
||||
|
||||
/**
|
||||
* Initializes with the values from m_defaultStyle and m_defaultErrorBars.
|
||||
*/
|
||||
Data2d(const std::string& title);
|
||||
|
||||
virtual std::string GetCommand() const;
|
||||
virtual void PrintExpression(std::ostream &os) const;
|
||||
virtual void PrintDatafile(std::ostream &os) const;
|
||||
};
|
||||
|
||||
Gnuplot2dDataset::Data2d::Data2d(const std::string& title)
|
||||
: Data(title),
|
||||
m_style(m_defaultStyle),
|
||||
m_errorBars(m_defaultErrorBars)
|
||||
{
|
||||
}
|
||||
|
||||
std::string
|
||||
Gnuplot2dDataset::Data2d::GetCommand() const
|
||||
{
|
||||
return "plot";
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dDataset::Data2d::PrintExpression(std::ostream &os) const
|
||||
{
|
||||
os << "'-' ";
|
||||
|
||||
if (m_title.size())
|
||||
os << " title '" << m_title << "'";
|
||||
|
||||
switch (m_style) {
|
||||
case LINES:
|
||||
os << " with lines";
|
||||
break;
|
||||
case POINTS:
|
||||
switch (m_errorBars)
|
||||
{
|
||||
case NONE:
|
||||
os << " with points";
|
||||
break;
|
||||
case X:
|
||||
os << " with xerrorbars";
|
||||
break;
|
||||
case Y:
|
||||
os << " with yerrorbars";
|
||||
break;
|
||||
case XY:
|
||||
os << " with xyerrorbars";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LINES_POINTS:
|
||||
switch (m_errorBars)
|
||||
{
|
||||
case NONE:
|
||||
os << " with linespoints";
|
||||
break;
|
||||
case X:
|
||||
os << " with errorlines";
|
||||
break;
|
||||
case Y:
|
||||
os << " with yerrorlines";
|
||||
break;
|
||||
case XY:
|
||||
os << " with xyerrorlines";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DOTS:
|
||||
os << " with dots";
|
||||
break;
|
||||
case IMPULSES:
|
||||
os << " with impulses";
|
||||
break;
|
||||
case STEPS:
|
||||
os << " with steps";
|
||||
break;
|
||||
case FSTEPS:
|
||||
os << " with fsteps";
|
||||
break;
|
||||
case HISTEPS:
|
||||
os << " with histeps";
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_extra.size())
|
||||
os << " " << m_extra;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dDataset::Data2d::PrintDatafile(std::ostream &os) const
|
||||
{
|
||||
for (PointSet::const_iterator i = m_pointset.begin ();
|
||||
i != m_pointset.end (); ++i)
|
||||
{
|
||||
if (i->empty) {
|
||||
os << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (m_errorBars) {
|
||||
case NONE:
|
||||
os << i->x << " " << i->y << std::endl;
|
||||
break;
|
||||
case X:
|
||||
os << i->x << " " << i->y << " " << i->dx << std::endl;
|
||||
break;
|
||||
case Y:
|
||||
os << i->x << " " << i->y << " " << i->dy << std::endl;
|
||||
break;
|
||||
case XY:
|
||||
os << i->x << " " << i->y << " " << i->dx << " " << i->dy << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
os << "e" << std::endl;
|
||||
}
|
||||
|
||||
// --- Gnuplot2dDataset ---------------------------------------------------- //
|
||||
|
||||
enum Gnuplot2dDataset::Style Gnuplot2dDataset::m_defaultStyle = LINES;
|
||||
enum Gnuplot2dDataset::ErrorBars Gnuplot2dDataset::m_defaultErrorBars = NONE;
|
||||
|
||||
Gnuplot2dDataset::Gnuplot2dDataset (const std::string& title)
|
||||
: GnuplotDataset( new Data2d(title) )
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dDataset::SetDefaultStyle (enum Style style)
|
||||
{
|
||||
m_defaultStyle = style;
|
||||
}
|
||||
void
|
||||
Gnuplot2dDataset::SetStyle (enum Style style)
|
||||
{
|
||||
reinterpret_cast<Data2d*>(m_data)->m_style = style;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dDataset::SetDefaultErrorBars (enum ErrorBars errorBars)
|
||||
{
|
||||
m_defaultErrorBars = errorBars;
|
||||
}
|
||||
void
|
||||
Gnuplot2dDataset::SetErrorBars (enum ErrorBars errorBars)
|
||||
{
|
||||
reinterpret_cast<Data2d*>(m_data)->m_errorBars = errorBars;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dDataset::Add (double x, double y)
|
||||
{
|
||||
NS_ASSERT (reinterpret_cast<Data2d*>(m_data)->m_errorBars == NONE);
|
||||
|
||||
struct Point data;
|
||||
data.empty = false;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.dx = 0.0;
|
||||
data.dy = 0.0;
|
||||
reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dDataset::Add (double x, double y, double errorDelta)
|
||||
{
|
||||
NS_ASSERT ( reinterpret_cast<Data2d*>(m_data)->m_errorBars == X ||
|
||||
reinterpret_cast<Data2d*>(m_data)->m_errorBars == Y );
|
||||
|
||||
struct Point data;
|
||||
data.empty = false;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.dx = errorDelta;
|
||||
data.dy = errorDelta;
|
||||
reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dDataset::Add (double x, double y, double minY, double maxY)
|
||||
{
|
||||
NS_ASSERT ( reinterpret_cast<Data2d*>(m_data)->m_errorBars == X ||
|
||||
reinterpret_cast<Data2d*>(m_data)->m_errorBars == Y );
|
||||
|
||||
struct Point data;
|
||||
data.empty = false;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.dx = minY;
|
||||
data.dy = maxY;
|
||||
reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dDataset::AddEmptyLine()
|
||||
{
|
||||
struct Point data;
|
||||
data.empty = true;
|
||||
reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
|
||||
}
|
||||
|
||||
// --- Gnuplot2dFunction::Function2d --------------------------------------- //
|
||||
|
||||
struct Gnuplot2dFunction::Function2d : public GnuplotDataset::Data
|
||||
{
|
||||
// *** Data Variables ***
|
||||
|
||||
std::string m_function;
|
||||
|
||||
/**
|
||||
* Initializes with the function and title.
|
||||
*/
|
||||
Function2d(const std::string& title, const std::string& function);
|
||||
|
||||
virtual std::string GetCommand() const;
|
||||
virtual void PrintExpression(std::ostream &os) const;
|
||||
virtual void PrintDatafile(std::ostream &os) const;
|
||||
};
|
||||
|
||||
Gnuplot2dFunction::Function2d::Function2d(const std::string& title, const std::string& function)
|
||||
: Data(title),
|
||||
m_function(function)
|
||||
{
|
||||
}
|
||||
|
||||
std::string
|
||||
Gnuplot2dFunction::Function2d::GetCommand() const
|
||||
{
|
||||
return "plot";
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dFunction::Function2d::PrintExpression(std::ostream &os) const
|
||||
{
|
||||
os << m_function;
|
||||
|
||||
if (m_title.size())
|
||||
os << " title '" << m_title << "'";
|
||||
|
||||
if (m_extra.size())
|
||||
os << " " << m_extra;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dFunction::Function2d::PrintDatafile(std::ostream &os) const
|
||||
{
|
||||
}
|
||||
|
||||
// --- Gnuplot2dFunction --------------------------------------------------- //
|
||||
|
||||
Gnuplot2dFunction::Gnuplot2dFunction (const std::string& title, const std::string& function)
|
||||
: GnuplotDataset( new Function2d(title, function) )
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot2dFunction::SetFunction (const std::string& function)
|
||||
{
|
||||
reinterpret_cast<Function2d*>(m_data)->m_function = function;
|
||||
}
|
||||
|
||||
// --- Gnuplot3dDataset::Data3d -------------------------------------------- //
|
||||
|
||||
struct Gnuplot3dDataset::Data3d : public GnuplotDataset::Data
|
||||
{
|
||||
// *** Data Variables ***
|
||||
|
||||
std::string m_style;
|
||||
|
||||
PointSet m_pointset;
|
||||
|
||||
/**
|
||||
* Initializes with value from m_defaultStyle.
|
||||
*/
|
||||
Data3d(const std::string& title);
|
||||
|
||||
virtual std::string GetCommand() const;
|
||||
virtual void PrintExpression(std::ostream &os) const;
|
||||
virtual void PrintDatafile(std::ostream &os) const;
|
||||
};
|
||||
|
||||
Gnuplot3dDataset::Data3d::Data3d(const std::string& title)
|
||||
: Data(title),
|
||||
m_style(m_defaultStyle)
|
||||
{
|
||||
}
|
||||
|
||||
std::string
|
||||
Gnuplot3dDataset::Data3d::GetCommand() const
|
||||
{
|
||||
return "splot";
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot3dDataset::Data3d::PrintExpression(std::ostream &os) const
|
||||
{
|
||||
os << "'-' ";
|
||||
|
||||
if (m_style.size())
|
||||
os << " " << m_style;
|
||||
|
||||
if (m_title.size())
|
||||
os << " title '" << m_title << "'";
|
||||
|
||||
if (m_extra.size())
|
||||
os << " " << m_extra;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot3dDataset::Data3d::PrintDatafile(std::ostream &os) const
|
||||
{
|
||||
for (PointSet::const_iterator i = m_pointset.begin ();
|
||||
i != m_pointset.end (); ++i)
|
||||
{
|
||||
if (i->empty) {
|
||||
os << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
os << i->x << " " << i->y << " " << i->z << std::endl;
|
||||
}
|
||||
os << "e" << std::endl;
|
||||
}
|
||||
|
||||
// --- Gnuplot3dDataset ---------------------------------------------------- //
|
||||
|
||||
std::string Gnuplot3dDataset::m_defaultStyle = "";
|
||||
|
||||
Gnuplot3dDataset::Gnuplot3dDataset (const std::string& title)
|
||||
: GnuplotDataset( new Data3d(title) )
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot3dDataset::SetDefaultStyle (const std::string& style)
|
||||
{
|
||||
m_defaultStyle = style;
|
||||
}
|
||||
void
|
||||
Gnuplot3dDataset::SetStyle (const std::string& style)
|
||||
{
|
||||
reinterpret_cast<Data3d*>(m_data)->m_style = style;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot3dDataset::Add (double x, double y, double z)
|
||||
{
|
||||
struct Point data;
|
||||
data.empty = false;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.z = z;
|
||||
reinterpret_cast<Data3d*>(m_data)->m_pointset.push_back (data);
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot3dDataset::AddEmptyLine()
|
||||
{
|
||||
struct Point data;
|
||||
data.empty = true;
|
||||
reinterpret_cast<Data3d*>(m_data)->m_pointset.push_back (data);
|
||||
}
|
||||
|
||||
// --- Gnuplot3dFunction::Function3d --------------------------------------- //
|
||||
|
||||
struct Gnuplot3dFunction::Function3d : public GnuplotDataset::Data
|
||||
{
|
||||
// *** Data Variables ***
|
||||
|
||||
std::string m_function;
|
||||
|
||||
/**
|
||||
* Initializes with the function and title.
|
||||
*/
|
||||
Function3d(const std::string& title, const std::string& function);
|
||||
|
||||
virtual std::string GetCommand() const;
|
||||
virtual void PrintExpression(std::ostream &os) const;
|
||||
virtual void PrintDatafile(std::ostream &os) const;
|
||||
};
|
||||
|
||||
Gnuplot3dFunction::Function3d::Function3d(const std::string& title, const std::string& function)
|
||||
: Data(title),
|
||||
m_function(function)
|
||||
{
|
||||
}
|
||||
|
||||
std::string
|
||||
Gnuplot3dFunction::Function3d::GetCommand() const
|
||||
{
|
||||
return "splot";
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot3dFunction::Function3d::PrintExpression(std::ostream &os) const
|
||||
{
|
||||
os << m_function;
|
||||
|
||||
if (m_title.size())
|
||||
os << " title '" << m_title << "'";
|
||||
|
||||
if (m_extra.size())
|
||||
os << " " << m_extra;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot3dFunction::Function3d::PrintDatafile(std::ostream &os) const
|
||||
{
|
||||
}
|
||||
|
||||
// --- Gnuplot3dFunction --------------------------------------------------- //
|
||||
|
||||
Gnuplot3dFunction::Gnuplot3dFunction (const std::string& title, const std::string& function)
|
||||
: GnuplotDataset( new Function3d(title, function) )
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot3dFunction::SetFunction (const std::string& function)
|
||||
{
|
||||
reinterpret_cast<Function3d*>(m_data)->m_function = function;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
Gnuplot::Gnuplot (const std::string& outputFilename, const std::string& title)
|
||||
: m_outputFilename(outputFilename),
|
||||
m_terminal( DetectTerminal(outputFilename) ),
|
||||
m_title(title)
|
||||
{
|
||||
}
|
||||
|
||||
std::string Gnuplot::DetectTerminal (const std::string& filename)
|
||||
{
|
||||
std::string::size_type dotpos = filename.rfind('.');
|
||||
if (dotpos == std::string::npos) return "";
|
||||
|
||||
if (filename.substr(dotpos) == ".png") {
|
||||
return "png";
|
||||
}
|
||||
else if (filename.substr(dotpos) == ".pdf") {
|
||||
return "pdf";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot::SetTerminal (const std::string& terminal)
|
||||
{
|
||||
m_terminal = terminal;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot::SetTitle (const std::string& title)
|
||||
{
|
||||
m_title = title;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot::SetLegend (const std::string& xLegend, const std::string& yLegend)
|
||||
{
|
||||
m_xLegend = xLegend;
|
||||
m_yLegend = yLegend;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot::SetExtra (const std::string& extra)
|
||||
{
|
||||
m_extra = extra;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot::AppendExtra (const std::string& extra)
|
||||
{
|
||||
m_extra += "\n";
|
||||
m_extra += extra;
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot::AddDataset (const GnuplotDataset& dataset)
|
||||
{
|
||||
m_datasets.push_back (dataset);
|
||||
}
|
||||
|
||||
void
|
||||
Gnuplot::GenerateOutput (std::ostream &os) const
|
||||
{
|
||||
if (m_terminal.size())
|
||||
os << "set terminal " << m_terminal << std::endl;
|
||||
|
||||
if (m_outputFilename.size())
|
||||
os << "set output '" << m_outputFilename << "'" << std::endl;
|
||||
|
||||
if (m_title.size())
|
||||
os << "set title '" << m_title << "'" << std::endl;
|
||||
|
||||
if (m_xLegend.size())
|
||||
os << "set xlabel '" << m_xLegend << "'" << std::endl;
|
||||
|
||||
if (m_yLegend.size())
|
||||
os << "set ylabel '" << m_yLegend << "'" << std::endl;
|
||||
|
||||
if (m_extra.size())
|
||||
os << m_extra << std::endl;
|
||||
|
||||
if (m_datasets.empty())
|
||||
return;
|
||||
|
||||
// Determine the GetCommand() values of all datasets included. Check that all
|
||||
// are equal and print the command.
|
||||
|
||||
std::string command = m_datasets.begin()->m_data->GetCommand();
|
||||
|
||||
for (Datasets::const_iterator i = m_datasets.begin () + 1;
|
||||
i != m_datasets.end (); ++i)
|
||||
{
|
||||
NS_ASSERT_MSG(command == i->m_data->GetCommand(),
|
||||
"Cannot mix 'plot' and 'splot' GnuplotDatasets.");
|
||||
}
|
||||
|
||||
os << command << " ";
|
||||
|
||||
// Print all dataset expressions
|
||||
|
||||
for (Datasets::const_iterator i = m_datasets.begin (); i != m_datasets.end ();)
|
||||
{
|
||||
i->m_data->PrintExpression(os);
|
||||
|
||||
i++;
|
||||
|
||||
if (i != m_datasets.end ())
|
||||
{
|
||||
os << ", ";
|
||||
}
|
||||
}
|
||||
os << std::endl;
|
||||
|
||||
// followed by the inline datafile.
|
||||
|
||||
for (Datasets::const_iterator i = m_datasets.begin (); i != m_datasets.end (); i++)
|
||||
{
|
||||
i->m_data->PrintDatafile(os);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
GnuplotCollection::GnuplotCollection (const std::string& outputFilename)
|
||||
: m_outputFilename(outputFilename),
|
||||
m_terminal( Gnuplot::DetectTerminal(outputFilename) )
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GnuplotCollection::SetTerminal (const std::string& terminal)
|
||||
{
|
||||
m_terminal = terminal;
|
||||
}
|
||||
|
||||
void
|
||||
GnuplotCollection::AddPlot (const Gnuplot& plot)
|
||||
{
|
||||
m_plots.push_back (plot);
|
||||
}
|
||||
|
||||
Gnuplot&
|
||||
GnuplotCollection::GetPlot(unsigned int id)
|
||||
{
|
||||
if (id >= m_plots.size())
|
||||
throw(std::range_error("Gnuplot id is out of range"));
|
||||
else
|
||||
return m_plots[id];
|
||||
}
|
||||
|
||||
void
|
||||
GnuplotCollection::GenerateOutput (std::ostream &os) const
|
||||
{
|
||||
if (m_terminal.size())
|
||||
os << "set terminal " << m_terminal << std::endl;
|
||||
|
||||
if (m_outputFilename.size())
|
||||
os << "set output '" << m_outputFilename << "'" << std::endl;
|
||||
|
||||
for (Plots::const_iterator i = m_plots.begin (); i != m_plots.end (); ++i)
|
||||
{
|
||||
i->GenerateOutput (os);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
} // namespace ns3
|
||||
460
src/tools/model/gnuplot.h
Normal file
460
src/tools/model/gnuplot.h
Normal file
@@ -0,0 +1,460 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA, 2008 Timo Bingmann
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Original Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
* Enhancements: Timo Bingmann <timo.bingmann@student.kit.edu>
|
||||
*/
|
||||
#ifndef GNUPLOT_H
|
||||
#define GNUPLOT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Abstract class to store a plot line to be used by ns3::Gnuplot.
|
||||
*
|
||||
* This class contains a reference counted data object in m_data. The data
|
||||
* object contains different structs derived from struct Data by subclasses.
|
||||
*/
|
||||
class GnuplotDataset
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Reference-counting copy constructor.
|
||||
*/
|
||||
GnuplotDataset (const GnuplotDataset& original);
|
||||
|
||||
/**
|
||||
* Reference-counting destructor.
|
||||
*/
|
||||
~GnuplotDataset();
|
||||
|
||||
/**
|
||||
* Reference-counting assignment operator.
|
||||
*/
|
||||
GnuplotDataset& operator= (const GnuplotDataset& original);
|
||||
|
||||
/**
|
||||
* \brief Change line title.
|
||||
* \param title the new title string to use for this dataset.
|
||||
*/
|
||||
void SetTitle (const std::string& title);
|
||||
|
||||
/**
|
||||
* \brief Change extra formatting style parameters for newly created objects.
|
||||
* \param extra extra formatting
|
||||
*/
|
||||
static void SetDefaultExtra (const std::string& extra);
|
||||
|
||||
/**
|
||||
* \brief Add extra formatting parameters to this dataset.
|
||||
* \param extra extra formatting
|
||||
*/
|
||||
void SetExtra (const std::string& extra);
|
||||
|
||||
protected:
|
||||
|
||||
/// Friend because it accesses m_data and it's virtual functions directly in
|
||||
/// GenerateOutput().
|
||||
friend class Gnuplot;
|
||||
|
||||
/**
|
||||
* \brief Extra gnuplot parameters set on every newly created dataset.
|
||||
*/
|
||||
static std::string m_defaultExtra;
|
||||
|
||||
/**
|
||||
* \brief Derived classes subclass this struct and add their own data fields.
|
||||
*/
|
||||
struct Data;
|
||||
|
||||
/**
|
||||
* Called by constructors of derived classes.
|
||||
* \param data the reference counted data object representing this dataset.
|
||||
*/
|
||||
GnuplotDataset (struct Data* data);
|
||||
|
||||
/**
|
||||
* Reference counted data object.
|
||||
*/
|
||||
struct Data* m_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class to represent a 2D points plot. Set the line or points style
|
||||
* using SetStyle() and set points using Add().
|
||||
*/
|
||||
class Gnuplot2dDataset : public GnuplotDataset
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The plotting style to use for this dataset.
|
||||
*/
|
||||
enum Style {
|
||||
LINES,
|
||||
POINTS,
|
||||
LINES_POINTS,
|
||||
DOTS,
|
||||
IMPULSES,
|
||||
STEPS,
|
||||
FSTEPS,
|
||||
HISTEPS,
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether errorbars should be used for this dataset.
|
||||
*/
|
||||
enum ErrorBars {
|
||||
NONE,
|
||||
X,
|
||||
Y,
|
||||
XY
|
||||
};
|
||||
|
||||
/**
|
||||
* \param title the title to be associated to this dataset.
|
||||
*
|
||||
* Create an empty dataset. Usually, the dataset's title is
|
||||
* displayed in the legend box.
|
||||
*/
|
||||
Gnuplot2dDataset (const std::string& title = "Untitled");
|
||||
|
||||
/**
|
||||
* Change default style for all newly created objects.
|
||||
* \param style the style of plotting to use for newly created datasets.
|
||||
*/
|
||||
static void SetDefaultStyle (enum Style style);
|
||||
|
||||
/**
|
||||
* \param style the style of plotting to use for this dataset.
|
||||
*/
|
||||
void SetStyle (enum Style style);
|
||||
|
||||
/**
|
||||
* Change default errorbars style for all newly created objects.
|
||||
* \param errorBars the style of errorbars to use for newly created datasets.
|
||||
*/
|
||||
static void SetDefaultErrorBars (enum ErrorBars errorBars);
|
||||
|
||||
/**
|
||||
* \param errorBars the style of errorbars to display.
|
||||
*
|
||||
* If you use any style other than none, you need
|
||||
* to make sure you store the delta information in
|
||||
* this dataset with the right GnuplotDataset::Add
|
||||
* method.
|
||||
*/
|
||||
void SetErrorBars (enum ErrorBars errorBars);
|
||||
|
||||
/**
|
||||
* \param x x coord to new data point
|
||||
* \param y y coord to new data point
|
||||
*
|
||||
* Use this method with error bar style NONE.
|
||||
*/
|
||||
void Add (double x, double y);
|
||||
|
||||
/**
|
||||
* \param x x coord to new data point
|
||||
* \param y y coord to new data point
|
||||
* \param errorDelta data point error range.
|
||||
*
|
||||
* Use this method with error bar style X or Y.
|
||||
*/
|
||||
void Add (double x, double y, double errorDelta);
|
||||
|
||||
/**
|
||||
* \param x x coord to new data point
|
||||
* \param y y coord to new data point
|
||||
* \param minY minimum error data point
|
||||
* \param maxY maximum error data point
|
||||
*
|
||||
* Use this method with error bar style X or Y.
|
||||
*/
|
||||
void Add (double x, double y, double minY, double maxY);
|
||||
|
||||
/**
|
||||
* Add an empty line in the data output sequence. Empty lines in the plot
|
||||
* data break continuous lines and do other things in the output.
|
||||
*/
|
||||
void AddEmptyLine();
|
||||
|
||||
private:
|
||||
|
||||
struct Point {
|
||||
bool empty;
|
||||
double x;
|
||||
double y;
|
||||
double dx;
|
||||
double dy;
|
||||
};
|
||||
|
||||
typedef std::vector<struct Point> PointSet;
|
||||
|
||||
static enum Style m_defaultStyle;
|
||||
static enum ErrorBars m_defaultErrorBars;
|
||||
|
||||
/// Forward declaration of the internal data class.
|
||||
struct Data2d;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class to represent a 2D function expression plot.
|
||||
*
|
||||
* Since the function expression is not escaped, styles and extras could just
|
||||
* as well be included in the expression string.
|
||||
*/
|
||||
class Gnuplot2dFunction : public GnuplotDataset
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param title the title to be associated to this dataset.
|
||||
* \param function function to plot
|
||||
*
|
||||
* Create an function dataset. Usually, the dataset's title is displayed in
|
||||
* the legend box.
|
||||
*/
|
||||
Gnuplot2dFunction (const std::string& title = "Untitled", const std::string& function = "");
|
||||
|
||||
/**
|
||||
* \param function new function string to set
|
||||
*/
|
||||
void SetFunction (const std::string& function);
|
||||
|
||||
private:
|
||||
|
||||
/// Forward declaration of the internal data class.
|
||||
struct Function2d;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class to represent a 3D points plot. Set the line or points style
|
||||
* using SetStyle() and set points using Add().
|
||||
*/
|
||||
class Gnuplot3dDataset : public GnuplotDataset
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param title the title to be associated to this dataset.
|
||||
*
|
||||
* Create an empty dataset. Usually, the dataset's title is
|
||||
* displayed in the legend box.
|
||||
*/
|
||||
Gnuplot3dDataset (const std::string& title = "Untitled");
|
||||
|
||||
/**
|
||||
* Change default style for all newly created objects.
|
||||
* \param style the style of plotting to use for newly created datasets.
|
||||
*/
|
||||
static void SetDefaultStyle (const std::string& style);
|
||||
|
||||
/**
|
||||
* \param style the style of plotting to use for this dataset.
|
||||
*/
|
||||
void SetStyle (const std::string& style);
|
||||
|
||||
/**
|
||||
* \param x x coord to new data point
|
||||
* \param y y coord to new data point
|
||||
* \param z z coord to new data point
|
||||
*
|
||||
* Use this method to add a new 3D point
|
||||
*/
|
||||
void Add (double x, double y, double z);
|
||||
|
||||
/**
|
||||
* Add an empty line in the data output sequence. Empty lines in the plot
|
||||
* data break continuous lines and do other things in the output.
|
||||
*/
|
||||
void AddEmptyLine();
|
||||
|
||||
private:
|
||||
|
||||
struct Point {
|
||||
bool empty;
|
||||
double x, y, z;
|
||||
};
|
||||
|
||||
typedef std::vector<struct Point> PointSet;
|
||||
|
||||
static std::string m_defaultStyle;
|
||||
|
||||
/// Forward declaration of the internal data class.
|
||||
struct Data3d;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class to represent a 3D function expression plot.
|
||||
*
|
||||
* Since the function expression is not escaped, styles and extras could just as
|
||||
* well be included in the expression string. The only difference to
|
||||
* Gnuplot2dFunction is the splot command string.
|
||||
*/
|
||||
class Gnuplot3dFunction : public GnuplotDataset
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param title the title to be associated to this dataset.
|
||||
* \param function function to plot
|
||||
*
|
||||
* Create an function dataset. Usually, the dataset's title is displayed in
|
||||
* the legend box.
|
||||
*/
|
||||
Gnuplot3dFunction (const std::string& title = "Untitled", const std::string& function = "");
|
||||
|
||||
/**
|
||||
* \param function new function string to set
|
||||
*/
|
||||
void SetFunction (const std::string& function);
|
||||
|
||||
private:
|
||||
|
||||
/// Forward declaration of the internal data class.
|
||||
struct Function3d;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief a simple class to generate gnuplot-ready plotting commands
|
||||
* from a set of datasets.
|
||||
*
|
||||
* This class really represents a single graph on which multiple datasets
|
||||
* can be plotted.
|
||||
*/
|
||||
class Gnuplot
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param outputFilename the name of the file where the rendering of the
|
||||
* graph will be generated if you feed the command stream output by
|
||||
* Gnuplot::GenerateOutput to the gnuplot program.
|
||||
* \param title title line of the plot page
|
||||
*/
|
||||
Gnuplot (const std::string& outputFilename="", const std::string& title = "");
|
||||
|
||||
/**
|
||||
* Crude attempt to auto-detect the correct terminal setting by inspecting
|
||||
* the filename's extension.
|
||||
* \param filename output file name
|
||||
*/
|
||||
static std::string DetectTerminal(const std::string& filename);
|
||||
|
||||
/**
|
||||
* \param terminal terminal setting string for output. The default terminal
|
||||
* string is "png"
|
||||
*/
|
||||
void SetTerminal (const std::string& terminal);
|
||||
|
||||
/**
|
||||
* \param title set new plot title string to use for this plot.
|
||||
*/
|
||||
void SetTitle (const std::string& title);
|
||||
|
||||
/**
|
||||
* \param xLegend the legend for the x horizontal axis
|
||||
* \param yLegend the legend for the y vertical axis
|
||||
*/
|
||||
void SetLegend (const std::string& xLegend, const std::string& yLegend);
|
||||
|
||||
/**
|
||||
* \param extra set extra gnuplot directive for output.
|
||||
*/
|
||||
void SetExtra (const std::string& extra);
|
||||
|
||||
/**
|
||||
* \param extra append extra gnuplot directive for output.
|
||||
*/
|
||||
void AppendExtra (const std::string& extra);
|
||||
|
||||
/**
|
||||
* \param dataset add a dataset to the graph to be plotted.
|
||||
*/
|
||||
void AddDataset (const GnuplotDataset& dataset);
|
||||
|
||||
/**
|
||||
* \param os the output stream on which the relevant gnuplot commands should
|
||||
* be generated. Including output file and terminal headers.
|
||||
*/
|
||||
void GenerateOutput (std::ostream &os) const;
|
||||
|
||||
private:
|
||||
typedef std::vector<GnuplotDataset> Datasets;
|
||||
|
||||
std::string m_outputFilename;
|
||||
std::string m_terminal;
|
||||
|
||||
Datasets m_datasets;
|
||||
|
||||
std::string m_title;
|
||||
std::string m_xLegend;
|
||||
std::string m_yLegend;
|
||||
std::string m_extra;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief a simple class to group together multiple gnuplots into one file,
|
||||
* e.g. for PDF multi-page output terminals.
|
||||
*/
|
||||
class GnuplotCollection
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \param outputFilename the name of the file where the rendering of the
|
||||
* graph will be generated if you feed the command stream output by
|
||||
* GnuplotCollection::GenerateOutput to the gnuplot program.
|
||||
*/
|
||||
GnuplotCollection (const std::string& outputFilename);
|
||||
|
||||
/**
|
||||
* \param terminal terminal setting string for output. The default terminal
|
||||
* string is guessed from the output filename's extension.
|
||||
*/
|
||||
void SetTerminal (const std::string& terminal);
|
||||
|
||||
/**
|
||||
* \param plot add a plot to the collection to be plotted.
|
||||
*/
|
||||
void AddPlot (const Gnuplot& plot);
|
||||
|
||||
/**
|
||||
* Return a pointer to one of the added plots.
|
||||
* \param id index of plot to return
|
||||
* \return reference to plot, throws std::range_error if it does not exist.
|
||||
*/
|
||||
Gnuplot& GetPlot(unsigned int id);
|
||||
|
||||
/**
|
||||
* \param os the output stream on which the relevant gnuplot commands should
|
||||
* be generated.
|
||||
*/
|
||||
void GenerateOutput (std::ostream &os) const;
|
||||
|
||||
private:
|
||||
typedef std::vector<Gnuplot> Plots;
|
||||
|
||||
std::string m_outputFilename;
|
||||
std::string m_terminal;
|
||||
|
||||
Plots m_plots;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* GNUPLOT_H */
|
||||
21
src/tools/wscript
Normal file
21
src/tools/wscript
Normal file
@@ -0,0 +1,21 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def build(bld):
|
||||
|
||||
module = bld.create_ns3_module('tools', ['network'])
|
||||
module.source = [
|
||||
'model/event-garbage-collector.cc',
|
||||
'model/gnuplot.cc',
|
||||
'model/delay-jitter-estimation.cc',
|
||||
]
|
||||
|
||||
headers = bld.new_task_gen('ns3header')
|
||||
headers.module = 'tools'
|
||||
headers.source = [
|
||||
'model/average.h',
|
||||
'model/event-garbage-collector.h',
|
||||
'model/gnuplot.h',
|
||||
'model/delay-jitter-estimation.h',
|
||||
]
|
||||
|
||||
bld.ns3_python_bindings()
|
||||
Reference in New Issue
Block a user