ngspice: something starts to work

This commit is contained in:
Tomasz Wlostowski 2016-08-11 14:41:01 +02:00 committed by Maciej Suminski
parent 2dd53b6a43
commit f1f69979e6
20 changed files with 1421 additions and 15 deletions

View File

@ -247,6 +247,7 @@ KIWAY::FACE_T KIWAY::KifaceType( FRAME_T aFrameType )
case FRAME_SCH_LIB_EDITOR:
case FRAME_SCH_VIEWER:
case FRAME_SCH_VIEWER_MODAL:
case FRAME_SIMULATOR:
return FACE_SCH;
case FRAME_PCB:
@ -301,6 +302,7 @@ KIWAY_PLAYER* KIWAY::Player( FRAME_T aFrameType, bool doCreate, KIWAY_PLAYER* aP
return NULL;
}
printf("Player %d\n", aFrameType);
// return the previously opened window
KIWAY_PLAYER* frame = GetPlayerFrame( aFrameType );

View File

@ -177,7 +177,9 @@ set( EESCHEMA_SRCS
viewlib_frame.cpp
viewlibs.cpp
sim/simulate.cpp
sim/dialog_simulate_plot.cpp
sim/sim_plot_frame_base.cpp
sim/sim_plot_frame.cpp
sim/sim_plot_panel.cpp
sim/ngspice.cpp
netlist_exporters/netlist_exporter.cpp
@ -246,11 +248,11 @@ set_source_files_properties( ../common/single_top.cpp PROPERTIES
COMPILE_DEFINITIONS "TOP_FRAME=FRAME_SCH;PGM_DATA_FILE_EXT=\"sch\";BUILD_KIWAY_DLL"
)
if (KICAD_SPICE)
#if (KICAD_SPICE)
set ( EESCHEMA_LINK_LIBS ${wxWidgets_LIBRARIES} mgl mgl-wx)
else()
set ( EESCHEMA_LINK_LIBS ${wxWidgets_LIBRARIES} )
endif()
#else()
# set ( EESCHEMA_LINK_LIBS ${wxWidgets_LIBRARIES} )
#endif()
target_link_libraries( eeschema
#singletop # replaces common, giving us restrictive control and link warnings.

6
eeschema/diodes.lib Normal file
View File

@ -0,0 +1,6 @@
* Copyright © 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Linear Technology Corporation. All rights reserved.
*
* Mike Engelhardt
*
.model 1N914 D(Is=2.52n Rs=.568 N=1.752 Cjo=4p M=.4 tt=20n Iave=200m Vpk=75)
.model 1N4148 D(Is=2.52n Rs=.568 N=1.752 Cjo=4p M=.4 tt=20n Iave=200m Vpk=75)

View File

@ -46,6 +46,7 @@
#include <wildcards_and_files_ext.h>
#include <kiway.h>
#include <sim/sim_plot_frame.h>
// The main sheet of the project
SCH_SHEET* g_RootSheet = NULL;
@ -70,6 +71,8 @@ static struct IFACE : public KIFACE_I
wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 )
{
printf("Create class %d\n", aClassId);
switch( aClassId )
{
case FRAME_SCH:
@ -92,6 +95,12 @@ static struct IFACE : public KIFACE_I
}
break;
case FRAME_SIMULATOR:
{
SIM_PLOT_FRAME_BASE* frame = new SIM_PLOT_FRAME( aKiway, aParent );
return frame;
}
break;
case FRAME_SCH_VIEWER:
case FRAME_SCH_VIEWER_MODAL:
@ -238,4 +247,3 @@ void IFACE::OnKifaceEnd()
wxConfigSaveSetups( KifaceSettings(), cfg_params() );
end_common();
}

View File

@ -61,7 +61,7 @@ bool NETLIST_EXPORTER_PSPICE::Format( OUTPUTFORMATTER* formatter, int aCtl )
wxString delimeters = wxT( "{:,; }" );
wxString disableStr = wxT( "N" );
std::map<wxString, int> netIndices;
//std::map<wxString, int> netIndices;
// Prepare list of nets generation (not used here, but...
for( unsigned ii = 0; ii < m_masterList->size(); ii++ )
@ -74,9 +74,12 @@ bool NETLIST_EXPORTER_PSPICE::Format( OUTPUTFORMATTER* formatter, int aCtl )
SCH_SHEET_LIST sheetList( g_RootSheet );
std::vector<wxString> directives;
std::vector<wxString> probeNets;
netIndices["GND"] = 0;
formatter->Print(0, "Kicad schematic\n");
m_probes.clear();
m_netMap.clear();
m_netMap["GND"] = 0;
for( unsigned i = 0; i < sheetList.size(); i++ )
{
@ -216,9 +219,9 @@ bool NETLIST_EXPORTER_PSPICE::Format( OUTPUTFORMATTER* formatter, int aCtl )
{
NETLIST_OBJECT* pin = m_SortedComponentPinList[0];
printf("Probe net: %s\n", (const char*) pin->GetNetName().c_str() );
//printf("Probe net: %s\n", (const char*) pin->GetNetName().c_str() );
probeNets.push_back(pin->GetNetName());
m_probes.push_back(pin->GetNetName());
continue;
}
@ -271,12 +274,12 @@ bool NETLIST_EXPORTER_PSPICE::Format( OUTPUTFORMATTER* formatter, int aCtl )
wxString netName = pin->GetNetName();
int netIdx;
if (netIndices.find(netName) == netIndices.end())
if (m_netMap.find(netName) == m_netMap.end())
{
netIdx = curNetIndex++;
netIndices[netName] = netIdx;
m_netMap[netName] = netIdx;
} else {
netIdx = netIndices[netName];
netIdx = m_netMap[netName];
}
//printf("net %s index %d\n", (const char*)netName.c_str(), netIdx);
@ -302,6 +305,14 @@ bool NETLIST_EXPORTER_PSPICE::Format( OUTPUTFORMATTER* formatter, int aCtl )
}
for( auto dir : directives )
{
formatter->Print(0, "%s\n", (const char *)dir.c_str());
}
formatter->Print(0, ".end\n");
#if 0
m_SortedComponentPinList.clear();

View File

@ -27,6 +27,7 @@
#define NETLIST_EXPORTER_PSPICE_H
#include "netlist_exporter.h"
#include <map>
/**
* Class NETLIST_EXPORTER_PSPICE
@ -40,6 +41,9 @@ public:
{
}
typedef std::map<wxString, int> NetIndexMap;
typedef std::vector<wxString> ProbeList;
/**
* Function WriteNetlist
* writes to specified output file
@ -48,6 +52,22 @@ public:
bool Format( OUTPUTFORMATTER* aOutputFormatter, int aCtl );
const NetIndexMap& GetNetIndexMap ( ) const
{
return m_netMap;
}
const ProbeList& GetProbeList() const
{
return m_probes;
}
private:
NetIndexMap m_netMap;
ProbeList m_probes;
};
#endif

View File

@ -0,0 +1,328 @@
/* header file for shared ngspice */
/* Copyright 2013 Holger Vogt */
/* Modified BSD license */
/*
Interface between a calling program (caller) and ngspice.dll (ngspice.so)
**
ngSpice_Init(SendChar*, SendStat*, ControlledExit*,
SendData*, SendInitData*, BGThreadRunning*, void*)
After caller has loaded ngspice.dll, the simulator has to be initialized
by calling ngSpice_Init(). Address pointers of several callback functions
defined in the caller are sent to ngspice.dll.
Callback funtion typedefs
SendChar typedef of callback function for reading printf, fprintf, fputs
SendStat typedef of callback function for reading status string and precent value
ControlledExit typedef of callback function for tranferring a signal upon
ngspice controlled_exit to caller. May be used by caller
to detach ngspice.dll.
SendData typedef of callback function for sending an array of structs containing
data values of all vectors in the current plot (simulation output)
SendInitData typedef of callback function for sending an array of structs containing info on
all vectors in the current plot (immediately before simulation starts)
BGThreadRunning typedef of callback function for sending a boolean signal (true if thread
is running)
The void pointer may contain the object address of the calling
function ('self' or 'this' pointer), so that the answer may be directed
to a calling object. Callback functions are defined in the global section.
**
ngSpice_Command(char*)
Send a valid command (see the control or interactive commands) from caller
to ngspice.dll. Will be executed immediately (as if in interactive mode).
Some commands are rejected (e.g. 'plot', because there is no graphics interface).
Command 'quit' will remove internal data, and then send a notice to caller via
ngexit().
**
ngGet_Vec_Info(char*)
receives the name of a vector (may be in the form 'vectorname' or
<plotname>.vectorname) and returns a pointer to a vector_info struct.
The caller may then directly assess the vector data (but probably should
not modify them).
**
ngSpice_Circ(char**)
sends an array of null-terminated char* to ngspice.dll. Each char* contains a
single line of a circuit (each line like in an input file **.sp). The last
entry to char** has to be NULL. Upon receiving the arry, ngspice.dll will
immediately parse the input and set up the circuit structure (as if received
the circuit from a file by the 'source' command.
**
char* ngSpice_CurPlot();
returns to the caller a pointer to the name of the current plot
**
char** ngSpice_AllPlots()
returns to the caller a pointer to an array of all plots (by their typename)
**
char** ngSpice_AllVecs(char*);
returns to the caller a pointer to an array of vector names in the plot
named by the string in the argument.
**
Additional basics:
No memory mallocing and freeing across the interface:
Memory allocated in ngspice.dll has to be freed in ngspice.dll.
Memory allocated in the calling program has to be freed only there.
ngspice.dll should never call exit() directly, but handle either the 'quit'
request to the caller or an request for exiting upon error,
done by callback function ngexit().
*/
#ifndef NGSPICE_DLL_H
#define NGSPICE_DLL_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__CYGWIN__)
#ifdef SHARED_MODULE
#define IMPEXP __declspec(dllexport)
#else
#define IMPEXP __declspec(dllimport)
#endif
#else
/* use with gcc flag -fvisibility=hidden */
#if __GNUC__ >= 4
#define IMPEXP __attribute__ ((visibility ("default")))
#define IMPEXPLOCAL __attribute__ ((visibility ("hidden")))
#else
#define IMPEXP
#define IMPEXP_LOCAL
#endif
#endif
/* required only if header is used by the caller,
is already defined in ngspice.dll */
#ifndef ngspice_NGSPICE_H
/* Complex numbers. */
struct ngcomplex {
double cx_real;
double cx_imag;
} ;
typedef struct ngcomplex ngcomplex_t;
#endif
/* vector info obtained from any vector in ngspice.dll.
Allows direct access to the ngspice internal vector structure,
as defined in include/ngspice/devc.h . */
typedef struct vector_info {
char *v_name; /* Same as so_vname. */
int v_type; /* Same as so_vtype. */
short v_flags; /* Flags (a combination of VF_*). */
double *v_realdata; /* Real data. */
ngcomplex_t *v_compdata; /* Complex data. */
int v_length; /* Length of the vector. */
} vector_info, *pvector_info;
typedef struct vecvalues {
char* name; /* name of a specific vector */
double creal; /* actual data value */
double cimag; /* actual data value */
bool is_scale; /* if 'name' is the scale vector */
bool is_complex; /* if the data are complex numbers */
} vecvalues, *pvecvalues;
typedef struct vecvaluesall {
int veccount; /* number of vectors in plot */
int vecindex; /* index of actual set of vectors. i.e. the number of accepted data points */
pvecvalues *vecsa; /* values of actual set of vectors, indexed from 0 to veccount - 1 */
} vecvaluesall, *pvecvaluesall;
/* info for a specific vector */
typedef struct vecinfo
{
int number; /* number of vector, as postion in the linked list of vectors, starts with 0 */
char *vecname; /* name of the actual vector */
bool is_real; /* TRUE if the actual vector has real data */
void *pdvec; /* a void pointer to struct dvec *d, the actual vector */
void *pdvecscale; /* a void pointer to struct dvec *ds, the scale vector */
} vecinfo, *pvecinfo;
/* info for the current plot */
typedef struct vecinfoall
{
/* the plot */
char *name;
char *title;
char *date;
char *type;
int veccount;
/* the data as an array of vecinfo with length equal to the number of vectors in the plot */
pvecinfo *vecs;
} vecinfoall, *pvecinfoall;
/* callback functions
addresses received from caller with ngSpice_Init() function
*/
/* sending output from stdout, stderr to caller */
typedef int (SendChar)(char*, int, void*);
/*
char* string to be sent to caller output
int identification number of calling ngspice shared lib
void* return pointer received from caller, e.g. pointer to object having sent the request
*/
/* sending simulation status to caller */
typedef int (SendStat)(char*, int, void*);
/*
char* simulation status and value (in percent) to be sent to caller
int identification number of calling ngspice shared lib
void* return pointer received from caller
*/
/* asking for controlled exit */
typedef int (ControlledExit)(int, bool, bool, int, void*);
/*
int exit status
bool if true: immediate unloading dll, if false: just set flag, unload is done when function has returned
bool if true: exit upon 'quit', if false: exit due to ngspice.dll error
int identification number of calling ngspice shared lib
void* return pointer received from caller
*/
/* send back actual vector data */
typedef int (SendData)(pvecvaluesall, int, int, void*);
/*
vecvaluesall* pointer to array of structs containing actual values from all vectors
int number of structs (one per vector)
int identification number of calling ngspice shared lib
void* return pointer received from caller
*/
/* send back initailization vector data */
typedef int (SendInitData)(pvecinfoall, int, void*);
/*
vecinfoall* pointer to array of structs containing data from all vectors right after initialization
int identification number of calling ngspice shared lib
void* return pointer received from caller
*/
/* indicate if background thread is running */
typedef int (BGThreadRunning)(bool, int, void*);
/*
bool true if background thread is running
int identification number of calling ngspice shared lib
void* return pointer received from caller
*/
/* callback functions
addresses received from caller with ngSpice_Init_Sync() function
*/
/* ask for VSRC EXTERNAL value */
typedef int (GetVSRCData)(double*, double, char*, int, void*);
/*
double* return voltage value
double actual time
char* node name
int identification number of calling ngspice shared lib
void* return pointer received from caller
*/
/* ask for ISRC EXTERNAL value */
typedef int (GetISRCData)(double*, double, char*, int, void*);
/*
double* return current value
double actual time
char* node name
int identification number of calling ngspice shared lib
void* return pointer received from caller
*/
/* ask for new delta time depending on synchronization requirements */
typedef int (GetSyncData)(double, double*, double, int, int, int, void*);
/*
double actual time (ckt->CKTtime)
double* delta time (ckt->CKTdelta)
double old delta time (olddelta)
int redostep (as set by ngspice)
int identification number of calling ngspice shared lib
int location of call for synchronization in dctran.c
void* return pointer received from caller
*/
/* ngspice initialization,
printfcn: pointer to callback function for reading printf, fprintf
statfcn: pointer to callback function for the status string and percent value
ControlledExit: pointer to callback function for setting a 'quit' signal in caller
SendData: pointer to callback function for returning data values of all current output vectors
SendInitData: pointer to callback function for returning information of all output vectors just initialized
BGThreadRunning: pointer to callback function indicating if workrt thread is running
userData: pointer to user-defined data, will not be modified, but
handed over back to caller during Callback, e.g. address of calling object */
IMPEXP
int ngSpice_Init(SendChar* printfcn, SendStat* statfcn, ControlledExit* ngexit,
SendData* sdata, SendInitData* sinitdata, BGThreadRunning* bgtrun, void* userData);
/* initialization of synchronizing functions
vsrcdat: pointer to callback function for retrieving a voltage source value from caller
isrcdat: pointer to callback function for retrieving a current source value from caller
syncdat: pointer to callback function for synchronization
ident: pointer to integer unique to this shared library (defaults to 0)
userData: pointer to user-defined data, will not be modified, but
handed over back to caller during Callback, e.g. address of calling object.
If NULL is sent here, userdata info from ngSpice_Init() will be kept, otherwise
userdata will be overridden by new value from here.
*/
IMPEXP
int ngSpice_Init_Sync(GetVSRCData *vsrcdat, GetISRCData *isrcdat, GetSyncData *syncdat, int *ident, void *userData);
/* Caller may send ngspice commands to ngspice.dll.
Commands are executed immediately */
IMPEXP
int ngSpice_Command(char* command);
/* get info about a vector */
IMPEXP
pvector_info ngGet_Vec_Info(char* vecname);
/* send a circuit to ngspice.dll
The circuit description is a dynamic array
of char*. Each char* corresponds to a single circuit
line. The last entry of the array has to be a NULL */
IMPEXP
int ngSpice_Circ(char** circarray);
/* return to the caller a pointer to the name of the current plot */
IMPEXP
char* ngSpice_CurPlot(void);
/* return to the caller a pointer to an array of all plots created
so far by ngspice.dll */
IMPEXP
char** ngSpice_AllPlots(void);
/* return to the caller a pointer to an array of vector names in the plot
named by plotname */
IMPEXP
char** ngSpice_AllVecs(char* plotname);
/* returns TRUE if ngspice is running in a second (background) thread */
IMPEXP
bool ngSpice_running(void);
/* set a breakpoint in ngspice */
IMPEXP
bool ngSpice_SetBkpt(double time);
#ifdef __cplusplus
}
#endif
#endif

