Hello,
I implemented a discrete time linear system model. It iterates system state vector, x, according to
x_{t+1} = Ax_t+Bu_t
where u is the model input.
I assumed that the entries in x should be saved in a variable allocated by cm_analog_alloc
and accessed by cm_analog_get_ptr
. But, it causes a segmentation fault.
It can be tested by building this ngspice fork based on pre-master
branch:
https://sourceforge.net/u/dmrokan/ngspice/ci/broken-dlti-model/tree/
Xspice model: https://sourceforge.net/u/dmrokan/ngspice/ci/broken-dlti-model/tree/src/xspice/icm/xtraevt/dlti/cfunc.mod
Also, implemented a workaround which works as expected in which x is stored in the array allocated for the model parameter named 'ic' (initial conditions).
https://sourceforge.net/u/dmrokan/ngspice/ci/main/tree/src/xspice/icm/xtraevt/dlti/cfunc.mod
Despite the workaround gives expected results, it seems like a wrong way to keep model states. Lastly, I would like to ask the proper way to store the state in this case.
I tested with the spice code below.
Regards,
Okan
The problem is probably that the analysis type is DC during the INIT call as the simulator is trying to find the initial conditions. That means that the code never allocates state memory.
Also it may matter that your code runs once per call, not once in a fixed time period, so the results may be unpredictable if combined with other components.
Thank you for comments.
I think using a generic global data storage functionality for each model instance would be good. I can not be sure when to allocate memory by
cm_analog_alloc
and not sure it will be available at each time model function is called.Is there a recommended way to allocate memory at the beginning of simulation and free at the end for the xspice models? By saying allocating, I mean, keeping any type of data structure, not only
double
numbers. It can surely be donecm_analog_alloc
but it seems like a workaround.I think the second is issue mentioned can be solved by adding a clock input to the model. Thank you for pointing this out, I was not aware of this.
Your use of cm_analog_alloc() looks fine, except that you need to be sure it is called during INIT. That is the standard way to do it. It allocates bytes, not doubles, so storage for any data type may be allocated, including arrays. (But if you plan to allocate pointers to other storage, be careful.)
There is an alternative: use a STATIC_VAR_TABLE to make an instance-local pointer variable and assign a value from malloc() to it. But then you have to manage everything yourself, including deallocation via the CALLBACK macro and the fact that time can go backwards during simulation. The cm_analog_alloc() mechanism handles all that for you. This is all in the manual, but it is terse and requires careful reading.
One thing that I would do differently is to allocate your storage as a block in a single call to cm_analog_alloc(). The you get back a pointer to an array of doubles and can probably eliminate the malloc()ed block of working storage. (If not, it would be more efficient to use alloca() or a dynamic-sized automatic array in an inner block. (C99 is assumed.)).
A clock input will certainly work to control the rate of iteration, You can also do it internally, by using cm_analog_set_perm_bkpt(). to get called when the next iteration is due. But be aware that you may not be called at exactly the right time, and it may be very slightly early.
Last edit: Giles Atkinson 2023-06-05
Thanks a lot.
Updated the model according to the suggestions, now it became a proper discrete time linear system block.