Begin development of a new Sim Model Editor dialog

With that also begin reworking the internal structure of the simulation
model storage. Some models have parameter information extracted from
Ngspice, which was specially patched to faciliate that. The model is
stored and managed by the SPICE_MODEL class (later will be renamed to
SIM_MODEL).
This commit is contained in:
Mikolaj Wielgus 2022-02-09 01:45:04 +01:00
parent a8505d9c76
commit 229e5c9e0f
12 changed files with 10039 additions and 16267 deletions

View File

@ -312,6 +312,7 @@ if( KICAD_SPICE )
dialogs/dialog_spice_model_base.cpp
sim/ngspice_helpers.cpp
sim/ngspice.cpp
sim/ngspice_models.cpp
sim/sim_panel_base.cpp
sim/sim_plot_colors.cpp
sim/sim_plot_frame.cpp
@ -319,6 +320,7 @@ if( KICAD_SPICE )
sim/sim_plot_panel.cpp
sim/sim_workbook.cpp
sim/spice_simulator.cpp
sim/spice_model.cpp
sim/spice_value.cpp
widgets/tuner_slider.cpp
widgets/tuner_slider_base.cpp

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016-2017 CERN
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -31,180 +29,35 @@
#include <netlist_exporter_pspice.h>
#include <scintilla_tricks.h>
#include <sim/spice_value.h>
#include <sim/spice_model.h>
#include <sch_symbol.h>
#include <sch_field.h>
#include <lib_field.h>
#include <wx/valnum.h>
template <typename T>
class DIALOG_SPICE_MODEL : public DIALOG_SPICE_MODEL_BASE
{
public:
enum COLUMN { DESCRIPTION, NAME, VALUE, UNIT };
DIALOG_SPICE_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
std::vector<SCH_FIELD>* aSchFields );
DIALOG_SPICE_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
std::vector<LIB_FIELD>* aLibFields );
std::vector<T>* aSchFields );
private:
/**
* Parse a string describing a power source, so appropriate settings are checked in the dialog.
*
* @param aModel contains the string to be parse (e.g. sin(0 1 10k))
* @return True if the input string was parsed without errors.
*/
bool parsePowerSource( const wxString& aModel );
bool TransferDataFromWindow() override;
bool TransferDataToWindow() override;
/**
* Parse a string describing a lossless transmission line, so appropriate settings are checked in the dialog.
*
* @param aModel contains the string to be parse (e.g. "Z0=50 td=10n")
* @return True if the input string was parsed without errors.
*/
bool parseLosslessTline( const wxString& aModel );
void updateModel();
void updateWidgets();
/**
* Parse a string describing a lossy transmission line, so appropriate settings are checked in the dialog.
*
* @param aModel contains the string to be parse (e.g. "R=50 C=10 LEN=1")
* @return True if the input string was parsed without errors.
*/
bool parseLossyTline( const wxString& aModel );
void onDeviceTypeChoice( wxCommandEvent& aEvent ) override;
void onTypeChoice( wxCommandEvent& aEvent ) override;
void onGridCellChange( wxGridEvent& aEvent ) override;
/**
* Generate a string to describe power source parameters, basing on the current selection.
*
* If there are missing fields, it will not modify the target string.
*
* @param aTarget is the destination for the generated string.
* @return True if the string was saved successfully.
*/
bool generatePowerSource( wxString& aTarget );
/**
* Generate a string to describe a transmission line model, basing on the current selection.
*
* If there are missing fields, it will not modify the target string.
*
* @param aTarget is the destination for the generated string.
* @return True if the string was saved successfully.
*/
bool generateTlineLossless( wxString& aTarget );
/**
* Generate a string to describe a transmission line model, basing on the current selection.
*
* If there are missing fields, it will not modify the target string.
*
* @param aTarget is the destination for the generated string.
* @return True if the string was saved successfully.
*/
bool generateTlineLossy( wxString& aTarget );
/**
* Load a list of components (.model and .subckt) from a spice library file and add them to
* a combo box.
*
* @param aComboBox is the target combo box
* @param aFilePath is path to the library file
*/
void loadLibrary( const wxString& aFilePath );
/**
* Return or create a field in the edited schematic fields vector.
*
* @param aFieldType is an SPICE_FIELD enum value.
* @return Requested field.
*/
SCH_FIELD& getSchField( int aFieldType );
LIB_FIELD& getLibField( int aFieldType );
/**
* Add a value to the PWL values list.
*
* @param aTime is the time value.
* @param aValue is the source value at the given time.
* @return True if request has completed successfully, false if the data is invalid.
*/
bool addPwlValue( const wxString& aTime, const wxString& aValue );
virtual bool TransferDataFromWindow() override;
virtual bool TransferDataToWindow() override;
// The default dialog Validate() calls the validators of all widgets.
// This is not what we want; We want only validators of the selected page
// of the notebooks. So disable the wxDialog::Validate(), and let our
// TransferDataFromWindow doing the job.
virtual bool Validate() override
{
return true;
}
virtual void onInitDlg( wxInitDialogEvent& event ) override
{
// Call the default wxDialog handler of a wxInitDialogEvent
TransferDataToWindow();
// Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings();
}
/**
* Initialize the internal settings.
*/
void Init();
/**
* Display a note info about pin order
*/
void showPinOrderNote( int aModelType );
// Event handlers
void onSelectLibrary( wxCommandEvent& event ) override;
void onModelSelected( wxCommandEvent& event ) override;
void onPwlAdd( wxCommandEvent& event ) override;
void onPwlRemove( wxCommandEvent& event ) override;
void onRandomSourceType( wxCommandEvent& event ) override;
void onTypeSelected( wxCommandEvent& event ) override;
///< Edited symbol
SCH_SYMBOL& m_symbol;
std::vector<T>* m_fields;
///< Fields from the symbol properties dialog.
std::vector<SCH_FIELD>* m_schfields;
std::vector<LIB_FIELD>* m_libfields;
bool m_useSchFields;
///< Temporary field values
std::map<int, wxString> m_fieldsTmp;
struct MODEL
{
///< Line number in the library file
int line;
///< Type of the device
SPICE_PRIMITIVE model;
///< Convert string to model
static SPICE_PRIMITIVE parseModelType( const wxString& aValue );
MODEL( int aLine, enum SPICE_PRIMITIVE aModel )
: line( aLine ), model( aModel )
{
}
};
///< Models available in the selected library file
std::map<wxString, MODEL> m_models;
///< Column identifiers for PWL power source value list
long m_pwlTimeCol, m_pwlValueCol;
SPICE_VALIDATOR m_spiceValidator;
SPICE_VALIDATOR m_spiceEmptyValidator;
wxTextValidator m_notEmptyValidator;
std::vector<SPICE_MODEL> m_models;
std::map<SPICE_MODEL::DEVICE_TYPE, SPICE_MODEL::TYPE> m_curModelTypeOfDeviceType;
SPICE_MODEL::TYPE m_curModelType = SPICE_MODEL::TYPE::NONE;
std::unique_ptr<SCINTILLA_TRICKS> m_scintillaTricks;
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.0-4761b0c5)
// C++ code generated with wxFormBuilder (version 3.10.0)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -9,30 +9,28 @@
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include "dialog_shim.h"
class WX_GRID;
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/combobox.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
#include <wx/statline.h>
#include <wx/panel.h>
#include <wx/button.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/stc/stc.h>
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/listctrl.h>
#include <wx/choice.h>
#include <wx/notebook.h>
#include <wx/radiobox.h>
#include <wx/checkbox.h>
#include <wx/choice.h>
#include <wx/grid.h>
#include <wx/panel.h>
#include <wx/stc/stc.h>
#include <wx/notebook.h>
#include <wx/statline.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
@ -41,252 +39,45 @@
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_SPICE_MODEL_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_SPICE_MODEL_BASE : public DIALOG_SHIM
class DIALOG_SPICE_MODEL_BASE : public wxDialog
{
private:
protected:
wxNotebook* m_notebook;
wxPanel* m_passive;
wxStaticText* m_staticTextPtype;
wxComboBox* m_pasType;
wxStaticText* m_staticText62;
wxStaticText* m_staticTextPvalue;
wxTextCtrl* m_pasValue;
wxStaticText* m_staticTextSpVal;
wxPanel* m_modelPanel;
wxStaticText* m_staticText122;
wxTextCtrl* m_modelName;
wxButton* m_browseButton;
wxStaticText* m_staticText124;
wxStaticText* m_staticText125;
wxCheckBox* m_checkBox2;
wxNotebook* m_notebook4;
wxPanel* m_parametersPanel;
wxStaticText* m_staticText127;
wxChoice* m_deviceTypeChoice;
wxStaticText* m_staticText8;
wxChoice* m_typeChoice;
WX_GRID* m_paramGrid;
wxPanel* m_codePanel;
wxStyledTextCtrl* m_codePreview;
wxPanel* m_pinAssignmentsPanel;
WX_GRID* m_pinAssignmentGrid;
wxStaticLine* m_staticline1;
wxStaticText* m_staticText32;
wxStaticText* m_staticText321;
wxStaticText* m_staticTextF1;
wxStaticText* m_staticTextF2;
wxStaticText* m_staticTextF3;
wxStaticText* m_staticTextP1;
wxStaticText* m_staticTextP2;
wxStaticText* m_staticTextP3;
wxStaticText* m_staticTextN1;
wxStaticText* m_staticTextN2;
wxStaticText* m_staticTextN3;
wxStaticText* m_staticTextU1;
wxStaticText* m_staticTextU2;
wxStaticText* m_staticTextU3;
wxStaticText* m_staticTextM1;
wxStaticText* m_staticTextM2;
wxStaticText* m_staticTextM3;
wxStaticText* m_staticTextK1;
wxStaticText* m_staticTextK2;
wxStaticText* m_staticTextK3;
wxStaticText* m_staticTextMeg1;
wxStaticText* m_staticTextMeg2;
wxStaticText* m_staticTextMeg3;
wxStaticText* m_staticTextG1;
wxStaticText* m_staticTextG2;
wxStaticText* m_staticTextG3;
wxStaticText* m_staticTextT1;
wxStaticText* m_staticTextT2;
wxStaticText* m_staticTextT3;
wxPanel* m_model;
wxStaticText* m_staticText7;
wxTextCtrl* m_modelLibrary;
wxButton* m_selectLibrary;
wxStaticText* m_staticText5;
wxComboBox* m_modelName;
wxStaticText* m_staticText4;
wxComboBox* m_modelType;
wxStaticText* m_staticTextNote;
wxStaticText* m_stInfoNote;
wxStyledTextCtrl* m_libraryContents;
wxPanel* m_power;
wxStaticText* m_staticText10;
wxTextCtrl* m_genDc;
wxStaticText* m_staticText113;
wxStaticText* m_staticText11;
wxTextCtrl* m_genAcMag;
wxStaticText* m_staticText111;
wxStaticText* m_staticText12;
wxTextCtrl* m_genAcPhase;
wxStaticText* m_staticText112;
wxNotebook* m_powerNotebook;
wxPanel* m_pwrPulse;
wxStaticText* m_staticText13;
wxTextCtrl* m_pulseInit;
wxStaticText* m_staticText131;
wxStaticText* m_staticText14;
wxTextCtrl* m_pulseNominal;
wxStaticText* m_staticText132;
wxStaticText* m_staticText15;
wxTextCtrl* m_pulseDelay;
wxStaticText* m_staticText133;
wxStaticText* m_staticText16;
wxTextCtrl* m_pulseRise;
wxStaticText* m_staticText134;
wxStaticText* m_staticText17;
wxTextCtrl* m_pulseFall;
wxStaticText* m_staticText135;
wxStaticText* m_staticText18;
wxTextCtrl* m_pulseWidth;
wxStaticText* m_staticText136;
wxStaticText* m_staticText20;
wxTextCtrl* m_pulsePeriod;
wxStaticText* m_staticText137;
wxPanel* m_pwrSin;
wxStaticText* m_staticText21;
wxTextCtrl* m_sinOffset;
wxStaticText* m_staticText211;
wxStaticText* m_staticText22;
wxTextCtrl* m_sinAmplitude;
wxStaticText* m_staticText212;
wxStaticText* m_staticText23;
wxTextCtrl* m_sinFreq;
wxStaticText* m_staticText213;
wxStaticText* m_staticText24;
wxTextCtrl* m_sinDelay;
wxStaticText* m_staticText214;
wxStaticText* m_staticText25;
wxTextCtrl* m_sinDampFactor;
wxStaticText* m_staticText215;
wxPanel* m_pwrExp;
wxStaticText* m_staticText26;
wxTextCtrl* m_expInit;
wxStaticText* m_staticText261;
wxStaticText* m_staticText27;
wxTextCtrl* m_expPulsed;
wxStaticText* m_staticText262;
wxStaticText* m_staticText28;
wxTextCtrl* m_expRiseDelay;
wxStaticText* m_staticText263;
wxStaticText* m_staticText29;
wxTextCtrl* m_expRiseConst;
wxStaticText* m_staticText264;
wxStaticText* m_staticText30;
wxTextCtrl* m_expFallDelay;
wxStaticText* m_staticText265;
wxStaticText* m_staticText31;
wxTextCtrl* m_expFallConst;
wxStaticText* m_staticText266;
wxPanel* m_pwrPwl;
wxStaticText* m_staticText34;
wxTextCtrl* m_pwlTime;
wxStaticText* m_staticText342;
wxStaticText* m_staticText35;
wxTextCtrl* m_pwlValue;
wxStaticText* m_staticText343;
wxButton* m_pwlAddButton;
wxListCtrl* m_pwlValList;
wxButton* m_pwlRemoveBtn;
wxPanel* m_pwrFm;
wxStaticText* m_staticText138;
wxTextCtrl* m_fmOffset;
wxStaticText* m_staticText1311;
wxStaticText* m_staticText141;
wxTextCtrl* m_fmAmplitude;
wxStaticText* m_staticText1321;
wxStaticText* m_staticText151;
wxTextCtrl* m_fmFcarrier;
wxStaticText* m_staticText1331;
wxStaticText* m_staticText161;
wxTextCtrl* m_fmModIndex;
wxStaticText* m_staticText1341;
wxStaticText* m_staticText171;
wxTextCtrl* m_fmFsignal;
wxStaticText* m_staticText1351;
wxStaticText* m_staticText181;
wxTextCtrl* m_fmPhaseC;
wxStaticText* m_staticText1361;
wxStaticText* m_staticText201;
wxTextCtrl* m_fmPhaseS;
wxStaticText* m_staticText1371;
wxPanel* m_pwrAm;
wxStaticText* m_staticText1381;
wxTextCtrl* m_amAmplitude;
wxStaticText* m_staticText13111;
wxStaticText* m_staticText1411;
wxTextCtrl* m_amOffset;
wxStaticText* m_staticText13211;
wxStaticText* m_staticText1511;
wxTextCtrl* m_amModulatingFreq;
wxStaticText* m_staticText13311;
wxStaticText* m_staticText1611;
wxTextCtrl* m_amCarrierFreq;
wxStaticText* m_staticText13411;
wxStaticText* m_staticText1711;
wxTextCtrl* m_amSignalDelay;
wxStaticText* m_staticText13511;
wxStaticText* m_staticText1811;
wxTextCtrl* m_amPhase;
wxStaticText* m_staticText13611;
wxPanel* m_pwrTransNoise;
wxPanel* m_pwrRandom;
wxStaticText* m_staticText27111;
wxChoice* m_rnType;
wxStaticText* m_staticText26711;
wxTextCtrl* m_rnTS;
wxStaticText* m_staticText262111;
wxStaticText* m_staticText28111;
wxTextCtrl* m_rnTD;
wxStaticText* m_staticText263111;
wxStaticText* m_rnParam1Text;
wxTextCtrl* m_rnParam1;
wxStaticText* m_rnParam2Text;
wxTextCtrl* m_rnParam2;
wxPanel* m_pwrExtData;
wxRadioBox* m_pwrType;
wxPanel* m_tline;
wxNotebook* m_tlineNotebook;
wxPanel* m_tlineLossless;
wxStaticText* m_staticText2671111;
wxTextCtrl* m_tlineLosslessImpedance;
wxStaticText* m_staticText26211111;
wxStaticText* m_staticText26711111;
wxTextCtrl* m_tlineLosslessDelay;
wxStaticText* m_staticText262111111;
wxStaticText* m_staticText267111111;
wxTextCtrl* m_tlineLosslessFrequency;
wxStaticText* m_staticText2621111111;
wxStaticText* m_staticText2671111111;
wxTextCtrl* m_tlineLosslessWavelength;
wxRadioBox* m_tlineLosslessDelayMode;
wxPanel* m_tlineLossy;
wxStaticText* m_staticText26711112;
wxTextCtrl* m_tlineLossyR;
wxStaticText* m_staticText262111112;
wxStaticText* m_staticText267111112;
wxTextCtrl* m_tlineLossyL;
wxStaticText* m_staticText2621111112;
wxStaticText* m_staticText2671111112;
wxTextCtrl* m_tlineLossyC;
wxStaticText* m_staticText26211111111;
wxStaticText* m_staticText26711111111;
wxTextCtrl* m_tlineLossyG;
wxStaticText* m_staticText262111111111;
wxStaticText* m_staticText267111111111;
wxTextCtrl* m_tlineLossyLen;
wxStaticText* m_staticText262111111112;
wxStaticText* m_staticText2671111111111;
wxTextCtrl* m_tlineLossyParams;
wxStaticLine* m_staticline21;
wxStaticText* m_staticText1812;
wxStaticLine* m_staticline2;
wxCheckBox* m_disabled;
wxCheckBox* m_nodeSeqCheck;
wxTextCtrl* m_nodeSeqVal;
wxStaticLine* m_staticline3;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;
wxCheckBox* m_excludeSymbol;
wxStdDialogButtonSizer* m_sdbSizer1;
wxButton* m_sdbSizer1OK;
wxButton* m_sdbSizer1Cancel;
// Virtual event handlers, override them in your derived class
virtual void onInitDlg( wxInitDialogEvent& event ) { event.Skip(); }
virtual void onSelectLibrary( wxCommandEvent& event ) { event.Skip(); }
virtual void onModelSelected( wxCommandEvent& event ) { event.Skip(); }
virtual void onTypeSelected( wxCommandEvent& event ) { event.Skip(); }
virtual void onPwlAdd( wxCommandEvent& event ) { event.Skip(); }
virtual void onPwlRemove( wxCommandEvent& event ) { event.Skip(); }
virtual void onRandomSourceType( wxCommandEvent& event ) { event.Skip(); }
virtual void onDeviceTypeChoice( wxCommandEvent& event ) { event.Skip(); }
virtual void onTypeChoice( wxCommandEvent& event ) { event.Skip(); }
virtual void onGridCellChange( wxGridEvent& event ) { event.Skip(); }
public:
DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Spice Model Editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Spice Model Editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxSTAY_ON_TOP );
~DIALOG_SPICE_MODEL_BASE();