197
eeschema/noname.sch Normal file
View File

@ -0,0 +1,197 @@
EESchema Schematic File Version 2
LIBS:power
LIBS:device
LIBS:transistors
LIBS:conn
LIBS:linear
LIBS:regul
LIBS:74xx
LIBS:cmos4000
LIBS:adc-dac
LIBS:memory
LIBS:xilinx
LIBS:microcontrollers
LIBS:dsp
LIBS:microchip
LIBS:analog_switches
LIBS:motorola
LIBS:texas
LIBS:intel
LIBS:audio
LIBS:interface
LIBS:digital-audio
LIBS:philips
LIBS:display
LIBS:cypress
LIBS:siliconi
LIBS:opto
LIBS:atmel
LIBS:contrib
LIBS:valves
LIBS:pspice
LIBS:noname-cache
EELAYER 25 0
EELAYER END
$Descr A4 11693 8268
encoding utf-8
Sheet 1 1
Title ""
Date ""
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDescr
$Comp
L VSOURCE V1
U 1 1 57336052
P 4400 4050
F 0 "V1" H 4528 4096 50 0000 L CNN
F 1 "SINE(0 1.5 1k 0 0 0 0)" H 4528 4005 50 0000 L CNN
F 2 "" H 4400 4050 50 0000 C CNN
F 3 "" H 4400 4050 50 0000 C CNN
F 4 "Value" H 4400 4050 60 0001 C CNN "Fieldname"
F 5 "V" H 4400 4050 60 0001 C CNN "Spice_Primitive"
F 6 "1 2" H 4100 4250 60 0001 C CNN "Spice_Node_Sequence"
1 4400 4050
-1 0 0 1
$EndComp
$Comp
L GND #PWR1
U 1 1 573360D3
P 4400 4350
F 0 "#PWR1" H 4400 4100 50 0001 C CNN
F 1 "GND" H 4405 4177 50 0000 C CNN
F 2 "" H 4400 4350 50 0000 C CNN
F 3 "" H 4400 4350 50 0000 C CNN
1 4400 4350
1 0 0 -1
$EndComp
$Comp
L R R1
U 1 1 573360F5
P 4650 3700
F 0 "R1" V 4443 3700 50 0000 C CNN
F 1 "1k" V 4534 3700 50 0000 C CNN
F 2 "" V 4580 3700 50 0000 C CNN
F 3 "" H 4650 3700 50 0000 C CNN
F 4 "Value" H 4650 3700 60 0001 C CNN "Fieldname"
F 5 "1 2" H 4650 3700 60 0001 C CNN "SpiceMapping"
F 6 "R" V 4650 3700 60 0001 C CNN "Spice_Primitive"
1 4650 3700
0 1 1 0
$EndComp
$Comp
L D D1
U 1 1 573361B8
P 5100 3700
F 0 "D1" H 5100 3485 50 0000 C CNN
F 1 "1N4148" H 5100 3576 50 0000 C CNN
F 2 "" H 5100 3700 50 0000 C CNN
F 3 "" H 5100 3700 50 0000 C CNN
F 4 "Value" H 5100 3700 60 0001 C CNN "Fieldname"
F 5 "D" H 5100 3700 60 0001 C CNN "Spice_Primitive"
F 6 "2 1" H 5100 3700 60 0001 C CNN "Spice_Node_Sequence"
1 5100 3700
-1 0 0 1
$EndComp
$Comp
L C C1
U 1 1 5733628F
P 5400 4000
F 0 "C1" H 5515 4046 50 0000 L CNN
F 1 "100n" H 5515 3955 50 0000 L CNN
F 2 "" H 5438 3850 50 0000 C CNN
F 3 "" H 5400 4000 50 0000 C CNN
F 4 "Value" H 5400 4000 60 0001 C CNN "Fieldname"
F 5 "C" H 5400 4000 60 0001 C CNN "Spice_Primitive"
F 6 "1 2" H 5400 4000 60 0001 C CNN "SpiceMapping"
1 5400 4000
1 0 0 -1
$EndComp
$Comp
L R R2
U 1 1 573362F7
P 5750 4000
F 0 "R2" H 5680 3954 50 0000 R CNN
F 1 "100k" H 5680 4045 50 0000 R CNN
F 2 "" V 5680 4000 50 0000 C CNN
F 3 "" H 5750 4000 50 0000 C CNN
F 4 "Value" H 5750 4000 60 0001 C CNN "Fieldname"
F 5 "1 2" H 5750 4000 60 0001 C CNN "SpiceMapping"
F 6 "R" V 5750 4000 60 0001 C CNN "Spice_Primitive"
1 5750 4000
-1 0 0 1
$EndComp
Text Notes 4300 4900 0 60 ~ 0
*.tran 1u 10m\n
$Comp
L SPICE_PROBE U1
U 1 1 573367CB
P 4400 3700
F 0 "U1" H 4400 3700 60 0001 C CNN
F 1 "SPICE_PROBE" H 4400 3700 60 0001 C CNN
F 2 "" H 4400 3700 60 0000 C CNN
F 3 "" H 4400 3700 60 0000 C CNN
1 4400 3700
1 0 0 -1
$EndComp
Wire Wire Line
4400 4350 4400 4250
Wire Wire Line
4400 4300 5750 4300
Connection ~ 4400 4300
Wire Wire Line
5250 3700 5750 3700
Wire Wire Line
5750 3700 5750 3850
Wire Wire Line
5400 3850 5400 3700
Connection ~ 5400 3700
Wire Wire Line
5400 4300 5400 4150
Wire Wire Line
5750 4300 5750 4150
Connection ~ 5400 4300
Wire Wire Line
4800 3700 4950 3700
Connection ~ 4900 3700
Wire Wire Line
4400 3850 4400 3700
Wire Wire Line
4400 3700 4500 3700
Connection ~ 5650 3700
Connection ~ 4400 3700
Text Notes 4300 4800 0 60 ~ 0
.include diodes.lib\n
Text Label 4400 3800 0 60 ~ 0
in
$Comp
L SPICE_PROBE U?
U 1 1 5734D78F
P 4900 3700
F 0 "U?" H 4900 3700 60 0001 C CNN
F 1 "SPICE_PROBE" H 4900 3700 60 0001 C CNN
F 2 "" H 4900 3700 60 0000 C CNN
F 3 "" H 4900 3700 60 0000 C CNN
1 4900 3700
1 0 0 -1
$EndComp
$Comp
L SPICE_PROBE U?
U 1 1 5734D7B3
P 5400 3700
F 0 "U?" H 5400 3700 60 0001 C CNN
F 1 "SPICE_PROBE" H 5400 3700 60 0001 C CNN
F 2 "" H 5400 3700 60 0000 C CNN
F 3 "" H 5400 3700 60 0000 C CNN
1 5400 3700
1 0 0 -1
$EndComp
Text Label 5550 3700 0 60 ~ 0
rect
Text Notes 4300 5000 0 60 ~ 0
.ac dec 10 1 1Meg\n
$EndSCHEMATC

