1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

added support for CBuilder models

This commit is contained in:
Steffen Vogel 2016-06-26 15:28:34 +02:00
parent 132dd5fd65
commit cc66553761
9 changed files with 550 additions and 34 deletions

View file

@ -104,10 +104,10 @@ LIB_LDLIBS += $(shell pkg-config --libs ${PKGS})
######## Targets ########
.PHONY: all clean install release docker doc
.PHONY: all clean install release docker doc models
# Default target: build everything
all: $(LIBS) $(TARGETS)
all: $(LIBS) $(TARGETS) models
# Dependencies for individual binaries
fpga: LDLIBS += -lpci -lxil
@ -157,5 +157,8 @@ docker:
doc:
doxygen
models:
$(MAKE) -C lib/cbmodels
# Include auto-generated dependencies
-include $(wildcard *.d)

View file

@ -0,0 +1,55 @@
/** Node type: Wrapper around RSCAD CBuilder model
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2015-2016, Steffen Vogel
* This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
#ifndef _CBUILDER_H_
#define _CBUILDER_H_
#include <pthread.h>
#include "list.h"
/* Helper macros for registering new models */
#define REGISTER_CBMODEL(cb) \
__attribute__((constructor)) static void __register() { \
list_push(&cbmodels, cb); \
}
extern struct list cbmodels; /**< Table of existing CBuilder models */
struct cbuilder {
unsigned long step, read;
double timestep;
struct cbmodel *model;
float *params;
int paramlen;
/* This mutex and cv are used to protect model parameters, input & outputs
*
* The cbuilder_read() function will wait for the completion of a simulation step
* before returning.
* The simulation step is triggerd by a call to cbuilder_write().
*/
pthread_mutex_t mtx;
pthread_cond_t cv;
};
struct cbmodel {
char *name;
void (*code)();
void (*ram)();
int (*init)(struct cbuilder *cb);
int (*read)(float inputs[], int len);
int (*write)(float outputs[], int len);
};
#endif /* _CBUILDER_H_ */

8
lib/cbmodels/Makefile Normal file
View file

@ -0,0 +1,8 @@
MODELS = simple_circuit
CFLAGS = -fPIC -DVILLAS -I../../include/villas
all: $(addsuffix .so,${MODELS})
%.so: %.o
$(CC) -shared $^ -o $@

32
lib/cbmodels/Subsystem.c Normal file
View file

@ -0,0 +1,32 @@
VERSION:
3.001
#include "Subsystem.h"
STATIC:
#define SECTION STATIC
#include "model.c"
#undef SECTION
RAM_FUNCTIONS:
#define SECTION RAM_FUNCTIONS
#include "model.c"
#undef SECTION
RAM:
#define SECTION RAM
#include "model.c"
#undef SECTION
model_ram();
CODE:
#define SECTION CODE
#include "model.c"
#undef SECTION
model_code();

24
lib/cbmodels/Subsystem.h Normal file
View file

@ -0,0 +1,24 @@
MODEL_TYPE: CTL
#define SECTION CONSTANTS
#include "model.c"
#undef SECTION
INPUTS:
#define SECTION INPUTS
#include "model.c"
#undef SECTION
OUTPUTS:
#define SECTION OUTPUTS
#include "model.c"
#undef SECTION
PARAMETERS:
#define SECTION PARAMETERS
#include "model.c"
#undef SECTION

9
lib/cbmodels/constants.h Normal file
View file

@ -0,0 +1,9 @@
/* These constants are defined by RTDS in the component header file */
#define PI 3.1415926535897932384626433832795 // definition of PI
#define TWOPI 6.283185307179586476925286766559 // definition of 2.0*PI
#define E 2.71828182845904523536028747135266 // definition of E
#define EINV 0.36787944117144232159552377016147 // definition of E Inverse (1/E)
#define RT2 1.4142135623730950488016887242097 // definition of square root 2.0
#define RT3 1.7320508075688772935274463415059 // definition of square root 3.0
#define INV_ROOT2 0.70710678118654752440084436210485

163
lib/cbmodels/model.c Normal file
View file