View File

@ -0,0 +1,371 @@
#!/bin/bash
# This script is disgusting (very slow and hacky). Please rewrite it in Python if you have time.
MODELS=$(cat << END
resistor R - R 2 0 0
capacitor C - C 2 0 0
inductor L - L 2 0 0
ltra LTRA - O 4 0 0
tranline - - T 4 0 0
urc URC - U 3 0 0
transline - - Y 4 0 0
diode D - D 2 0 0
bjt NPN PNP Q 3 1 0
vbic NPN PNP Q 3 4 0
hicum2 NPN PNP Q 3 8 0
jfet NJF PJF J 3 1 0
jfet2 NJF PJF J 3 2 0
mes NMF PMF Z 3 1 0
mesa NMF PMF Z 3 2 0
hfet1 NMF PMF Z 3 5 0
hfet2 NMF PMF Z 3 6 0
mos1 NMOS PMOS M 4 1 0
mos2 NMOS PMOS M 4 2 0
mos3 NMOS PMOS M 4 3 0
bsim1 NMOS PMOS M 4 4 0
bsim2 NMOS PMOS M 4 5 0
mos6 NMOS PMOS M 4 6 0
bsim3 NMOS PMOS M 4 8 3.3.0
mos9 NMOS PMOS M 4 9 0
b4soi NMOS PMOS M 4 10 0
bsim4 NMOS PMOS M 4 14 4.8.1
b3soifd NMOS PMOS M 4 55 0
b3soidd NMOS PMOS M 4 56 0
b3soipd NMOS PMOS M 4 57 0
hisim2 NMOS PMOS M 4 68 0
hisimhv1 NMOS PMOS M 4 73 1.2.4
hisimhv2 NMOS PMOS M 4 73 2.2.0
END
)
UNITS=$(cat << END
%/deg C
exponent alternative
-
exponent
ohm/m
sheet resistance
resistance per unit length
ohm
resistance
resistor model default value
F/m^2
cap per area
F/m
capacitance per meter
overlap cap
capacitance per unit length
capacitance grading coefficient per unit length
F
capacitance
cap\.
H
inductance
1/W
coef of thermal current reduction
sqrt V
bulk effect coefficient 1
bulk threshold parameter
1/V
channel length modulation
vgs dependence on mobility
V/cm
Crit. field for mob. degradation
V
voltage
potential
A/V^2
transconductance parameter
A/m^2
current density
A/m
current per unit length
A
current
ohm/deg C^2
second order temp. coefficient
ohm/deg C
first order temp. coefficient
1/deg C^2
grading coefficient 1st temp. coeff
1/deg C
grading coefficient 2nd temp. coeff
deg C/W
thermal resistance
deg C
temperature
eV
energy
cm^2/V^2 s
VBS dependence on muz
VBS dependence on mus
VDS dependence on mus
cm^2/V s
zero field mobility
surface mobility
um/V^2
VDS depence of u1
um
.* in um
1/cm^3
substrate doping
1/cm^2
surface state density
fast surface state density
m/s
velocity
m
length
width
thickness
narrowing of
shortening of
C
epi charge parameter
s
time
deg
excess phase
-
.*
END
)
run_ngspice()
{
ngspice -n 2>/dev/null << END
*
$1
.control
$2
.endc
END
}
{
echo "// Generated using the $(basename $0) script."
echo "// Modify that script instead of this file if you want to make changes."
echo ""
echo "#include <sim/ngspice.h>"
echo ""
echo "enum class NGSPICE::MODEL_TYPE"
echo "{"
echo "$MODELS" | while read -r model_name model_primitive model_level model_version; do
if [ -n "$model_name" ]; then
echo " ${model_name^^},"
fi
done
echo "};"
echo ""
echo "NGSPICE::MODEL_INFO NGSPICE::GetModelInfo( NGSPICE::MODEL_TYPE aType )"
echo "{"
echo " switch( aType )"
echo " {"
echo "$MODELS" | while read -r model_name \
model_type1 \
model_type2 \
model_primitive \
model_pin_count \
model_level \
model_version
do
if [ -n "$model_name" ]; then
# Print model description.
run_ngspice "" "devhelp -type $model_name" | while read -r name sep description; do
if [ "$sep" = "-" ]; then
echo -n " case NGSPICE::MODEL_TYPE::${model_name^^}:"
echo -n " return { \"$name\","
for model_type in "$model_type1" "$model_type2"; do
if [ "$model_type" != "-" ]; then
echo -n " \"$model_type\","
else
echo -n " \"\","
fi
done
echo " \"$description\","
fi
done
# Print model parameter ID, name, direction, type, unit, and description.
run_ngspice "" "devhelp -type $model_name" | while read -r param_id \
param_name \
param_dir \
param_type \
param_description
do
if [ "$param_id" = "Model" ] && [ "$param_name" = "Parameters" ]; then
echo " // Model parameters"
echo " {"
elif [ "$param_id" = "Instance" ] && [ "$param_name" = "Parameters" ]; then
echo " },"
echo " // Instance parameters"
echo " {"
elif [ "$param_id" -eq "$param_id" ] 2>/dev/null \
&& [ -n "$param_name" ] \
&& [ -n "$param_dir" ] \
&& [ -n "$param_description" ]
then
echo -n " { \"${param_name,,}\","
echo -n " { $param_id,"
echo -n " NGSPICE::PARAM_DIR::${param_dir^^},"
echo -n " NGSPICE::PARAM_TYPE::${param_type^^},"
unit=""
# Non-reals are unlikely to have units.
if [ "$param_type" = "real" ]; then
# Don't use a pipe here because it creates a subshell, as it prevents the
# changes to the variables from propagating upwards. Bash is cursed.
while read -r pattern; do
if [ "$unit" = "" ]; then
unit="$pattern"
elif [ -z "$pattern" ]; then
unit=""
elif grep -iE "$pattern" <<< "$param_description" >/dev/null; then
break
fi
done <<< "$UNITS"
fi
if [ "$unit" = "-" ]; then
unit=""
fi
echo -n " \"$unit\","
for model_type in "$model_type1" "$model_type2"; do
if [ "$model_type" = "-" ]; then
echo -n " \"\","
continue
fi
# For a given primitive, Ngspice determines the device model to be used
# from two parameters: "level" and "version".
params=""
if [ "$model_level" != 0 ]; then
params="$params level=$model_level"
fi
if [ "$model_version" != 0 ]; then
params="$params version=$model_version"
fi
netlist=$(cat << END
.model $model_type $model_type($params)
${model_primitive}1 $(seq -s ' ' $model_pin_count) $model_type
END
)
control=$(cat << END
op
showmod ${model_primitive}1 : $param_name
END
)
was_model_line=0
was_echoed=0
# Don't use a pipe here either.
while read -r name value; do
# Ngspice displays only the first 11 characters of the variable name.
# We also convert to lowercase because a few parameter names have
# uppercase characters in them.
lowercase_name=${name,,}
lowercase_param_name=${param_name,,}
if [ "$was_model_line" = 0 ] && [ "$lowercase_name" = "model" ]; then
was_model_line=1
elif [ "$was_model_line" = 1 ] \
&& [ "$lowercase_name" = "${lowercase_param_name:0:11}" ]
then
if [ "$value" = "<<NAN, error = 7>>" ]; then
value="NaN"
elif [ "$value" = "?????????" ]; then
value=""
fi
was_echoed=1
echo -n " \"$value\","
fi
done < <(run_ngspice "$netlist" "$control")
if [ "$was_echoed" = 0 ]; then
echo ""
echo "Error! Default value not found."
exit 1
fi
done
echo " \"$param_description\" } },"
fi
done
echo " } };"
fi
done
echo " }"
echo ""
echo " wxFAIL;"
echo " return {};"
echo "}"
} > $(dirname "$0")/ngspice_models.cpp