252
eeschema/sim/ngspice.cpp Normal file
View File

@ -0,0 +1,252 @@
#include "sharedspice.h"
#include <cstdio>
#include <sstream>
#include <wx/dynlib.h>
#include <string>
#include <vector>
#include "spice_simulator.h"
#include <reporter.h>
using namespace std;
class NGSPICE : public SPICE_SIMULATOR {
public:
NGSPICE();
virtual ~NGSPICE();
void Init();
bool LoadNetlist(const string& netlist);
bool Command(const string& cmd);
string GetConsole() const;
const vector<double> GetPlot( std::string name, int max_len = -1);
private:
typedef void (*ngSpice_Init)(SendChar*, SendStat*, ControlledExit*,
SendData*, SendInitData*, BGThreadRunning*, void*);
typedef int (*ngSpice_Circ)(char** circarray);
typedef int (*ngSpice_Command)(char* command);
typedef pvector_info (*ngGet_Vec_Info)(char* vecname);
typedef char** (*ngSpice_AllVecs)(char* plotname);
typedef char** (*ngSpice_AllPlots)(void);
ngSpice_Init m_ngSpice_Init;
ngSpice_Circ m_ngSpice_Circ;
ngSpice_Command m_ngSpice_Command;
ngGet_Vec_Info m_ngGet_Vec_Info;
ngSpice_AllPlots m_ngSpice_AllPlots;
ngSpice_AllVecs m_ngSpice_AllVecs;
wxDynamicLibrary *m_dll;
static int cbSendChar( char* what, int id, void* user)
{
NGSPICE *sim = reinterpret_cast<NGSPICE*>(user);
printf("sim %p cr %p\n",sim, sim->m_consoleReporter );
if(sim->m_consoleReporter)
sim->m_consoleReporter->Report(what);
return 0;
}
static int cbSendStat( char* what, int id, void* user)
{
/* NGSPICE *sim = reinterpret_cast<NGSPICE*>(user);
if(sim->m_consoleReporter)
sim->m_consoleReporter->Report(what);*/
return 0;
}
};
NGSPICE::NGSPICE()
{
m_dll = new wxDynamicLibrary("/home/twl/projects_sw/ngspice-26/src/.libs/libngspice.so.0.0.0"); //, wxDL_LAZY);
printf("DLL at %p\n", m_dll);
assert(m_dll);
m_ngSpice_Init = (ngSpice_Init) m_dll->GetSymbol("ngSpice_Init");
printf("Init @ %p\n", m_ngSpice_Init);
m_ngSpice_Circ = (ngSpice_Circ) m_dll->GetSymbol("ngSpice_Circ");
m_ngSpice_Command = (ngSpice_Command) m_dll->GetSymbol("ngSpice_Command");
m_ngGet_Vec_Info = (ngGet_Vec_Info) m_dll->GetSymbol("ngGet_Vec_Info");
m_ngSpice_AllPlots = (ngSpice_AllPlots) m_dll->GetSymbol("ngSpice_AllPlots");
m_ngSpice_AllVecs = (ngSpice_AllVecs) m_dll->GetSymbol("ngSpice_AllVecs");
}
void NGSPICE::Init()
{
m_ngSpice_Init( &cbSendChar, &cbSendStat, NULL, NULL, NULL, NULL, this);
}
const vector<double> NGSPICE::GetPlot( std::string name, int max_len )
{
vector<double> data;
vector_info *vi = m_ngGet_Vec_Info((char*)name.c_str());
if(vi->v_realdata)
for(int i = 0; i<vi->v_length;i++)
data.push_back(vi->v_realdata[i]);
return data;
}
static string loadFile(const string& filename)
{
FILE *f=fopen(filename.c_str(),"rb");
char buf[10000];
int n = fread(buf, 1, 10000, f);
fclose(f);
buf[n] = 0;
return buf;
}
bool NGSPICE::LoadNetlist(const string& netlist)
{
char *lines[16384];
stringstream ss(netlist);
int n = 0;
while(!ss.eof())
{
char line[1024];
ss.getline(line, 1024);
lines[n++] = strdup(line);
printf("l '%s'\n", line);
}
lines[n]= NULL;
printf("netlist contains %d lines\n", n);
m_ngSpice_Circ(lines);
for(int i = 0; i < n; i++)
delete lines[i];
return true;
}
bool NGSPICE::Command(const string& cmd )
{
m_ngSpice_Command( (char*)(cmd + string("\n")).c_str());
return true;
}
#if 0
bool NGSPICE::Run()
{
// m_ngSpice_Command("run\n");
char **plots = m_ngSpice_AllPlots();
for(int i = 0; plots[i]; i++)
{
printf("-> plot : %s\n", plots[i]);
char **vecs = m_ngSpice_AllVecs(plots[i]);
for(int j = 0; vecs[j]; j++)
{
printf(" - vector %s\n", vecs[j]);
vector_info *vi = m_ngGet_Vec_Info(vecs[j]);
printf(" - v_type %x\n", vi->v_type);
printf(" - v_flags %x\n", vi->v_flags);
printf(" - v_length %d\n", vi->v_length);
}
}
}
#endif
NGSPICE::~NGSPICE()
{
printf("Killing ngspice\n");
delete m_dll;
}
#if 0
main()
{
NGSPICE spice;
spice.Init();
spice.LoadNetlist(loadFile("1.ckt"));
spice.Command("tran .05 1");
spice.Command("save all");
spice.Run();
vector<double> t = spice.GetPlot("time");
vector<double> v1 = spice.GetPlot("V(1)");
vector<double> v2 = spice.GetPlot("V(2)");
// Prepare data.
// Plot line from given x and y data. Color is selected automatically.
plt::plot(t, v1);
// Plot a red dashed line from given x and y data.
plt::plot(t, v2,"r--");
for(int i=0;i<v1.size();i++)
printf("%.10f\n",v2[i]);
// Add graph title
plt::title("Sample figure");
// Enable legend.
plt::legend();
// save figure
plt::show();
// spice.Run();
}
#endif
std::string NGSPICE::GetConsole() const {
return "";
}
SPICE_SIMULATOR::~SPICE_SIMULATOR()
{
}
SPICE_SIMULATOR *SPICE_SIMULATOR::CreateInstance( const std::string name )
{
return new NGSPICE;
}