@ -0,0 +1,163 @@
// This is c-code for CBuilder component for Subsystem 2
// Solver used as in RTDS: Resistive companion (Dommel's algo)
// Subsystem 1 is modelled in RSCAD
//
//% Circuit topology
// %
//% *** Subsystem 1 (SS1) *** % *** Subsystem 2 (SS2) ***
//% %
//% |---------| |---------| %
//% |---------| R1 |-------| L1 |----%-------|---------|
//% | |---------| |---------| % | |
//% | % | |
//% ----- % ----- -----
//% | + | % | | | |
//% | E | % |C2 | | R2|
//% | - | % | | | |
//% ----- % ----- -----
//% | % | |
//% |------------------------------------------%------------------
// %
// %
/* These constants are defined by RTDS in the component header file */
#if defined(VILLAS) || SECTION == CONSTANTS
#define PI 3.1415926535897932384626433832795 // definition of PI
#define TWOPI 6.283185307179586476925286766559 // definition of 2.0*PI
#define E 2.71828182845904523536028747135266 // definition of E
#define EINV 0.36787944117144232159552377016147 // definition of E Inverse (1/E)
#define RT2 1.4142135623730950488016887242097 // definition of square root 2.0
#define RT3 1.7320508075688772935274463415059 // definition of square root 3.0
#define INV_ROOT2 0.70710678118654752440084436210485
#endif
// -----------------------------------------------
// Variables declared here may be used as parameters
// inputs or outputs
// The have to match with whats in Subsystem.h
// -----------------------------------------------
#if defined(VILLAS) || SECTION == INPUTS
double IntfIn;
#endif
#if defined(VILLAS) || SECTION == OUTPUTS
double IntfOut;
#endif
#if defined(VILLAS) || SECTION == PARAMETERS
double R2; // Resistor [Ohm] in SS2
double C2; // Capacitance [F] in SS2
#endif
// -----------------------------------------------
// Variables declared here may be used in both the
// RAM: and CODE: sections below.
// -----------------------------------------------
#if defined(VILLAS) || SECTION == STATIC
double dt;
double GR2, GC2; //Inductances of components
double GnInv; //Inversion of conductance matrix (here only scalar)
double vC2Hist, iC2Hist, AC2; // history meas. and current of dynamic elements
double Jn; //source vector in equation Gn*e=Jn
double eSS2; //node voltage solution
#endif
// -----------------------------------------------
// This section should contain any 'c' functions
// to be called from the RAM section (either
// RAM_PASS1 or RAM_PASS2). Example:
//
// static double myFunction(double v1, double v2)
// {
// return(v1*v2);
// }
// -----------------------------------------------
#if defined(VILLAS) || SECTION == RAM_FUNCTIONS
/* Nothing here */
#endif
// -----------------------------------------------
// Place C code here which computes constants
// required for the CODE: section below. The C
// code here is executed once, prior to the start
// of the simulation case.
// -----------------------------------------------
#if defined(VILLAS) || SECTION == RAM
void ram() {
GR2 = 1/R2;
GC2 = 2*C2/dt; //trapezoidal rule
GnInv = 1/(GR2+GC2); //eq. conductance (inverted)
vC2Hist = 0.0; //Voltage over C2 in previous time step
iC2Hist = 0.0; //Current through C2 in previous time step
}
#endif
// -----------------------------------------------
// Place C code here which runs on the RTDS. The
// code below is entered once each simulation
// step.
// -----------------------------------------------
#if defined(VILLAS) || SECTION == CODE
void code() {
//Update source vector
AC2 = iC2Hist+vC2Hist*GC2;
Jn = IntfIn+AC2;
//Solution of the equation Gn*e=Jn;
eSS2 = GnInv*Jn;
//Post step -> calculate the voltage and current for C2 for next step and set interface output
vC2Hist= eSS2;
iC2Hist = vC2Hist*GC2-AC2;
IntfOut = eSS2;
}
#endif
// -----------------------------------------------
// The following code portion is VILLASnode specific
// -----------------------------------------------
#if defined(VILLAS)
#include "nodes/cbuilder.h"
// -----------------------------------------------
// Place C code here which intializes parameters
// -----------------------------------------------
void init(struct cbuilder *cb)
{
R2 = cb->params[0];
C2 = cb->params[1];
dt = cb->timestep;
}
// -----------------------------------------------
// Place C code here reads model outputs
// -----------------------------------------------
int read(float outputs[], int len)
{
outputs[0] = IntfOut;
}
// -----------------------------------------------
// Place C code here which updates model inputs
// -----------------------------------------------
int write(float inputs[], int len)
{
IntfIn = inputs[0];
}
static struct cbmodel cb = {
.name = "simple_circuit",
.code = code,
.init = init,
.read = read,
.write = write,
};
REGISTER_CBMODEL(&cb);
#endif

View file

