C-Block — Custom Computation Blocks¶
C-Blocks let you inject arbitrary signal-domain logic into a Pulsim circuit without modifying the simulator's C++ core. You write a small C function (or a Python callable), the runtime loads it as a shared library, and it becomes a first-class block in the signal-evaluation graph — with the same wire-based connectivity as any built-in block.
Why use a C-Block?¶
| Scenario | Recommendation |
|---|---|
| Standard filter, gain, integrator | Use built-in blocks (PI_CONTROLLER, TRANSFER_FUNCTION, …) |
| Lookup table, custom non-linearity | C-Block — direct C code, no overhead |
| Algorithm you already have in C | C-Block — just add the ABI wrapper |
| Rapid prototyping, no compiler | PythonCBlock — Python callable, zero compilation |
| Full device model (electrical ports) | C++ extension in core/ (different path) |
Quick-start (5 lines)¶
from pulsim.cblock import compile_cblock, CBlockLibrary
lib = compile_cblock("gain3x.c", name="gain3x")
blk = CBlockLibrary(lib, n_inputs=1, n_outputs=1)
print(blk.step(0.0, 1e-6, [2.0])) # → [6.0]
Where gain3x.c is:
#include "pulsim/v1/cblock_abi.h"
PULSIM_CBLOCK_EXPORT int pulsim_cblock_abi_version = PULSIM_CBLOCK_ABI_VERSION;
PULSIM_CBLOCK_EXPORT int pulsim_cblock_step(
PulsimCBlockCtx* ctx, double t, double dt,
const double* in, double* out)
{
(void)ctx; (void)t; (void)dt;
out[0] = 3.0 * in[0];
return 0;
}
Two paths¶
Your logic
│
├─── C source (.c) ─── compile_cblock() ─── CBlockLibrary ─┐
│ ├─ SignalEvaluator
└─── Python callable ──── PythonCBlock ──────────────────────┘
CBlockLibrary loads a compiled shared library (.so / .dylib / .dll).
Use it for performance-critical code, code you already have in C, or anything that
needs malloc / file I/O.
PythonCBlock wraps any Python function.
Use it for prototyping: no compiler, no build step, same API.
Using in a YAML netlist¶
schema: pulsim-v1
version: 1
components:
- type: voltage_probe
name: ERR
nodes: [sig_in, 0]
- type: c_block
name: MY_GAIN
nodes: []
n_inputs: 1
n_outputs: 1
inputs: [ERR]
source: path/to/gain3x.c
c_block is control-domain only in the mixed-domain runtime:
inputs must come from control channels (for example probes, controllers, or
other virtual channels), and outputs are emitted as control channels.