20
eeschema/sim/ngspice.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef __NGSPICE_H
#define __NGSPICE_H
#include <string>
#include <vector>
class SPICE_SIMULATOR {
public:
SPICE_SIMULATOR();
~SPICE_SIMULATOR();
virtual void Init();
virtual bool LoadNetlist(const std::string& netlist);
virtual bool Command(const std::string& cmd);
const std::vector<double> GetPlot( std::string name, int max_len = -1);
};
#endif

View File

@ -0,0 +1,130 @@
#include <schframe.h>
#include <fctsys.h>
#include <kiface_i.h>
#include <pgm_base.h>
#include <gr_basic.h>
#include <class_drawpanel.h>
#include <gestfich.h>
#include <confirm.h>
#include <base_units.h>
#include <msgpanel.h>
#include <html_messagebox.h>
#include <general.h>
#include <eeschema_id.h>
#include <netlist.h>
#include <lib_pin.h>
#include <class_library.h>
#include <schframe.h>
#include <sch_component.h>
#include <dialog_helpers.h>
#include <libeditframe.h>
#include <viewlib_frame.h>
#include <hotkeys.h>
#include <eeschema_config.h>
#include <sch_sheet.h>
#include <sch_sheet_path.h>
#include <invoke_sch_dialog.h>
#include <dialogs/dialog_schematic_find.h>
#include <wx/display.h>
#include <build_version.h>
#include <wildcards_and_files_ext.h>
#include <netlist_exporter_kicad.h>
#include <kiway.h>
#include <netlist_exporters/netlist_exporter_pspice.h>
#include <reporter.h>
#include "sim_plot_frame.h"
#include "sim_plot_panel.h"
#include "spice_simulator.h"
class SIM_REPORTER : public REPORTER
{
public:
SIM_REPORTER( wxRichTextCtrl *console )
{
m_console = console;
}
~SIM_REPORTER( )
{
}
virtual REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_UNDEFINED )
{
m_console->WriteText(aText);
m_console->Newline();
return *this;
}
private:
wxRichTextCtrl *m_console;
};
SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY *aKiway, wxWindow* parent )
: SIM_PLOT_FRAME_BASE( aKiway, parent )
{
m_exporter = NULL;
m_simulator = NULL;
}
SIM_PLOT_FRAME::~SIM_PLOT_FRAME()
{
}
void SIM_PLOT_FRAME::StartSimulation()
{
if(m_exporter)
delete m_exporter;
if(m_simulator)
delete m_simulator;
m_simulator = SPICE_SIMULATOR::CreateInstance("ngspice");
m_simulator->SetConsoleReporter( new SIM_REPORTER( m_simConsole ) );
m_simulator->Init();
//m_simulator->SetConsoleReporter( , this );
NETLIST_OBJECT_LIST* net_atoms = m_schematicFrame->BuildNetListBase();
m_exporter = new NETLIST_EXPORTER_PSPICE ( net_atoms, Prj().SchLibs() );
STRING_FORMATTER formatter;
m_exporter->Format( &formatter, GNL_ALL );
m_plotPanel->DeleteTraces();
printf("*******************\n%s\n", (const char *)formatter.GetString().c_str());
m_simulator->LoadNetlist( formatter.GetString() );
m_simulator->Command("run\n");
auto mapping = m_exporter->GetNetIndexMap();
auto data_t = m_simulator->GetPlot("time");
for(auto name : m_exporter->GetProbeList())
{
char spiceName[1024];
sprintf(spiceName,"V(%d)", mapping[name] );
//printf("probe %s->%s\n", (const char *) name.c_str(), spiceName);
auto data_y = m_simulator->GetPlot(spiceName);
//printf("%d - %d data points\n", data_t.size(), data_y.size() );
m_plotPanel->AddTrace(wxT("V(") + name + wxT(")"), data_t.size(), data_t.data(), data_y.data(), 0);
}
delete m_simulator;
m_simulator = NULL;
//m_simulator->Command("quit\n");
}