@ -0,0 +1,175 @@
// This is c-code for CBuilder component for Subsystem 2
// Solver used as in RTDS: Resistive companion (Dommel's algo)
// Subsystem 1 is modelled in RSCAD
//
//% Circuit topology
// %
//% *** Subsystem 1 (SS1) *** % *** Subsystem 2 (SS2) ***
//% %
//% |---------| |---------| %
//% |---------| R1 |-------| L1 |----%-------|---------|
//% | |---------| |---------| % | |
//% | % | |
//% ----- % ----- -----
//% | + | % | | | |
//% | E | % |C2 | | R2|
//% | - | % | | | |
//% ----- % ----- -----
//% | % | |
//% |------------------------------------------%------------------
// %
// %
// -----------------------------------------------
// Variables declared here may be used as parameters
// inputs or outputs
// The have to match with whats in Subsystem.h
// -----------------------------------------------
#if defined(VILLAS) || SECTION == INPUTS
double IntfIn;
#endif
#if defined(VILLAS) || SECTION == OUTPUTS
double IntfOut;
#endif
#if defined(VILLAS) || SECTION == PARAMS
double R2; // Resistor [Ohm] in SS2
double C2; // Capacitance [F] in SS2
#endif
// -----------------------------------------------
// Variables declared here may be used in both the
// RAM: and CODE: sections below.
// -----------------------------------------------
#if defined(VILLAS) || SECTION == STATIC
double dt;
double GR2, GC2; //Inductances of components
double GnInv; //Inversion of conductance matrix (here only scalar)
double vC2Hist, iC2Hist, AC2; // history meas. and current of dynamic elements
double Jn; //source vector in equation Gn*e=Jn
double eSS2; //node voltage solution
#endif
// -----------------------------------------------
// This section should contain any 'c' functions
// to be called from the RAM section (either
// RAM_PASS1 or RAM_PASS2). Example:
//
// static double myFunction(double v1, double v2)
// {
// return(v1*v2);
// }
// -----------------------------------------------
#if defined(VILLAS) || SECTION == RAM_FUNCTIONS
/* Nothing here */
#endif
// -----------------------------------------------
// Place C code here which computes constants
// required for the CODE: section below. The C
// code here is executed once, prior to the start
// of the simulation case.
// -----------------------------------------------
#if defined(VILLAS) || SECTION == RAM
void simple_circuit_ram() {
GR2 = 1/R2;
GC2 = 2*C2/dt; //trapezoidal rule
GnInv = 1/(GR2+GC2); //eq. conductance (inverted)
vC2Hist = 0.0; //Voltage over C2 in previous time step
iC2Hist = 0.0; //Current through C2 in previous time step
}
#endif
// -----------------------------------------------
// Place C code here which runs on the RTDS. The
// code below is entered once each simulation
// step.
// -----------------------------------------------
#if defined(VILLAS) || SECTION == CODE
void simple_circuit_code() {
//Update source vector
AC2 = iC2Hist+vC2Hist*GC2;
Jn = IntfIn+AC2;
//Solution of the equation Gn*e=Jn;
eSS2 = GnInv*Jn;
//Post step -> calculate the voltage and current for C2 for next step and set interface output
vC2Hist= eSS2;
iC2Hist = vC2Hist*GC2-AC2;
IntfOut = eSS2;
}
#endif
// -----------------------------------------------
// Interface to VILLASnode
// -----------------------------------------------
#if defined(VILLAS)
#include "nodes/cbuilder.h"
double getTimeStep()
{
return dt;
}
// -----------------------------------------------
// Place C code here which intializes parameters
// -----------------------------------------------
int simple_circuit_init(struct cbuilder *cb)
{
if (cb->paramlen < 2)
return -1; /* not enough parameters given */
R2 = cb->params[0];
C2 = cb->params[1];
/* 'dt' is a special parameter */
dt = cb->timestep;
return 0; /* success */
}
// -----------------------------------------------
// Place C code here reads model outputs
// -----------------------------------------------
int simple_circuit_read(float outputs[], int len)
{
if (len < 1)
return -1; /* not enough space */
outputs[0] = IntfOut;
return 1; /* 1 value per sample */
}
// -----------------------------------------------
// Place C code here which updates model inputs
// -----------------------------------------------
int simple_circuit_write(float inputs[], int len)
{
if (len < 1)
return -1; /* not enough values */
IntfIn = inputs[0];
return 0;
}
static struct cbmodel cb = {
.name = "simple_circuit",
.code = simple_circuit_code,
.init = simple_circuit_init,
.read = simple_circuit_read,
.write = simple_circuit_write,
.ram = simple_circuit_ram
};
REGISTER_CBMODEL(&cb);
#endif

View file