View File

@ -47,6 +47,56 @@ class wxDynamicLibrary;
class NGSPICE : public SPICE_SIMULATOR
{
public:
enum class PARAM_DIR
{
IN,
OUT,
INOUT
};
enum class PARAM_TYPE
{
FLAG,
INTEGER,
REAL,
COMPLEX,
NODE,
INSTANCE,
STRING,
PARSETREE,
VECTOR,
FLAGVEC,
INTVEC,
REALVEC,
CPLXVEC,
NODEVEC,
INSTVEC,
STRINGVEC
};
struct PARAM_INFO
{
unsigned int id;
PARAM_DIR dir;
PARAM_TYPE type;
wxString unit;
wxString defaultValueOfVariant1;
wxString defaultValueOfVariant2;
wxString description;
};
enum class MODEL_TYPE; // Defined in ngspice_devices.cpp.
struct MODEL_INFO
{
wxString name;
wxString variant1;
wxString variant2;
wxString description;
std::map<wxString, PARAM_INFO> modelParams;
std::map<wxString, PARAM_INFO> instanceParams;
};
NGSPICE();
virtual ~NGSPICE();
@ -92,6 +142,8 @@ public:
///< @copydoc SPICE_SIMULATOR::GetPhasePlot()
std::vector<double> GetPhasePlot( const std::string& aName, int aMaxLen = -1 ) override final;
MODEL_INFO GetModelInfo( MODEL_TYPE aDeviceType );
std::vector<std::string> GetSettingCommands() const override final;
///< @copydoc SPICE_SIMULATOR::GetNetlist()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,309 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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 <iterator>
#include <sim/spice_model.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
#include <locale_io.h>
#include <lib_symbol.h>
/*namespace SPICE_MODEL_PARSER
{
using namespace tao::pegtl;
struct directive : sor<TAO_PEGTL_ISTRING( ".model" ),
TAO_PEGTL_ISTRING( ".param" ),
TAO_PEGTL_ISTRING( ".subckt" )> {};*//*
struct spaces : star<space> {};
struct identifierNotFirstChar : sor<alnum, one<'!', '#', '$', '%', '[', ']', '_'>> {};
struct identifier : seq<alpha, star<identifierNotFirstChar>> {};
struct digits : plus<digit> {};
struct sign : opt<one<'+', '-'>> {};
struct significand : sor<seq<digits, one<'.'>, opt<digits>>, seq<one<'.'>, digits>> {};
struct exponent : opt<one<'e', 'E'>, sign, digits> {};
struct metricSuffix : sor<TAO_PEGTL_ISTRING( "T" ),
TAO_PEGTL_ISTRING( "G" ),
TAO_PEGTL_ISTRING( "Meg" ),
TAO_PEGTL_ISTRING( "K" ),
TAO_PEGTL_ISTRING( "mil" ),
TAO_PEGTL_ISTRING( "m" ),
TAO_PEGTL_ISTRING( "u" ),
TAO_PEGTL_ISTRING( "n" ),
TAO_PEGTL_ISTRING( "p" ),
TAO_PEGTL_ISTRING( "f" )> {};
struct number : seq<sign, significand, exponent, metricSuffix> {};
struct modelModelType : sor<TAO_PEGTL_ISTRING( "R" ),
TAO_PEGTL_ISTRING( "C" ),
TAO_PEGTL_ISTRING( "L" ),
TAO_PEGTL_ISTRING( "SW" ),
TAO_PEGTL_ISTRING( "CSW" ),
TAO_PEGTL_ISTRING( "URC" ),
TAO_PEGTL_ISTRING( "LTRA" ),
TAO_PEGTL_ISTRING( "D" ),
TAO_PEGTL_ISTRING( "NPN" ),
TAO_PEGTL_ISTRING( "PNP" ),
TAO_PEGTL_ISTRING( "NJF" ),
TAO_PEGTL_ISTRING( "PJF" ),
TAO_PEGTL_ISTRING( "NMOS" ),
TAO_PEGTL_ISTRING( "PMOS" ),
TAO_PEGTL_ISTRING( "NMF" ),
TAO_PEGTL_ISTRING( "PMF" ),
TAO_PEGTL_ISTRING( "VDMOS" )> {};
struct paramValuePair : seq<alnum, spaces, one<'='>, spaces, number> {};
struct paramValuePairs : opt<paramValuePair, star<spaces, paramValuePair>> {};
struct modelModelSpec : seq<modelModelType,
spaces,
one<'('>,
spaces,
paramValuePairs,
spaces,
one<')'>,
spaces> {};
struct modelModel : seq<TAO_PEGTL_ISTRING( ".model" ), identifier, modelModelSpec> {};
struct model : modelModel {};
//struct model : sor<modelModel, paramModel, subcircuitModel> {};
}*/
namespace SPICE_MODEL_PARSER
{
using namespace tao::pegtl;
struct spaces : star<space> {};
struct digits : plus<digit> {};
struct sign : opt<one<'+', '-'>> {};
struct significand : sor<seq<digits, opt<one<'.'>, opt<digits>>>, seq<one<'.'>, digits>> {};
struct exponent : opt<one<'e', 'E'>, sign, digits> {};
struct metricSuffix : opt<sor<TAO_PEGTL_ISTRING( "T" ),
TAO_PEGTL_ISTRING( "G" ),
TAO_PEGTL_ISTRING( "Meg" ),
TAO_PEGTL_ISTRING( "K" ),
TAO_PEGTL_ISTRING( "mil" ),
TAO_PEGTL_ISTRING( "m" ),
TAO_PEGTL_ISTRING( "u" ),
TAO_PEGTL_ISTRING( "n" ),
TAO_PEGTL_ISTRING( "p" ),
TAO_PEGTL_ISTRING( "f" )>> {};
// TODO: Move the `number` grammar to the SPICE_VALUE class.
struct number : seq<sign, significand, exponent, metricSuffix> {};
struct param : seq<alnum> {};
struct paramValuePair : seq<param, spaces, one<'='>, spaces, number> {};
struct paramValuePairs : opt<paramValuePair, star<spaces, paramValuePair>> {};
template <typename Rule> struct paramValuePairsSelector : std::false_type {};
template <> struct paramValuePairsSelector<param> : std::true_type {};
template <> struct paramValuePairsSelector<number> : std::true_type {};
}
template SPICE_MODEL::TYPE SPICE_MODEL::ReadTypeFromFields( const std::vector<SCH_FIELD>* aFields );
template SPICE_MODEL::TYPE SPICE_MODEL::ReadTypeFromFields( const std::vector<LIB_FIELD>* aFields );
template <typename T>
SPICE_MODEL::TYPE SPICE_MODEL::ReadTypeFromFields( const std::vector<T>* aFields )
{
wxString typeFieldValue = getFieldValue( aFields, TYPE_FIELD );
wxString deviceTypeFieldValue = getFieldValue( aFields, DEVICE_TYPE_FIELD );
bool typeFound = false;
for( TYPE type : TYPE_ITERATOR() )
{
if( typeFieldValue == TypeInfo( type ).fieldValue )
{
typeFound = true;
if( deviceTypeFieldValue == DeviceTypeInfo( TypeInfo( type ).deviceType ).fieldValue )
return type;
}
}
if( !typeFound )
throw KI_PARAM_ERROR( wxString::Format( _( "Invalid \"%s\" field value: \"%s\"" ),
TYPE_FIELD, typeFieldValue ) );
throw KI_PARAM_ERROR( wxString::Format( _( "Invalid \"%s\" field value: \"%s\"" ),
DEVICE_TYPE_FIELD, deviceTypeFieldValue ) );
}
SPICE_MODEL::SPICE_MODEL( TYPE aType ) : m_type( aType )
{
}
template SPICE_MODEL::SPICE_MODEL( const std::vector<SCH_FIELD>* aFields );
template SPICE_MODEL::SPICE_MODEL( const std::vector<LIB_FIELD>* aFields );
template <typename T>
SPICE_MODEL::SPICE_MODEL( const std::vector<T>* aFields )
: m_type( ReadTypeFromFields( aFields ) )
{
SetFile( getFieldValue( aFields, "Model_File" ) );
parseParamValuePairs( getFieldValue( aFields, "Model_Params" ) );
}
SPICE_MODEL::SPICE_MODEL( const wxString& aCode )
{
}
template void SPICE_MODEL::WriteFields( std::vector<SCH_FIELD>* aFields );
template void SPICE_MODEL::WriteFields( std::vector<LIB_FIELD>* aFields );
template <typename T>
void SPICE_MODEL::WriteFields( std::vector<T>* aFields )
{
setFieldValue( aFields, DEVICE_TYPE_FIELD,
DeviceTypeInfo( TypeInfo( m_type ).deviceType ).fieldValue );
setFieldValue( aFields, TYPE_FIELD, TypeInfo( m_type ).fieldValue );
setFieldValue( aFields, FILE_FIELD, GetFile() );
setFieldValue( aFields, PARAMS_FIELD, generateParamValuePairs() );
}
void SPICE_MODEL::WriteCode( wxString& aCode )
{
}
void SPICE_MODEL::parseParamValuePairs( const wxString& aParamValuePairs )
{
LOCALE_IO toggle;
tao::pegtl::string_input<> in( aParamValuePairs.ToStdString(), "from_input" );
auto root = tao::pegtl::parse_tree::parse<SPICE_MODEL_PARSER::paramValuePairs,
SPICE_MODEL_PARSER::paramValuePairsSelector>( in );
wxString paramName = "";
for( const auto& node : root->children )
{
if( node->is_type<SPICE_MODEL_PARSER::param>() )
paramName = node->string();
else if( node->is_type<SPICE_MODEL_PARSER::number>() )
{
wxASSERT( paramName != "" );
try
{
SPICE_VALUE value( node->string() );
/*if( !SetParamValue( paramName, value ) )
{
m_params.clear();
throw KI_PARAM_ERROR( wxString::Format( _( "Unknown parameter \"%s\"" ),
paramName ) );
}*/
}
catch( KI_PARAM_ERROR& e )
{
m_params.clear();
throw KI_PARAM_ERROR( wxString::Format( _( "Invalid \"%s\" parameter value: \"%s\"" ),
paramName, e.What() ) );
}
}
else
wxFAIL;
}
}
wxString SPICE_MODEL::generateParamValuePairs()
{
wxString result = "";
/*for( auto it = GetParams().cbegin(); it != GetParams().cend(); it++ )
{
result += it->first;
result += "=";
result += it->second.value.ToString();
if( std::next( it ) != GetParams().cend() )
result += " ";
}*/
return result;
}
template <typename T>
wxString SPICE_MODEL::getFieldValue( const std::vector<T>* aFields, const wxString& aFieldName )
{
static_assert( std::is_same<T, SCH_FIELD>::value || std::is_same<T, LIB_FIELD>::value );
auto fieldIt = std::find_if( aFields->begin(), aFields->end(),
[&]( const T& f )
{
return f.GetName() == aFieldName;
} );
if( fieldIt != aFields->end() )
return fieldIt->GetText();
return wxEmptyString;
}
template <typename T>
void SPICE_MODEL::setFieldValue( std::vector<T>* aFields, const wxString& aFieldName,
const wxString& aValue )
{
static_assert( std::is_same<T, SCH_FIELD>::value || std::is_same<T, LIB_FIELD>::value );
auto fieldIt = std::find_if( aFields->begin(), aFields->end(),
[&]( const T& f )
{
return f.GetName() == aFieldName;
} );
if( fieldIt != aFields->end() )
{
fieldIt->SetText( aValue );
return;
}
if constexpr( std::is_same<T, SCH_FIELD>::value )
{
wxASSERT( aFields->size() >= 1 );
SCH_ITEM* parent = static_cast<SCH_ITEM*>( aFields->at( 0 ).GetParent() );
aFields->emplace_back( wxPoint(), aFields->size(), parent, aFieldName );
}
else if constexpr( std::is_same<T, LIB_FIELD>::value )
aFields->emplace_back( aFields->size(), aFieldName );
aFields->back().SetText( aValue );
}

287
eeschema/sim/spice_model.h Normal file
View File

@ -0,0 +1,287 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* 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_MODEL_H
#define SPICE_MODEL_H
#include <map>
#include <stdexcept>
#include <enum_vector.h>
#include <sch_field.h>
#include <lib_field.h>
#include <sim/ngspice.h>
#include <sim/spice_value.h>
#include <wx/string.h>
class SPICE_MODEL
{
public:
static constexpr auto DEVICE_TYPE_FIELD = "Model_Device";
static constexpr auto TYPE_FIELD = "Model_Type";
static constexpr auto FILE_FIELD = "Model_File";
static constexpr auto PARAMS_FIELD = "Model_Params";
/*struct PARAM
{
SPICE_VALUE value;
wxString description;
wxString unit;
};*/
DEFINE_ENUM_CLASS_WITH_ITERATOR( DEVICE_TYPE,
NONE,
RESISTOR,
CAPACITOR,
INDUCTOR,
TLINE,
DIODE,
BJT,
JFET,
MESFET,
MOSFET,
VSOURCE,
ISOURCE,
SUBCIRCUIT,
CODEMODEL,
RAWSPICE
)
struct DEVICE_TYPE_INFO
{
wxString fieldValue;
wxString description;
};
static DEVICE_TYPE_INFO DeviceTypeInfo( DEVICE_TYPE aDeviceType )
{
switch( aDeviceType )
{
case DEVICE_TYPE::NONE: return {"", ""};
case DEVICE_TYPE::RESISTOR: return {"RESISTOR", "Resistor"};
case DEVICE_TYPE::CAPACITOR: return {"CAPACITOR", "Capacitor"};
case DEVICE_TYPE::INDUCTOR: return {"INDUCTOR", "Inductor"};
case DEVICE_TYPE::TLINE: return {"TLINE", "Transmission Line"};
case DEVICE_TYPE::DIODE: return {"DIODE", "Diode"};
case DEVICE_TYPE::BJT: return {"BJT", "BJT"};
case DEVICE_TYPE::JFET: return {"JFET", "JFET"};
case DEVICE_TYPE::MOSFET: return {"MOSFET", "MOSFET"};
case DEVICE_TYPE::MESFET: return {"MESFET", "MESFET"};
case DEVICE_TYPE::VSOURCE: return {"VSOURCE", "Voltage Source"};
case DEVICE_TYPE::ISOURCE: return {"ISOURCE", "Current Source"};
case DEVICE_TYPE::SUBCIRCUIT: return {"SUBCIRCUIT", "Subcircuit"};
case DEVICE_TYPE::CODEMODEL: return {"CODEMODEL", "Code Model"};
case DEVICE_TYPE::RAWSPICE: return {"RAWSPICE", "Raw Spice Element"};
case DEVICE_TYPE::_ENUM_END: break;
}
wxFAIL;
return {};
}
DEFINE_ENUM_CLASS_WITH_ITERATOR( TYPE,
NONE,
RESISTOR_IDEAL,
RESISTOR_SEMICONDUCTOR,
CAPACITOR_IDEAL,
CAPACITOR_SEMICONDUCTOR,
INDUCTOR_IDEAL,
INDUCTOR_IDEAL_COIL,
TLINE_LOSSY,
TLINE_LOSSLESS,
TLINE_DISTRIBUTED_RC,
TLINE_KSPICE_LOSSY,
DIODE,
BJT_GUMMEL_POON,
BJT_VBIC,
//BJT_MEXTRAM,
BJT_HICUM_L2,
//BJT_HICUM_L0,
JFET_SHICHMAN_HODGES,
JFET_PARKER_SKELLERN,
MESFET_STATZ,
MESFET_YTTERDAL,
MESFET_HFET1,
MESFET_HFET2,
MOSFET_MOS1,
MOSFET_MOS2,
MOSFET_MOS3,
MOSFET_BSIM1,
MOSFET_BSIM2,
MOSFET_MOS6,
MOSFET_MOS9,
MOSFET_BSIM3,
MOSFET_B4SOI,
MOSFET_BSIM4,
//MOSFET_EKV2_6,
//MOSFET_PSP,
MOSFET_B3SOIFD,
MOSFET_B3SOIDD,
MOSFET_B3SOIPD,
//MOSFET_STAG,
MOSFET_HISIM2,
MOSFET_HISIM_HV,
VSOURCE,
ISOURCE,
SUBCIRCUIT,
CODEMODEL,
RAWSPICE
)
struct TYPE_INFO
{
DEVICE_TYPE deviceType;
//NGSPICE::MODEL_TYPE ngspiceModelType;
wxString ngspicePrimitive;
unsigned int ngspiceLevel;
wxString fieldValue;
wxString description;
};
static TYPE_INFO TypeInfo( TYPE aType )
{
switch( aType )
{
case TYPE::NONE: return { DEVICE_TYPE::NONE, "", 0, "", "" };
case TYPE::RESISTOR_IDEAL: return { DEVICE_TYPE::RESISTOR, "R", 0, "IDEAL", "Ideal model" };
case TYPE::RESISTOR_SEMICONDUCTOR: return { DEVICE_TYPE::RESISTOR, "R", 0, "SEMICONDUCTOR", "Semiconductor model" };
case TYPE::CAPACITOR_IDEAL: return { DEVICE_TYPE::CAPACITOR, "C", 0, "IDEAL", "Ideal model" };
case TYPE::CAPACITOR_SEMICONDUCTOR: return { DEVICE_TYPE::CAPACITOR, "C", 0, "SEMICONDUCTOR", "Semiconductor model" };
case TYPE::INDUCTOR_IDEAL: return { DEVICE_TYPE::INDUCTOR, "L", 0, "IDEAL", "Ideal model" };
case TYPE::INDUCTOR_IDEAL_COIL: return { DEVICE_TYPE::INDUCTOR, "L", 0, "LOSSLESS_COIL", "Lossless coil model" };
case TYPE::TLINE_LOSSY: return { DEVICE_TYPE::TLINE, "O", 0, "LOSSY", "Lossy model" };
case TYPE::TLINE_LOSSLESS: return { DEVICE_TYPE::TLINE, "T", 0, "LOSSLESS", "Lossless model" };
case TYPE::TLINE_DISTRIBUTED_RC: return { DEVICE_TYPE::TLINE, "U", 0, "DISTRIBUTED_RC", "Uniformly distributed RC model" };
case TYPE::TLINE_KSPICE_LOSSY: return { DEVICE_TYPE::TLINE, "Y", 0, "KSPICE_LOSSY", "KSPICE lossy model" };
case TYPE::DIODE: return { DEVICE_TYPE::DIODE, "D", 0, "", "" };
case TYPE::BJT_GUMMEL_POON: return { DEVICE_TYPE::BJT, "Q", 1, "GUMMEL_POON", "Gummel-Poon model" };
case TYPE::BJT_VBIC: return { DEVICE_TYPE::BJT, "Q", 4, "VBIC", "VBIC model" };
//case TYPE::BJT_MEXTRAM: return { DEVICE_TYPE::BJT, "Q", 6, "MEXTRAM", "MEXTRAM model" };
case TYPE::BJT_HICUM_L2: return { DEVICE_TYPE::BJT, "Q", 8, "HICUM_L2", "HICUM Level 2 model" };
//case TYPE::BJT_HICUM_L0: return { DEVICE_TYPE::BJT, "Q", 7, "HICUM_L0", "HICUM Level 0 model" };
case TYPE::JFET_SHICHMAN_HODGES: return { DEVICE_TYPE::JFET, "J", 1, "SHICHMAN_HODGES", "Shichman-Hodges model" };
case TYPE::JFET_PARKER_SKELLERN: return { DEVICE_TYPE::JFET, "J", 2, "PARKER_SKELLERN", "Parker-Skellern model" };
case TYPE::MESFET_STATZ: return { DEVICE_TYPE::MESFET, "Z", 1, "STATZ", "Statz model" };
case TYPE::MESFET_YTTERDAL: return { DEVICE_TYPE::MESFET, "Z", 2, "YTTERDAL", "Ytterdal model" };
case TYPE::MESFET_HFET1: return { DEVICE_TYPE::MESFET, "Z", 5, "HFET1", "HFET1 model" };
case TYPE::MESFET_HFET2: return { DEVICE_TYPE::MESFET, "Z", 6, "HFET2", "HFET2 model" };
case TYPE::MOSFET_MOS1: return { DEVICE_TYPE::MOSFET, "M", 1, "MOS1", "Classical quadratic model (MOS1)" };
case TYPE::MOSFET_MOS2: return { DEVICE_TYPE::MOSFET, "M", 2, "MOS2", "Grove-Frohman model (MOS2)" };
case TYPE::MOSFET_MOS3: return { DEVICE_TYPE::MOSFET, "M", 3, "MOS3", "MOS3 model" };
case TYPE::MOSFET_BSIM1: return { DEVICE_TYPE::MOSFET, "M", 4, "BSIM1", "BSIM1 model" };
case TYPE::MOSFET_BSIM2: return { DEVICE_TYPE::MOSFET, "M", 5, "BSIM2", "BSIM2 model" };
case TYPE::MOSFET_MOS6: return { DEVICE_TYPE::MOSFET, "M", 6, "MOS6", "MOS6 model" };
case TYPE::MOSFET_BSIM3: return { DEVICE_TYPE::MOSFET, "M", 8, "BSIM3", "BSIM3 model" };
case TYPE::MOSFET_MOS9: return { DEVICE_TYPE::MOSFET, "M", 9, "MOS9", "MOS9 model" };
case TYPE::MOSFET_B4SOI: return { DEVICE_TYPE::MOSFET, "M", 10, "B4SOI", "BSIM4 SOI model (B4SOI)" };
case TYPE::MOSFET_BSIM4: return { DEVICE_TYPE::MOSFET, "M", 14, "BSIM4", "BSIM4 model" };
//case TYPE::MOSFET_EKV2_6: return { DEVICE_TYPE::MOSFET, "M", 44, "EKV2.6", "EKV2.6 model" };
//case TYPE::MOSFET_PSP: return { DEVICE_TYPE::MOSFET, "M", 45, "PSP", "PSP model" };
case TYPE::MOSFET_B3SOIFD: return { DEVICE_TYPE::MOSFET, "M", 55, "B3SOIFD", "B3SOIFD (BSIM3 fully depleted SOI) model" };
case TYPE::MOSFET_B3SOIDD: return { DEVICE_TYPE::MOSFET, "M", 56, "B3SOIDD", "B3SOIDD (BSIM3 SOI, both fully and partially depleted) model" };
case TYPE::MOSFET_B3SOIPD: return { DEVICE_TYPE::MOSFET, "M", 57, "B3SOIPD", "B3SOIPD (BSIM3 partially depleted SOI) model" };
//case TYPE::MOSFET_STAG: return { DEVICE_TYPE::MOSFET, "M", 60, "STAG", "STAG model" };
case TYPE::MOSFET_HISIM2: return { DEVICE_TYPE::MOSFET, "M", 68, "HiSIM2", "HiSIM2 model" };
case TYPE::MOSFET_HISIM_HV: return { DEVICE_TYPE::MOSFET, "M", 73, "HiSIM_HV", "HiSIM_HV model" };
case TYPE::VSOURCE: return { DEVICE_TYPE::VSOURCE, "V", 0, "", "" };
case TYPE::ISOURCE: return { DEVICE_TYPE::ISOURCE, "V", 0, "", "" };
case TYPE::SUBCIRCUIT: return { DEVICE_TYPE::SUBCIRCUIT, "X", 0, "", "" };
case TYPE::CODEMODEL: return { DEVICE_TYPE::CODEMODEL, "A", 0, "", "" };
case TYPE::RAWSPICE: return { DEVICE_TYPE::RAWSPICE, "", 0, "", "" };
case TYPE::_ENUM_END: break;
}
wxFAIL;
return { };
}
template <typename T>
static TYPE ReadTypeFromFields( const std::vector<T>* aFields );
SPICE_MODEL( TYPE aType );
template <typename T>
SPICE_MODEL( const std::vector<T>* aFields );
SPICE_MODEL( const wxString& aCode );
template <typename T>
void WriteFields( std::vector<T>* aFields );
void WriteCode( wxString& aCode );
wxString GetFile() { return m_file; }
void SetFile( const wxString& aFile ) { m_file = aFile; }
private:
TYPE m_type;
wxString m_file;
std::map<wxString, double> m_params;
template <typename T>
static wxString getFieldValue( const std::vector<T>* aFields, const wxString& aFieldName );
template <typename T>
static void setFieldValue( std::vector<T>* aFields, const wxString& aFieldName,
const wxString& aValue );
wxString generateParamValuePairs();
void parseParamValuePairs( const wxString& aParamValuePairs );
};
#endif /* SPICE_MODEL_H */

View File

@ -18,29 +18,74 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEFINE_ENUM_VECTOR
#ifndef ENUM_VECTOR_H
#define ENUM_VECTOR_H
#include <type_traits>
/**
* Macro to create const vectors containing enum values to enable easy iteration.
* Macro to create const vectors containing enum values to enable easy iteration. Do not use in new
* code. Use the DEFINE_ENUM_CLASS_WITH_ITERATOR and DECLARE_ENUM_CLASS_ITERATOR macros instead
* (unless they don't work ;) ).
*
* Usage:
* [header]
* A {
* DEFINE_ENUM_VECTOR( COLORS, { RED, GREEN, BLUE } );
* DEFINE_ENUM_VECTOR( COLOR, { RED, GREEN, BLUE } )
* };
*
* [source]
* for( auto color : A::COLORS_vector ) {
* for( COLOR color : COLOR_vector ) {
* // do sth with color
* }
*
* DECLARE_ENUM_VECTOR( COLORS );
*/
#define DEFINE_ENUM_VECTOR(enum_name, ...) \
enum enum_name __VA_ARGS__; \
static constexpr enum_name enum_name##_vector[] = __VA_ARGS__;
#define DEFINE_ENUM_VECTOR( enumName, ... ) \
enum enumName __VA_ARGS__; \
static constexpr enumName enumName##_vector[] = __VA_ARGS__;
#define DECLARE_ENUM_VECTOR(class_name, enum_name) \
constexpr class_name::enum_name class_name::enum_name##_vector[];
#define DECLARE_ENUM_VECTOR( className, enumName ) \
constexpr className::enumName className::enumName##_vector[];
#endif
/**
* Macro to create const vectors containing enum class values to enable easy iteration.
*
* Usage:
* [header]
* A {
* DEFINE_ENUM_CLASS_WITH_ITERATOR( COLOR, RED, GREEN, BLUE )
* };
*
* [source]
* for( COLOR color : COLOR_ITERATOR() ) {
* // do sth with color
* }
*/
#define DEFINE_ENUM_CLASS_WITH_ITERATOR( enumName, beginVal, ... ) \
enum class enumName : int { beginVal, __VA_ARGS__, _ENUM_END }; \
typedef ENUM_ITERATOR<enumName, enumName::beginVal, enumName::_ENUM_END> enumName##_ITERATOR;
template <typename T, T beginVal, T endVal>
class ENUM_ITERATOR
{
typedef typename std::underlying_type<T>::type val_t;
int val;
public:
ENUM_ITERATOR( const T& f ) : val( static_cast<val_t>( f ) ) {}
ENUM_ITERATOR() : val( static_cast<val_t>( beginVal ) ) {}
ENUM_ITERATOR operator++()
{
val++;
return *this;
}
T operator*() { return static_cast<T>( val ); }
ENUM_ITERATOR begin() { return *this; }
ENUM_ITERATOR end() { return ENUM_ITERATOR( endVal ); }
bool operator!=( const ENUM_ITERATOR& aIt ) { return val != aIt.val; }
};
#endif /* ENUM_VECTOR_H */