View File

@ -0,0 +1,43 @@
#ifndef __sim_plot_frame__
#define __sim_plot_frame__
/**
@file
Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder.
*/
#include "sim_plot_frame_base.h"
#include "kiway_player.h"
#include <netlist_exporters/netlist_exporter_pspice.h>
//// end generated include
class SPICE_SIMULATOR;
class NETLIST_EXPORTER_PSPICE;
/** Implementing SIM_PLOT_FRAME_BASE */
class SIM_PLOT_FRAME : public SIM_PLOT_FRAME_BASE
{
public:
/** Constructor */
SIM_PLOT_FRAME(KIWAY *aKiway, wxWindow* parent );
~SIM_PLOT_FRAME();
void SetSchFrame( SCH_EDIT_FRAME* schFrame )
{
m_schematicFrame = schFrame;
}
void StartSimulation();
private:
SCH_EDIT_FRAME *m_schematicFrame;
NETLIST_EXPORTER_PSPICE *m_exporter;
SPICE_SIMULATOR *m_simulator;
//// end generated class members
};
#endif // __sim_plot_frame__

View File

@ -0,0 +1,76 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jun 17 2015)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "sim_plot_panel.h"
#include "sim_plot_frame_base.h"
///////////////////////////////////////////////////////////////////////////
SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( KIWAY* aKiway, wxWindow* aParent ) :
KIWAY_PLAYER( aKiway, aParent, FRAME_SIMULATOR, _( "Spice Simulation" ),
wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, wxT("Spice Simulation" ) )
{
this->SetSizeHints( wxSize( 1920,1000 ), wxSize( 1920,1000 ) );
m_menubar1 = new wxMenuBar( 0 );
m_menu1 = new wxMenu();
wxMenuItem* m_menuItem2;
m_menuItem2 = new wxMenuItem( m_menu1, wxID_ANY, wxString( wxT("Save Plot") ) , wxEmptyString, wxITEM_NORMAL );
m_menu1->Append( m_menuItem2 );
m_menu1->AppendSeparator();
wxMenuItem* m_menuItem1;
m_menuItem1 = new wxMenuItem( m_menu1, wxID_ANY, wxString( wxT("Exit Simulation") ) , wxEmptyString, wxITEM_NORMAL );
m_menu1->Append( m_menuItem1 );
m_menubar1->Append( m_menu1, wxT("File") );
this->SetMenuBar( m_menubar1 );
wxBoxSizer* bSizer1;
bSizer1 = new wxBoxSizer( wxVERTICAL );
m_auiToolBar1 = new wxAuiToolBar( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_TB_HORZ_LAYOUT );
m_toolZoomIn = m_auiToolBar1->AddTool( wxID_ANY, wxT("Zoom In"), wxNullBitmap /*wxBitmap( wxT("zoom.png"), wxBITMAP_TYPE_ANY )*/, wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString, NULL );
m_auiToolBar1->Realize();
bSizer1->Add( m_auiToolBar1, 0, wxALL, 5 );
m_splitter1 = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3D );
m_splitter1->SetSashGravity( 0.2 );
m_splitter1->SetSashSize( 0 );
m_splitter1->Connect( wxEVT_IDLE, wxIdleEventHandler( SIM_PLOT_FRAME_BASE::m_splitter1OnIdle ), NULL, this );
m_plotPanel = new SIM_PLOT_PANEL( m_splitter1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_panel3 = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxVERTICAL );
m_simConsole = new wxRichTextCtrl( m_panel3, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY|wxVSCROLL|wxHSCROLL|wxNO_BORDER|wxWANTS_CHARS );
bSizer3->Add( m_simConsole, 1, wxEXPAND | wxALL, 5 );
m_panel3->SetSizer( bSizer3 );
m_panel3->Layout();
bSizer3->Fit( m_panel3 );
m_splitter1->SplitHorizontally( m_plotPanel, m_panel3, 700 );
bSizer1->Add( m_splitter1, 1, wxEXPAND, 5 );
this->SetSizer( bSizer1 );
this->Layout();
this->Centre( wxBOTH );
}
SIM_PLOT_FRAME_BASE::~SIM_PLOT_FRAME_BASE()
{
}