@ -7,64 +7,109 @@
**********************************************************************************/
#include "node.h"
/* Constants from RSCAD */
#define PI 3.1415926535897932384626433832795 // definition of PI
#define TWOPI 6.283185307179586476925286766559 // definition of 2.0*PI
#define E 2.71828182845904523536028747135266 // definition of E
#define EINV 0.36787944117144232159552377016147 // definition of E Inverse (1/E)
#define RT2 1.4142135623730950488016887242097 // definition of square root 2.0
#define RT3 1.7320508075688772935274463415059 // definition of square root 3.0
#define INV_ROOT2 0.70710678118654752440084436210485
#include "log.h"
#include "nodes/cbuilder.h"
double TimeStep;
struct list cbmodels; /**< Table of existing CBuilder models */
/* Add your inputs and outputs here */
double IntfIn;
double IntfOut;
int cbuilder_parse(struct node *n, config_setting_t *cfg)
{
struct cbuilder *cb = n->_vd;
config_setting_t *cfg_params;
/* Add your parameters here */
double R2; // Resistor [Ohm] in SS2
double C2; // Capacitance [F] in SS2
#include "cbuilder/static.h"
#include "cbuilder/ram_functions.h"
const char *model;
static double getTimeStep() {
return TimeStep;
if (!config_setting_lookup_float(cfg, "timestep", &cb->timestep))
cerror(cfg, "CBuilder model requires 'timestep' setting");
if (!config_setting_lookup_string(cfg, "model", &model))
cerror(cfg, "CBuilder model requires 'model' setting");
cb->model = list_lookup(&cbmodels, model);
if (!cb->model)
cerror(cfg, "Unknown model '%s'", model);
cfg_params = config_setting_get_member(cfg, "parameters");
if (cfg_params) {
if (!config_setting_is_array(cfg_params))
cerror(cfg_params, "Model parameters must be an array of numbers!");
cb->paramlen = config_setting_length(cfg_params);
cb->params = alloc(cb->paramlen * sizeof(double));
for (int i = 0; i < cb->paramlen; i++)
cb->params[i] = config_setting_get_float_elem(cfg_params, i);
}
return 0;
}
int cbuilder_open(struct node *n)
{
/* Initialize parameters */
R2 = 1; /**< R2 = 1 Ohm */
C2 = 0.001; /**< C2 = 1000 uF */
int ret;
struct cbuilder *cb = n->_vd;
TimeStep = 50e-6;
/* Initialize mutex and cv */
pthread_mutex_init(&cb->mtx, NULL);
pthread_cond_init(&cb->cv, NULL);
#include "cbuilder/ram.h"
/* Currently only a single timestep per model / instance is supported */
cb->step = 0;
cb->read = 0;
ret = cb->model->init(cb);
if (ret)
error("Failed to intialize CBuilder model %s", node_name(n));
cb->model->ram();
return 0;
}
int cbuilder_close(struct node *n)
{
struct cbuilder *cb = n->_vd;
pthread_mutex_destroy(&cb->mtx);
pthread_cond_destroy(&cb->cv);
return 0;
}
int cbuilder_read(struct node *n, struct sample *smps[], unsigned cnt)
{
struct cbuilder *cb = n->_vd;
struct sample *smp = smps[0];
smp->values[0].f = IntfOut;
/* Wait for completion of step */
pthread_mutex_lock(&cb->mtx);
while (cb->read >= cb->step)
pthread_cond_wait(&cb->cv, &cb->mtx);
smp->length = cb->model->read(&smp->values[0].f, 16);
smp->sequence = cb->step;
cb->read = cb->step;
pthread_mutex_unlock(&cb->mtx);
return 1;
}
int cbuilder_write(struct node *n, struct sample *smps[], unsigned cnt)
{
struct cbuilder *cb = n->_vd;
struct sample *smp = smps[0];
pthread_mutex_lock(&cb->mtx);
/* Update inputs */
IntfIn = smp->values[0].f;
cb->model->write(&smp->values[0].f, smp->length);
cb->model->code();
/* Start calculation of 1 step */
#include "cbuilder/code.h"
cb->step++;
pthread_cond_signal(&cb->cv);
pthread_mutex_unlock(&cb->mtx);
return 1;
}
@ -73,8 +118,10 @@ static struct node_type vt = {
.name = "cbuilder",
.description = "RTDS CBuilder model",
.vectorize = 1,
.size = 0,
.size = sizeof(struct cbuilder),
.parse = cbuilder_parse,
.open = cbuilder_open,
.close = cbuilder_close,
.read = cbuilder_read,
.write = cbuilder_write,
};