You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
6.8 KiB
266 lines
6.8 KiB
/***************************************************************************
|
|
* Copyright (C) 2005 by David Saxton *
|
|
* david@bluehaze.org *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
***************************************************************************/
|
|
|
|
#include "canvasitemparts.h"
|
|
#include "ecnode.h"
|
|
#include "element.h"
|
|
#include "libraryitem.h"
|
|
#include "meter.h"
|
|
#include "variant.h"
|
|
#include "voltagesource.h"
|
|
#include "pin.h"
|
|
#include "simulator.h"
|
|
|
|
#include <cmath>
|
|
#include <tdelocale.h>
|
|
#include <tqpainter.h>
|
|
|
|
|
|
//BEGIN class Meter
|
|
Meter::Meter( ICNDocument *icnDocument, bool newItem, const char *id )
|
|
: Component( icnDocument, newItem, id )
|
|
{
|
|
m_bDynamicContent = true;
|
|
b_timerStarted = false;
|
|
m_timeSinceUpdate = 0.;
|
|
m_old_value = 0.;
|
|
m_avgValue = 0.;
|
|
b_firstRun = true;
|
|
setSize( -16, -16, 32, 32 );
|
|
|
|
p_displayText = addDisplayText( "meter", TQRect( -16, 16, 32, 16 ), displayText() );
|
|
|
|
createProperty( "0-minValue", Variant::Type::Double );
|
|
property("0-minValue")->setCaption( i18n("Minimum Value") );
|
|
property("0-minValue")->setMinValue(1e-12);
|
|
property("0-minValue")->setMaxValue(1e12);
|
|
property("0-minValue")->setValue(1e-3);
|
|
|
|
createProperty( "1-maxValue", Variant::Type::Double );
|
|
property("1-maxValue")->setCaption( i18n("Maximum Value") );
|
|
property("1-maxValue")->setMinValue(1e-12);
|
|
property("1-maxValue")->setMaxValue(1e12);
|
|
property("1-maxValue")->setValue(1e3);
|
|
}
|
|
|
|
|
|
Meter::~Meter()
|
|
{
|
|
}
|
|
|
|
|
|
void Meter::dataChanged()
|
|
{
|
|
m_minValue = dataDouble("0-minValue");
|
|
m_maxValue = dataDouble("1-maxValue");
|
|
setChanged();
|
|
}
|
|
|
|
void Meter::stepNonLogic()
|
|
{
|
|
if (b_firstRun)
|
|
{
|
|
p_displayText->setText(displayText());
|
|
updateAttachedPositioning();
|
|
setChanged();
|
|
property("0-minValue")->setUnit(m_unit);
|
|
property("1-maxValue")->setUnit(m_unit);
|
|
b_firstRun = false;
|
|
}
|
|
|
|
const double v = meterValue();
|
|
if ( !b_timerStarted && std::abs(((v-m_old_value)/m_old_value)) > 1e-6 ) {
|
|
b_timerStarted = true;
|
|
}
|
|
|
|
if (b_timerStarted)
|
|
{
|
|
m_timeSinceUpdate += 1./LINEAR_UPDATE_RATE;
|
|
m_avgValue += v/LINEAR_UPDATE_RATE;
|
|
// setChanged();
|
|
if ( m_timeSinceUpdate > 0.05 )
|
|
{
|
|
if ( p_displayText->setText(displayText()) );
|
|
updateAttachedPositioning();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Meter::drawShape( TQPainter &p )
|
|
{
|
|
initPainter(p);
|
|
p.drawEllipse( (int)x()-16, (int)y()-16, width(), width() );
|
|
p.setPen(TQPen(TQt::black,2));
|
|
p.setBrush(TQt::black);
|
|
|
|
// The proportion between 0.1mV and 10KV, on a logarithmic scale
|
|
double prop;
|
|
const double abs_value = std::abs(m_old_value);
|
|
if ( abs_value <= m_minValue )
|
|
prop = 0.;
|
|
else if ( abs_value >= m_maxValue )
|
|
prop = 1.;
|
|
else
|
|
prop = std::log10( abs_value/m_minValue ) / std::log10( m_maxValue/m_minValue );
|
|
if ( m_old_value>0 )
|
|
prop *= -1;
|
|
double sin_prop = 10*std::sin(prop*1.571); // 1.571 = pi/2
|
|
double cos_prop = 10*std::cos(prop*1.571); // 1.571 = pi/2
|
|
|
|
int cx = int(x()-16+(width()/2));
|
|
int cy = int(y()-16+(height()/2));
|
|
p.drawLine( int(cx-sin_prop), int(cy-cos_prop), int(cx+sin_prop), int(cy+cos_prop) );
|
|
|
|
TQPointArray pa(3);
|
|
pa[0] = TQPoint( int(cx-sin_prop), int(cy-cos_prop) ); // Arrow head
|
|
pa[1] = TQPoint( int(cx-sin_prop + 8*std::sin(1.571*(-0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(-0.3+prop))) );
|
|
pa[2] = TQPoint( int(cx-sin_prop + 8*std::sin(1.571*(0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(0.3+prop))) );
|
|
p.drawPolygon(pa);
|
|
|
|
deinitPainter(p);
|
|
}
|
|
|
|
|
|
TQString Meter::displayText()
|
|
{
|
|
double value = m_avgValue/m_timeSinceUpdate;
|
|
if ( !std::isfinite(value) ) value = m_old_value;
|
|
if ( std::abs((value)) < 1e-9 ) value = 0.;
|
|
m_old_value = value;
|
|
m_avgValue = 0.;
|
|
m_timeSinceUpdate = 0.;
|
|
b_timerStarted = false;
|
|
return TQString::number( value/CNItem::getMultiplier(value), 'g', 3 ) + CNItem::getNumberMag(value) + m_unit;
|
|
}
|
|
//END class Meter
|
|
|
|
|
|
//BEGIN class FrequencyMeter
|
|
Item* FrequencyMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
|
|
{
|
|
return new FrequencyMeter( (ICNDocument*)itemDocument, newItem, id );
|
|
}
|
|
|
|
LibraryItem* FrequencyMeter::libraryItem()
|
|
{
|
|
return new LibraryItem(
|
|
TQString("ec/frequencymeter"),
|
|
i18n("Frequency Meter (TODO)"),
|
|
i18n("Outputs"),
|
|
"frequencymeter.png",
|
|
LibraryItem::lit_component,
|
|
FrequencyMeter::construct );
|
|
}
|
|
|
|
FrequencyMeter::FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id )
|
|
: Meter( icnDocument, newItem, (id) ? id : "frequencymeter" )
|
|
{
|
|
m_name = i18n("Frequency Meter");
|
|
m_desc = i18n("Place this at the point where frequency is to be measured.");
|
|
m_unit = "Hz";
|
|
|
|
m_probeNode = createPin( 0, -24, 90, "n1" );
|
|
}
|
|
|
|
FrequencyMeter::~FrequencyMeter()
|
|
{
|
|
}
|
|
|
|
double FrequencyMeter::meterValue()
|
|
{
|
|
return 0;
|
|
}
|
|
//END class FrequencyMeter
|
|
|
|
|
|
//BEGIN class ECAmmeter
|
|
Item* ECAmmeter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
|
|
{
|
|
return new ECAmmeter( (ICNDocument*)itemDocument, newItem, id );
|
|
}
|
|
|
|
LibraryItem* ECAmmeter::libraryItem()
|
|
{
|
|
TQStringList ids;
|
|
ids << "ec/ammeter" << "ec/ammmeter";
|
|
return new LibraryItem(
|
|
ids,
|
|
i18n("Ammeter"),
|
|
i18n("Outputs"),
|
|
"ammeter.png",
|
|
LibraryItem::lit_component,
|
|
ECAmmeter::construct
|
|
);
|
|
}
|
|
|
|
ECAmmeter::ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id )
|
|
: Meter( icnDocument, newItem, (id) ? id : "ammeter" )
|
|
{
|
|
m_name = i18n("Ammeter");
|
|
m_desc = i18n("Place this in series in the circuit to measure the current flowing.");
|
|
setSize( -16, -16, 32, 32 );
|
|
m_unit = "A";
|
|
|
|
init1PinLeft(0);
|
|
init1PinRight(0);
|
|
|
|
m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. );
|
|
}
|
|
|
|
ECAmmeter::~ECAmmeter()
|
|
{
|
|
}
|
|
|
|
double ECAmmeter::meterValue()
|
|
{
|
|
return -m_voltageSource->cbranchCurrent(0);
|
|
}
|
|
//END class ECAmmeter
|
|
|
|
|
|
//BEGIN class ECVoltmeter
|
|
Item* ECVoltMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
|
|
{
|
|
return new ECVoltMeter( (ICNDocument*)itemDocument, newItem, id );
|
|
}
|
|
|
|
LibraryItem* ECVoltMeter::libraryItem()
|
|
{
|
|
return new LibraryItem(
|
|
TQString("ec/voltmeter"),
|
|
i18n("Voltmeter"),
|
|
i18n("Outputs"),
|
|
"voltmeter.png",
|
|
LibraryItem::lit_component,
|
|
ECVoltMeter::construct );
|
|
}
|
|
|
|
ECVoltMeter::ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id )
|
|
: Meter( icnDocument, newItem, (id) ? id : "voltmeter" )
|
|
{
|
|
m_name = i18n("Voltmeter");
|
|
m_desc = i18n("Place this in parallel in the circuit to meaure the voltage between two points.");
|
|
m_unit = "V";
|
|
|
|
init1PinLeft(0);
|
|
init1PinRight(0);
|
|
}
|
|
|
|
ECVoltMeter::~ECVoltMeter()
|
|
{
|
|
}
|
|
|
|
double ECVoltMeter::meterValue()
|
|
{
|
|
return m_pNNode[0]->pin()->voltage() - m_pPNode[0]->pin()->voltage();
|
|
}
|
|
//END class ECVoltMeter
|
|
|