View File

@ -0,0 +1,67 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jun 17 2015)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __SIM_PLOT_FRAME_BASE_H__
#define __SIM_PLOT_FRAME_BASE_H__
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
class KIWAY_PLAYER;
class SIM_PLOT_PANEL;
#include "kiway_player.h"
#include <wx/string.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/menu.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/aui/aui.h>
#include <wx/aui/auibar.h>
#include <wx/panel.h>
#include <wx/richtext/richtextctrl.h>
#include <wx/sizer.h>
#include <wx/splitter.h>
#include <wx/frame.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class SIM_PLOT_FRAME_BASE
///////////////////////////////////////////////////////////////////////////////
class SIM_PLOT_FRAME_BASE : public KIWAY_PLAYER
{
private:
protected:
wxMenuBar* m_menubar1;
wxMenu* m_menu1;
wxAuiToolBar* m_auiToolBar1;
wxAuiToolBarItem* m_toolZoomIn;
wxSplitterWindow* m_splitter1;
SIM_PLOT_PANEL* m_plotPanel;
wxPanel* m_panel3;
wxRichTextCtrl* m_simConsole;
public:
SIM_PLOT_FRAME_BASE( KIWAY* aKiway, wxWindow* aParent );
~SIM_PLOT_FRAME_BASE();
void m_splitter1OnIdle( wxIdleEvent& )
{
m_splitter1->SetSashPosition( 700 );
m_splitter1->Disconnect( wxEVT_IDLE, wxIdleEventHandler( SIM_PLOT_FRAME_BASE::m_splitter1OnIdle ), NULL, this );
}
};
#endif //__SIM_PLOT_FRAME_BASE_H__

