-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add documentation for custom scripts
- Loading branch information
Showing
2 changed files
with
100 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,98 @@ | ||
# Tutorial - Using Custom Scripts to Preprocess Simulation Results | ||
# Using Custom Scripts to Postprocess Simulation Results | ||
|
||
```{warning} | ||
Custom scripts are still a WIP and the function signature of `postprocess` might still change! | ||
``` | ||
|
||
This tutorial shows how to use custom Python scripts to postprocess simulation results of the `ngspice` tool. | ||
|
||
This feature can be used to extract certain parameters from simulation results. For example, it could be used to calculate the INL, DNL, offset error and gain error of a DAC. An example of this can be seen in [sky130_ef_ip__rdac3v_8bit](https://github.com/RTimothyEdwards/sky130_ef_ip__rdac3v_8bit). | ||
|
||
For a step-by-step guide on how to set up custom scripts, please see below. | ||
|
||
## Specifying Custom Scripts in the Datasheet | ||
|
||
At present, only the `ngspice` tool allows postprocessing of the simulation results. Please have a look at its arguments at {doc}`../reference_manual/tools`. | ||
|
||
To add a custom script for postprocessing, you simply need to specify the `script` and `script_variables` arguments. | ||
|
||
```yaml | ||
tool: | ||
ngspice: | ||
template: voltage_output.sch | ||
collate: iterations | ||
format: ascii | ||
suffix: .data | ||
variables: [null, vout] | ||
script: inl.py | ||
script_variables: [inl] | ||
``` | ||
The `script` argument defines the name of the Python script that is called for each of the simulation results. The `script_variables` argument defines the results generated by the script. In this case, the script generates a single variable called `dnl`. The variables can then be used in the `spec` or `plot` section as if they came from the simulation run itself. The script needs to be placed in the `scripts` folder of CACE. | ||
|
||
CACE expects the custom script to provide a function called `postprocess`. The function signature of `postprocess` is as follows: | ||
|
||
```Python | ||
def postprocess(results: dict[str, list], conditions: dict[str, Any], collate: str|None) -> dict[str, list]: | ||
``` | ||
|
||
The `results` argument contains the results of a single simulation run. Since `variables: [null, vout]` is set in the datasheet, `results` contains a single key `vout` with a list of values (`results['vout'] = [..., ...]`). The `conditions` argument contains the conditions for this simulation run. For example, it contains a key `temperature` with the value for this simulation run, e.g. `27` (`conditions['temperature'] = 27`). | ||
|
||
If you collate simulation results based on a condition, then this condition will contain a list of values instead of a single value. For a Monte Carlo simulation that is collated with the `iterations` condition, `conditions['iterations']` contains a list of all the iterations for all collated simulations (`conditions['iterations'] = [1, 2, 3...]`). | ||
|
||
The return value of `postprocess` is another dictionary that must contain the keys specified in the `script_variables` argument in the datasheet. In this case `{'inl': [..., ...]}` is returned, where the list can also contain only a single value. | ||
|
||
To get a feel for the data being passed to your script, you can simply print `results` and `conditions` and return an empty dictionary. (Note that `script_variables` in the datasheet must be an empty list as this script does not return any results.) | ||
|
||
```Python | ||
def postprocess(results: dict[str, list], conditions: dict[str, Any]) -> dict[str, list]: | ||
print(f'results: {results}') | ||
print(f'conditions: {conditions}') | ||
return {} | ||
``` | ||
|
||
For a real example, see the contents of `inl.py`: | ||
|
||
```Python | ||
def postprocess(results: dict[str, list], conditions: dict[str, Any]) -> dict[str, list]: | ||
print(f'results: {results}') | ||
print(f'conditions: {conditions}') | ||
# INL calculation: | ||
# x is the digital value b7:0 converted to an integer | ||
# V(x) is the original value in RESULT: The voltage output of the DAC | ||
# under the given set of conditions. | ||
# ALSB = (Vhigh - Vlow) / 256 (ideal voltage step size per LSB) | ||
# | ||
# INL(x) = (RESULT - (x * ALSB + Vlow)) / ALSB (in units of LSB) | ||
# | ||
# NOTE that this DAC is based on 256 steps with the highest step being | ||
# 1 lsb below Vhigh. | ||
Vhigh = float(conditions['Vhigh']) | ||
Vlow = float(conditions['Vlow']) | ||
x = float(conditions['b']) | ||
alsb = (Vhigh - Vlow) / 256 | ||
inl = [] | ||
# Iterate over MC results | ||
for vout in results['vout']: | ||
inl.append((vout - (x * alsb + Vlow)) / alsb) | ||
return {'inl': inl} | ||
``` | ||
|
||
For a simulation run the result might look like this in the summary: | ||
|
||
``` | ||
Parameter Tool Result Min Limit Min Value Typ Target Typ Value Max Limit Max Value Status | ||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
INL ngspice inl -2 lsb 0.998 lsb 0 lsb 1.136 lsb 2 lsb 3.995 lsb Fail ❌ | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters