diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 72f371c36f..8e8f02126b 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -182,6 +182,7 @@ set( EESCHEMA_SRCS sim/sim_plot_frame.cpp sim/sim_plot_panel.cpp sim/spice_simulator.cpp + sim/spice_value.cpp sim/ngspice.cpp sim/netlist_exporter_pspice_sim.cpp dialogs/dialog_signal_list.cpp diff --git a/eeschema/dialogs/dialog_spice_model.cpp b/eeschema/dialogs/dialog_spice_model.cpp index 6817d133ef..7c5219d3b2 100644 --- a/eeschema/dialogs/dialog_spice_model.cpp +++ b/eeschema/dialogs/dialog_spice_model.cpp @@ -23,7 +23,9 @@ */ #include "dialog_spice_model.h" + #include +#include #include diff --git a/eeschema/netlist_exporters/netlist_exporter_pspice.cpp b/eeschema/netlist_exporters/netlist_exporter_pspice.cpp index 48c3251275..c3fc92e780 100644 --- a/eeschema/netlist_exporters/netlist_exporter_pspice.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_pspice.cpp @@ -381,91 +381,6 @@ void NETLIST_EXPORTER_PSPICE::writeDirectives( OUTPUTFORMATTER* aFormatter, unsi } -SPICE_VALUE::SPICE_VALUE( const wxString& aString ) -{ - char buf[8] = { 0, }; - - if( sscanf( (const char*) aString.c_str(), "%lf%7s", &m_base, buf ) == 0 ) - throw std::invalid_argument( "Invalid Spice value string" ); - - if( *buf == 0 ) - { - m_prefix = PFX_NONE; - return; - } - - for( char* bufPtr = buf; *bufPtr; ++bufPtr ) - *bufPtr = tolower( *bufPtr ); - - if( !strcmp( buf, "meg" ) ) - { - m_prefix = PFX_MEGA; - } - else - { - switch( buf[0] ) - { - case 'f': m_prefix = PFX_FEMTO; break; - case 'p': m_prefix = PFX_PICO; break; - case 'n': m_prefix = PFX_NANO; break; - case 'u': m_prefix = PFX_MICRO; break; - case 'm': m_prefix = PFX_MILI; break; - case 'k': m_prefix = PFX_KILO; break; - case 'g': m_prefix = PFX_GIGA; break; - case 't': m_prefix = PFX_TERA; break; - - default: - throw std::invalid_argument( "Invalid unit prefix" ); - } - } -} - - -SPICE_VALUE::SPICE_VALUE( int aInt, UNIT_PREFIX aPrefix ) - : m_base( aInt ), m_prefix( aPrefix ) -{ -} - - -SPICE_VALUE::SPICE_VALUE( double aDouble, UNIT_PREFIX aPrefix ) - : m_base( aDouble ), m_prefix( aPrefix ) -{ -} - - -double SPICE_VALUE::ToDouble() const -{ - double res = m_base; - - if( m_prefix != PFX_NONE ) - res *= pow( 10, (int) m_prefix ); - - return res; -} - - -wxString SPICE_VALUE::ToSpiceString() const -{ - wxString res = wxString::Format( "%f", m_base ); - - switch( m_prefix ) - { - case PFX_FEMTO: res += "f"; break; - case PFX_PICO: res += "p"; break; - case PFX_NANO: res += "n"; break; - case PFX_MICRO: res += "u"; break; - case PFX_MILI: res += "m"; break; - case PFX_NONE: break; - case PFX_KILO: res += "k"; break; - case PFX_MEGA: res += "Meg"; break; - case PFX_GIGA: res += "G"; break; - case PFX_TERA: res += "T"; break; - } - - return res; -} - - // Entries in the vector below have to follow the order in SPICE_FIELD enum const std::vector NETLIST_EXPORTER_PSPICE::m_spiceFields = { "Spice_Primitive", diff --git a/eeschema/netlist_exporters/netlist_exporter_pspice.h b/eeschema/netlist_exporters/netlist_exporter_pspice.h index 4c1ead2751..c45c4be425 100644 --- a/eeschema/netlist_exporters/netlist_exporter_pspice.h +++ b/eeschema/netlist_exporters/netlist_exporter_pspice.h @@ -170,41 +170,4 @@ private: static const std::vector m_spiceFields; }; - -// Helper class to handle Spice way of expressing values (e.g. 10.5m) -class SPICE_VALUE -{ -public: - enum UNIT_PREFIX - { - PFX_FEMTO = -15, - PFX_PICO = -12, - PFX_NANO = -9, - PFX_MICRO = -6, - PFX_MILI = -3, - PFX_NONE = 0, - PFX_KILO = 3, - PFX_MEGA = 6, - PFX_GIGA = 9, - PFX_TERA = 12 - }; - - SPICE_VALUE( const wxString& aString ); - SPICE_VALUE( int aInt, UNIT_PREFIX aPrefix = PFX_NONE ); - SPICE_VALUE( double aDouble, UNIT_PREFIX aPrefix = PFX_NONE ); - - double ToDouble() const; - - wxString ToSpiceString() const; - - wxString ToString() const - { - return wxString::Format( "%f", ToDouble() ); - } - -private: - double m_base; - UNIT_PREFIX m_prefix; -}; - #endif diff --git a/eeschema/sim/spice_value.cpp b/eeschema/sim/spice_value.cpp new file mode 100644 index 0000000000..8c5b8f1464 --- /dev/null +++ b/eeschema/sim/spice_value.cpp @@ -0,0 +1,223 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 CERN + * @author Maciej Suminski + * + * 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 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * https://www.gnu.org/licenses/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "spice_value.h" + +#include +#include + +SPICE_VALUE::SPICE_VALUE( const wxString& aString ) +{ + char buf[8] = { 0, }; + + if( sscanf( (const char*) aString.c_str(), "%lf%7s", &m_base, buf ) == 0 ) + throw std::invalid_argument( "Invalid Spice value string" ); + + if( *buf == 0 ) + { + m_prefix = PFX_NONE; + m_spiceStr = false; + Normalize(); + return; + } + + m_spiceStr = true; + + for( char* bufPtr = buf; *bufPtr; ++bufPtr ) + *bufPtr = tolower( *bufPtr ); + + if( !strcmp( buf, "meg" ) ) + { + m_prefix = PFX_MEGA; + } + else + { + switch( buf[0] ) + { + case 'f': m_prefix = PFX_FEMTO; break; + case 'p': m_prefix = PFX_PICO; break; + case 'n': m_prefix = PFX_NANO; break; + case 'u': m_prefix = PFX_MICRO; break; + case 'm': m_prefix = PFX_MILI; break; + case 'k': m_prefix = PFX_KILO; break; + case 'g': m_prefix = PFX_GIGA; break; + case 't': m_prefix = PFX_TERA; break; + + default: + throw std::invalid_argument( "Invalid unit prefix" ); + } + } + + Normalize(); +} + + +void SPICE_VALUE::Normalize() +{ + while( std::fabs( m_base ) >= 1000.0 ) + { + m_base *= 0.001; + m_prefix = (UNIT_PREFIX)( m_prefix + 3 ); + } + + while( m_base != 0.0 && std::fabs( m_base ) <= 0.001 ) + { + m_base *= 1000.0; + m_prefix = (UNIT_PREFIX)( m_prefix - 3 ); + } +} + + +double SPICE_VALUE::ToDouble() const +{ + double res = m_base; + + if( m_prefix != PFX_NONE ) + res *= std::pow( 10, (int) m_prefix ); + + return res; +} + +wxString SPICE_VALUE::ToString() const +{ + wxString res( wxString::Format( "%.3f", ToDouble() ) ); + stripZeros( res ); + + return res; +} + + +wxString SPICE_VALUE::ToSpiceString() const +{ + wxString res = wxString::Format( "%f", m_base ); + stripZeros( res ); + + switch( m_prefix ) + { + case PFX_FEMTO: res += "f"; break; + case PFX_PICO: res += "p"; break; + case PFX_NANO: res += "n"; break; + case PFX_MICRO: res += "u"; break; + case PFX_MILI: res += "m"; break; + case PFX_NONE: break; + case PFX_KILO: res += "k"; break; + case PFX_MEGA: res += "Meg"; break; + case PFX_GIGA: res += "G"; break; + case PFX_TERA: res += "T"; break; + } + + return res; +} + + +SPICE_VALUE SPICE_VALUE::operator+( const SPICE_VALUE& aOther ) const +{ + int prefixDiff = m_prefix - aOther.m_prefix; + SPICE_VALUE res; + res.m_spiceStr = m_spiceStr || aOther.m_spiceStr; + + // Convert both numbers to a common prefix + if( prefixDiff > 0 ) + { + // Switch to the aOther prefix + res.m_base = ( m_base * std::pow( 10, prefixDiff ) ) + aOther.m_base; + res.m_prefix = aOther.m_prefix; + } + else if( prefixDiff < 0 ) + { + // Use the current prefix + res.m_base = m_base + ( aOther.m_base * std::pow( 10, -prefixDiff ) ); + res.m_prefix = m_prefix; + } + else + { + res.m_base = m_base + aOther.m_base; + res.m_prefix = m_prefix; // == aOther.m_prefix + } + + res.Normalize(); + + return res; +} + + +SPICE_VALUE SPICE_VALUE::operator-( const SPICE_VALUE& aOther ) const +{ + int prefixDiff = m_prefix - aOther.m_prefix; + SPICE_VALUE res; + res.m_spiceStr = m_spiceStr || aOther.m_spiceStr; + + // Convert both numbers to a common prefix + if( prefixDiff > 0 ) + { + // Switch to the aOther prefix + res.m_base = m_prefix * std::pow( 10, prefixDiff ) - aOther.m_prefix; + res.m_prefix = aOther.m_prefix; + } + else if( prefixDiff < 0 ) + { + // Use the current prefix + res.m_base = m_prefix - aOther.m_prefix * std::pow( 10, -prefixDiff ); + res.m_prefix = m_prefix; + } + else + { + res.m_base = m_base - aOther.m_base; + res.m_prefix = m_prefix; // == aOther.m_prefix + } + + res.Normalize(); + + return res; +} + + +SPICE_VALUE SPICE_VALUE::operator*( const SPICE_VALUE& aOther ) const +{ + SPICE_VALUE res( m_base * aOther.m_base, (UNIT_PREFIX)( m_prefix + aOther.m_prefix ) ); + res.m_spiceStr = m_spiceStr || aOther.m_spiceStr; + res.Normalize(); + + return res; +} + + +SPICE_VALUE SPICE_VALUE::operator/( const SPICE_VALUE& aOther ) const +{ + SPICE_VALUE res( m_base / aOther.m_base, (UNIT_PREFIX)( m_prefix - aOther.m_prefix ) ); + res.m_spiceStr = m_spiceStr || aOther.m_spiceStr; + res.Normalize(); + + return res; +} + + +void SPICE_VALUE::stripZeros( wxString& aString ) +{ + while( aString.EndsWith( '0' ) ) + aString.RemoveLast(); + + if( aString.EndsWith( '.' ) ) + aString.RemoveLast(); +} diff --git a/eeschema/sim/spice_value.h b/eeschema/sim/spice_value.h new file mode 100644 index 0000000000..c5d00a191e --- /dev/null +++ b/eeschema/sim/spice_value.h @@ -0,0 +1,123 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 CERN + * @author Maciej Suminski + * + * 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 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * https://www.gnu.org/licenses/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef SPICE_VALUE_H +#define SPICE_VALUE_H + +#include + +///> Helper class to handle Spice way of expressing values (e.g. 10.5 Meg) +class SPICE_VALUE +{ +public: + enum UNIT_PREFIX + { + PFX_FEMTO = -15, + PFX_PICO = -12, + PFX_NANO = -9, + PFX_MICRO = -6, + PFX_MILI = -3, + PFX_NONE = 0, + PFX_KILO = 3, + PFX_MEGA = 6, + PFX_GIGA = 9, + PFX_TERA = 12 + }; + + SPICE_VALUE() + : m_base( 0 ), m_prefix( PFX_NONE ) + { + } + + SPICE_VALUE( const wxString& aString ); + + SPICE_VALUE( int aInt, UNIT_PREFIX aPrefix = PFX_NONE ) + : m_base( aInt ), m_prefix( aPrefix ), m_spiceStr( false ) + { + } + + SPICE_VALUE( double aDouble, UNIT_PREFIX aPrefix = PFX_NONE ) + : m_base( aDouble ), m_prefix( aPrefix ), m_spiceStr( false ) + { + } + + void Normalize(); + + double ToDouble() const; + + wxString ToString() const; + + wxString ToSpiceString() const; + + wxString ToOrigString() const + { + return m_spiceStr ? ToSpiceString() : ToString(); + } + + bool IsSpiceString() const + { + return m_spiceStr; + } + + bool operator==( const SPICE_VALUE& aOther ) const + { + return ( m_prefix == aOther.m_prefix && m_base == aOther.m_base ); + } + + bool operator>( const SPICE_VALUE& aOther ) const + { + return this->ToDouble() > aOther.ToDouble(); + } + + bool operator<( const SPICE_VALUE& aOther ) const + { + return this->ToDouble() < aOther.ToDouble(); + } + + bool operator>=( const SPICE_VALUE& aOther ) const + { + return ( *this == aOther || *this > aOther ); + } + + bool operator<=( const SPICE_VALUE& aOther ) const + { + return ( *this == aOther || *this < aOther ); + } + + SPICE_VALUE operator-( const SPICE_VALUE& aOther ) const; + SPICE_VALUE operator+( const SPICE_VALUE& aOther ) const; + SPICE_VALUE operator*( const SPICE_VALUE& aOther ) const; + SPICE_VALUE operator/( const SPICE_VALUE& aOther ) const; + +private: + double m_base; + UNIT_PREFIX m_prefix; + + ///> Was the value defined using the Spice notation? + bool m_spiceStr; + + static void stripZeros( wxString& aString ); +}; + +#endif /* SPICE_VALUE_H */