View File

@ -0,0 +1,75 @@
#include "sim_plot_panel.h"
#include <boost/foreach.hpp>
static SIM_PLOT_PANEL *panel = NULL;
static int drawPlotFunc( mglGraph *graph )
{
printf("DrawPlot [%d traces]!\n", panel->m_traces.size());
graph->Clf();
//graph->SetRanges(-10e-3,10e-3,-2,2);
graph->Axis("x");
graph->Label('x',"Time",0);
graph->AddRange('x', 0, 10e-3);
graph->Axis("y");
graph->Label('y',"Voltage",0);
graph->SetRange('y', -1.5, 1.5);
for(auto t : panel->m_traces)
{
graph->AddLegend((const char *)t.name.c_str(),"");
graph->Plot(t.y);
}
graph->Box();
graph->Grid();
if ( panel->m_traces.size() )
graph->Legend(1,"-#");
return 0;
}
SIM_PLOT_PANEL::SIM_PLOT_PANEL( wxWindow * parent,
wxWindowID id,
const wxPoint & pos,
const wxSize & size,
long style,
const wxString & name )
: wxMathGL ( parent, id, pos, size, style, name )
{
panel = this;
AutoResize = true;
SetDraw( drawPlotFunc );
Update();
}
SIM_PLOT_PANEL::~SIM_PLOT_PANEL()
{
}
void SIM_PLOT_PANEL::AddTrace(const wxString& name, int n_points, double *t, double *x, int flags )
{
Trace trace;
trace.name = name;
trace.x.Set(t, n_points);
trace.y.Set(x, n_points);
m_traces.push_back(trace);
Update();
}
void SIM_PLOT_PANEL::DeleteTraces()
{
m_traces.clear();
Update();
}

