kicad/tools/generate_sim_model_ngspice_...

463 lines
15 KiB
Bash
Executable File

#!/bin/bash
# This is a very dirty script that is sometimes used to generate data for
# sim_model_ngspice_data.cpp. To generate, write the models you want to generate in the MODELS
# variable in the format shown below. You may need to do many post-generation edits to make it
# compile -- this script is quite outdated.
#MODELS=$(cat << END
# hicum2 NPN PNP Q 3 8 0
# jfet2 NJF PJF J 3 2 0
# mesa NMF PMF Z 3 2 0
# hfet1 NMF PMF Z 4 0 0
# hfet2 NMF PMF Z 3 0 0
# hisimhv1 NMOS PMOS M 4 73 1.2.4
# hisimhv2 NMOS PMOS M 4 73 2.2.0
#END
#)
MODELS=$(cat << END
vdmos NCHAN PCHAN M 3 0 0
END
)
UNITS=$(cat << END
%/deg C
exponent alternative
-
exponent
normalized length
ohm/m
sheet resistance
resistance per meter
resistance per metre
resistance per length
resistance per unit length
/ohm m
conductance per meter
conductance per metre
ohm
resistance
impedance
resistor model default value
F/m^2
cap per area
F/m
capacitance per meter
capacitance per metre
overlap cap
capacitance per length
capacitance per unit length
capacitance grading coefficient per unit length
F
capacitance
cap\.
H/m
inductance per meter
inductance per metre
inductance per length
inductance per unit length
H
inductance
1/W
coef of thermal current reduction
sqrt V
bulk effect coefficient 1
bulk threshold parameter
1/V
channel length modulation
vgs dependence on mobility
V/cm
Crit\. field for mob\. degradation
V
voltage
potential
A/V^2
transconductance parameter
A/m^2
current density
A/m
current per meter
current per metre
current per length
current per unit length
A
current
ohm/deg C^2
second order temp\. coefficient
ohm/deg C
first order temp\. coefficient
1/deg C^2
grading coefficient 1st temp\. coeff
1/deg C
grading coefficient 2nd temp\. coeff
deg C/W
thermal resistance
deg C
temperature
eV
energy
cm^2/V^2 s
VBS dependence on muz
VBS dependence on mus
VDS dependence on mus
cm^2/V s
zero field mobility
surface mobility
um/V^2
VDS depence of u1
um
.* in um
1/cm^3
substrate doping
1/cm^2
surface state density
fast surface state density
m/s
velocity
m
length
width
thickness
narrowing of
shortening of
C
epi charge parameter
s
time
delay
Hz
frequency
deg
excess phase
-
.*
END
)
category()
{
model_name="$1"
param_name="$2"
param_flags="$3"
param_description="$4"
is_instance_param="$5"
if [ "$param_type" = "flag" ]; then
echo "FLAGS"
elif [[ "$model_name" = "resistor" && "$param_description" = "Resistor model default value" ]] \
|| [[ "$model_name" = "resistor" && "$param_description" = "Default device length" ]] \
|| [[ "$model_name" = "resistor" && "$param_name" = "defw" ]] \
|| [[ "$model_name" = "resistor" && "$param_name" = "defl" ]] \
|| [[ "$model_name" = "resistor" && "$param_name" = "narrow" ]] \
|| [[ "$model_name" = "resistor" && "$param_name" = "short" ]] \
|| [[ "$model_name" = "capacitor" && "$param_description" = "Capacitor model" ]] \
|| [[ "$model_name" = "capacitor" && "$param_description" = "Model capacitance" ]] \
|| [[ "$model_name" = "capacitor" && "$param_name" = "defw" ]] \
|| [[ "$model_name" = "capacitor" && "$param_name" = "defl" ]] \
|| [[ "$model_name" = "capacitor" && "$param_name" = "narrow" ]] \
|| [[ "$model_name" = "capacitor" && "$param_name" = "short" ]] \
|| [[ "$model_name" = "capacitor" && "$param_name" = "del" ]] \
|| [[ "$model_name" = "inductor" && "$param_description" = "Inductor model" ]] \
|| [[ "$model_name" = "ltra" && "$param_name" = "ltra" ]] \
|| [[ "$model_name" = "urc" && "$param_name" = "urc" ]] \
|| [[ "$model_name" = "transline" && "$param_description" = "Length of line" ]] \
|| [[ "$model_name" = "transline" && "$param_name" = "txl" ]] \
|| [[ "$model_name" = "transline" && "$param_name" = "pos_node" ]] \
|| [[ "$model_name" = "transline" && "$param_name" = "neg_node" ]] \
|| grep -iE "R" <<< "$param_flags" >/dev/null
then
echo "SUPERFLUOUS"
elif grep -iE "initial condition" <<< "$param_description" >/dev/null \
|| grep -iE "initial voltage" <<< "$param_description" >/dev/null \
|| grep -iE "initial current" <<< "$param_description" >/dev/null
then
echo "INITIAL_CONDITIONS"
elif [[ "$model_name" = "ltra" && "$param_name" = "compactrel" ]] \
|| [[ "$model_name" = "ltra" && "$param_name" = "compactabs" ]] \
|| [[ "$model_name" = "urc" && "$param_name" = "n" ]] \
|| [[ "$model_name" = "urc" && "$param_name" = "isperl" ]] \
|| [[ "$model_name" = "urc" && "$param_name" = "rsperl" ]] \
|| [[ "$model_name" = "urc" && "$param_name" = "compactrel" ]] \
|| [[ "$model_name" = "urc" && "$param_name" = "compactabs" ]]
then
echo "ADVANCED"
elif [ "$model_name" = "ltra" ] \
|| [ "$model_name" = "tranline" ] \
|| [ "$model_name" = "urc" ] \
|| [ "$model_name" = "transline" ] \
|| [ "$param_name" = "resistance" ] \
|| [ "$param_name" = "capacitance" ] \
|| [ "$param_name" = "inductance" ] # We make possibly bad exceptions for some instance parameters here.
then
echo "PRINCIPAL"
elif [ "$is_instance_param" = 1 ]; then
if [[ "$param_name" = "l" || "$param_name" = "w" || "$param_name" = "m" ]]; then
echo "GEOMETRY"
else
# Discard the instance parameters.
echo "SUPERFLUOUS"
fi
elif grep -iE "_max$" <<< "$param_name" >/dev/null; then
if [ "$is_instance_param" = 0 ]; then
echo "LIMITING"
else
# Discard the instance parameters.
echo "SUPERFLUOUS"
fi
elif [[ "$model_name" = "resistor" && "$param_name" = "rsh" ]] \
|| [[ "$model_name" = "capacitor" && "$param_name" = "di" ]] \
|| [[ "$model_name" = "capacitor" && "$param_name" = "thick" ]] \
|| [[ "$model_name" = "capacitor" && "$param_name" = "cj" ]] \
|| [[ "$model_name" = "capacitor" && "$param_name" = "cjsw" ]]
then
echo "GEOMETRY"
elif grep -iE "temperature" <<< "$param_description" >/dev/null \
|| grep -iE "temp\. coeff" <<< "$param_description" >/dev/null \
|| grep -iE "thermal resistance" <<< "$param_description" >/dev/null
then
echo "TEMPERATURE"
elif grep -iE "noise" <<< "$param_description" >/dev/null; then
echo "NOISE"
else
if [ "$is_instance_param" = 0 ]; then
echo "DC"
else
echo "SUPERFLUOUS"
fi
fi
}
run_ngspice()
{
ngspice -n 2>/dev/null << END
*
$1
.control
$2
.endc
END
}
{
echo "$MODELS" | while read -r model_name \
model_type1 \
model_type2 \
model_primitive \
model_pin_count \
model_level \
model_version
do
if [ -n "$model_name" ]; then
# Print model description.
run_ngspice "" "devhelp -type -flags $model_name" | while read -r name \
sep \
description
do
if [ "$sep" = "-" ]; then
echo -n "modelInfos[MODEL_TYPE::${model_name^^}] = "
echo -n "{ \"$name\","
for model_type in "$model_type1" "$model_type2"; do
if [ "$model_type" != "-" ]; then
echo -n " \"$model_type\","
else
echo -n " \"\","
fi
done
echo -n " \"$description\","
fi
done
echo " {}, {} };"
is_instance_param=0
# Print model parameter ID, name, direction, type, unit, and description.
run_ngspice "" "devhelp -type -flags $model_name" | while read -r param_id \
param_name \
param_dir \
param_type \
param_flags \
param_description
do
#&& [ -n "$param_description" ]
if [ "$param_id" = "Model" ] && [ "$param_name" = "Parameters" ]; then
echo "// Model parameters"
elif [ "$param_id" = "Instance" ] && [ "$param_name" = "Parameters" ]; then
echo "// Instance parameters"
is_instance_param=1
elif [ "$param_id" -eq "$param_id" ] 2>/dev/null \
&& [ -n "$param_name" ] \
&& [ -n "$param_dir" ]
then
if [ "$is_instance_param" = 1 ]; then
params="instanceParams"
else
params="modelParams"
fi
echo -n "modelInfos[MODEL_TYPE::${model_name^^}].${params}.emplace_back( \"${param_name,,}\","
echo -n " $param_id,"
echo -n " NGSPICE::PARAM_DIR::${param_dir^^},"
echo -n " NGSPICE::PARAM_TYPE::${param_type^^},"
if [ "$param_flags" != "-" ]; then
echo -n " $param_flags(),"
else
echo -n " {},"
fi
unit=""
# Non-reals are unlikely to have units.
if [ "$param_type" = "real" ]; then
# Simple finite state machine to read the UNITS string line by line.
# Maybe an if-elif-else statement would have been better?
# Don't use a pipe here because it creates a subshell, preventing the
# changes to the variables from propagating upwards. Bash is cursed.
while read -r pattern; do
if [ "$unit" = "" ]; then
unit="$pattern"
elif [ -z "$pattern" ]; then
unit=""
elif grep -iE "$pattern" <<< "$param_description" >/dev/null; then
break
fi
done <<< "$UNITS"
fi
if [ "$unit" = "-" ]; then
unit=""
fi
echo -n " \"$unit\","
echo -n " NGSPICE::PARAM_CATEGORY::"$(category "$model_name" "$param_name" "$param_flags" "$param_description" "$is_instance_param")","
for model_type in "$model_type1" "$model_type2"; do
if [ "$model_type" = "-" ]; then
echo -n " \"\","
continue
fi
model_instance_name="$model_type"
# Special cases for VDMOS because it has a weird syntax.
if [ "$model_type" = "NCHAN" ]; then
model_type="$model_name NCHAN"
fi
if [ "$model_type" = "PCHAN" ]; then
model_type="$model_name PCHAN"
fi
# For a given primitive, Ngspice determines the device model to be used
# from two parameters: "level" and "version".
params=""
if [ "$model_level" != 0 ]; then
params="$params level=$model_level"
fi
if [ "$model_version" != 0 ]; then
params="$params version=$model_version"
fi
netlist=$(cat << END
.model $model_instance_name $model_type $params
${model_primitive}1 $(seq -s ' ' $model_pin_count) $model_instance_name
END
)
control=$(cat << END
op
showmod ${model_primitive}1 : $param_name
END
)
was_model_line=0
was_echoed=0
# Again don't use a pipe.
while read -r name value; do
# Ngspice displays only the first 11 characters of the variable name.
# We also convert to lowercase because a few parameter names have
# uppercase characters in them.
lowercase_name=${name,,}
lowercase_param_name=${param_name,,}
if [ "$was_model_line" = 0 ] && [ "$lowercase_name" = "model" ]; then
was_model_line=1
elif [ "$was_model_line" = 1 ] \
&& [ "$lowercase_name" = "${lowercase_param_name:0:11}" ]
then
if [ "$value" = "<<NAN, error = 7>>" ]; then
value="NaN"
elif [ "$value" = "?????????" ]; then
value=""
fi
was_echoed=1
echo -n " \"$value\","
fi
done < <(run_ngspice "$netlist" "$control")
#if [ "$was_echoed" = 0 ]; then
#echo ""
#echo "Error! Default value not found."
#exit 1
#fi
done
echo " \"$param_description\" );"
fi
done
fi
done
} > $(dirname "$0")/new_ngspice_models.cpp