View File

@ -0,0 +1,34 @@
#ifndef __SIM_PLOT_PANEL_H
#define __SIM_PLOT_PANEL_H
#include "mgl2/canvas_wnd.h"
#include "mgl2/wx.h"
class SIM_PLOT_PANEL : public wxMathGL
{
public:
SIM_PLOT_PANEL( wxWindow * parent,
wxWindowID id,
const wxPoint & pos = wxDefaultPosition,
const wxSize & size = wxDefaultSize,
long style = 0,
const wxString & name = wxPanelNameStr );
~SIM_PLOT_PANEL();
struct Trace {
wxString name;
mglData x, y;
};
std::vector<Trace> m_traces;
void AddTrace(const wxString& name, int n_points, double *t, double *x, int flags = 0 );
void DeleteTraces();
};
#endif

79
eeschema/sim/simulate.cpp Normal file
View File

@ -0,0 +1,79 @@
#include <schframe.h>
#include <fctsys.h>
#include <kiface_i.h>
#include <pgm_base.h>
#include <gr_basic.h>
#include <class_drawpanel.h>
#include <gestfich.h>
#include <confirm.h>
#include <base_units.h>
#include <msgpanel.h>
#include <html_messagebox.h>
#include <general.h>
#include <eeschema_id.h>
#include <netlist.h>
#include <lib_pin.h>
#include <class_library.h>
#include <schframe.h>
#include <sch_component.h>
#include <dialog_helpers.h>
#include <libeditframe.h>
#include <viewlib_frame.h>
#include <hotkeys.h>
#include <eeschema_config.h>
#include <sch_sheet.h>
#include <sch_sheet_path.h>
#include <invoke_sch_dialog.h>
#include <dialogs/dialog_schematic_find.h>
#include <wx/display.h>
#include <build_version.h>
#include <wildcards_and_files_ext.h>
#include <netlist_exporter_kicad.h>
#include <kiway.h>
#include <netlist_exporters/netlist_exporter_pspice.h>
#include <sim/sim_plot_frame.h>
void SCH_EDIT_FRAME::OnSimulationRun( wxCommandEvent& event )
{
#if 0
NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase();
NETLIST_EXPORTER_PSPICE exporter( net_atoms, Prj().SchLibs() );
STRING_FORMATTER formatter;
exporter.Format( &formatter, GNL_ALL );
printf("*******************\n%s\n", (const char *)formatter.GetString().c_str());
#endif
SIM_PLOT_FRAME* simFrame = (SIM_PLOT_FRAME*) Kiway().Player( FRAME_SIMULATOR, false );
if( !simFrame )
{
simFrame = (SIM_PLOT_FRAME*) Kiway().Player( FRAME_SIMULATOR, true );
simFrame->Show( true );
}
// On Windows, Raise() does not bring the window on screen, when iconized
if( simFrame->IsIconized() )
simFrame->Iconize( false );
simFrame->Raise();
simFrame->SetSchFrame( this );
simFrame->StartSimulation();
}
void SCH_EDIT_FRAME::OnSimulationStop( wxCommandEvent& event )
{}
void SCH_EDIT_FRAME::OnSimulationAddProbe( wxCommandEvent& event )
{}

11
eeschema/sim/simulate.h Normal file
View File

@ -0,0 +1,11 @@
#include <schframe.h>
void SCH_EDIT_FRAME::OnSimulationRun( wxCommandEvent& event )
{}
void SCH_EDIT_FRAME::OnSimulationStop( wxCommandEvent& event )
{}
void SCH_EDIT_FRAME::OnSimulationAddProbe( wxCommandEvent& event )
{}

View File

@ -0,0 +1,44 @@
#ifndef __NGSPICE_H
#define __NGSPICE_H
#include <string>
#include <vector>
enum SimTraceType
{
SIM_AC_MAG = 0x1,
SIM_AC_PHASE = 0x2,
SIM_TR_VOLTAGE = 0x4,
SIM_TR_CURRENT = 0x8,
SIM_TR_FFT = 0x10
};
class REPORTER;
class SPICE_SIMULATOR {
public:
typedef void (*ConsoleCallback)( bool isError, const wxString& message, void *userData );
static SPICE_SIMULATOR *CreateInstance( const std::string name );
SPICE_SIMULATOR(){}
virtual ~SPICE_SIMULATOR() = 0;
virtual void Init() = 0;
virtual bool LoadNetlist(const std::string& netlist) = 0;
virtual bool Command(const std::string& cmd) = 0;
virtual void SetConsoleReporter ( REPORTER *rep )
{
m_consoleReporter = rep;
}
virtual const std::vector<double> GetPlot( std::string name, int max_len = -1) = 0;
protected:
REPORTER *m_consoleReporter;
};
#endif

View File

@ -37,7 +37,8 @@ enum FRAME_T
FRAME_SCH_LIB_EDITOR,
FRAME_SCH_VIEWER,
FRAME_SCH_VIEWER_MODAL,
FRAME_SIMULATOR,
FRAME_PCB,
FRAME_PCB_MODULE_EDITOR,
FRAME_PCB_MODULE_VIEWER,