Update to the SEEgenerator as describes in README.SEEgenerator
This commit is contained in:
parent
abcbcbd724
commit
8b32c743ae
|
|
@ -39,6 +39,23 @@ As literature please see for example
|
|||
Single-Event Effects, from Space to Accelerator Environments
|
||||
Springer 2025
|
||||
|
||||
There is an alternative pulse variant possible by setting the parameters scdelay and scaling.
|
||||
In advanced process nodes a single particle hit with its electron/hole pairs generated may
|
||||
influence not only a single node, but several neighboring nodes as well, may be a little less
|
||||
and with a small delay. This behaviour may be emulated by connecting SEEgen to a central node
|
||||
and some surrounding nodes. These will get a portion of the charge carriers, with a possible
|
||||
(small) delay. The .model line
|
||||
|
||||
.model seemod1 seegen (tdelay = 400p tperiod=500p tfall='tfall' trise='trise' let='let' cdepth='d'
|
||||
+ perlim=TRUE ctrlthres=0 scaling=[1, 0.5, 0.25, 0.125] scdelay=[0, 10p, 20p, 30p])
|
||||
|
||||
now contain the arrays scaling and scdelay. The nummber of array elements has to equal the number
|
||||
of ports. Scaling will distribute the LET onto the different nodes with each weight given.
|
||||
Scdelay will delay each port relative to the parameter tdelay. Parameters tperiod, perlim, and
|
||||
ctrlthres are ignored for now. As the netlist does not contain information on the location of the
|
||||
nodes in the layout, the user has to provide these data be selecting the proper nodes and pulse
|
||||
scaling.
|
||||
|
||||
Detailed description (will be added to the manual):
|
||||
|
||||
NAME_TABLE:
|
||||
|
|
@ -131,6 +148,25 @@ Vector: no no
|
|||
Vector_Bounds: - -
|
||||
Null_Allowed: yes yes
|
||||
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: scaling scdelay
|
||||
Description: "scale the current" "delay scaled pulses individually"
|
||||
Data_Type: real real
|
||||
Default_Value: 1 0
|
||||
Limits: [0 1] [0, -]
|
||||
Vector: yes yes
|
||||
Vector_Bounds: - -
|
||||
Null_Allowed: yes yes
|
||||
|
||||
STATIC_VAR_TABLE:
|
||||
|
||||
Static_Var_Name: pulses
|
||||
Data_Type: pointer
|
||||
Vector: no
|
||||
Description: "info on pulse for each port"
|
||||
|
||||
STATIC_VAR_TABLE:
|
||||
|
||||
Static_Var_Name: last_t_value
|
||||
|
|
|
|||
|
|
@ -55,7 +55,17 @@ NON-STANDARD FEATURES
|
|||
|
||||
|
||||
|
||||
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
|
||||
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
|
||||
|
||||
typedef struct pulse_info
|
||||
{
|
||||
double iscaled; /* scaled current pulse for this port */
|
||||
double start_time; /* pulse start time for this port */
|
||||
double next_start_time; /* next pulse start time for this port */
|
||||
} pulse_info_t;
|
||||
|
||||
|
||||
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
|
||||
|
||||
static void
|
||||
cm_seegen_callback(ARGS, Mif_Callback_Reason_t reason)
|
||||
|
|
@ -74,18 +84,14 @@ cm_seegen_callback(ARGS, Mif_Callback_Reason_t reason)
|
|||
if (last_ctrl)
|
||||
free(last_ctrl);
|
||||
STATIC_VAR (last_ctrl) = NULL;
|
||||
pulse_info_t *pulses = STATIC_VAR (pulses);
|
||||
if (pulses)
|
||||
free(pulses);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
|
||||
FUNCTION void cm_seegen()
|
||||
|
|
@ -144,6 +150,10 @@ void cm_seegen(ARGS) /* structure holding parms,
|
|||
double *last_ctrl; /* static storage of last ctrl value */
|
||||
double tcurr = TIME; /* current simulation time */
|
||||
|
||||
int ports; /* number of output ports */
|
||||
pulse_info_t *allpulses; /* info for pulse on each port */
|
||||
bool have_scaled = FALSE;/* TRUE if we want to use scaled pulses */
|
||||
|
||||
if (ANALYSIS == MIF_AC) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -160,6 +170,10 @@ void cm_seegen(ARGS) /* structure holding parms,
|
|||
angle = PARAM(angle);
|
||||
ctrlthres = PARAM(ctrlthres);
|
||||
|
||||
have_scaled = !PARAM_NULL(scaling) && !PARAM_NULL(scdelay);
|
||||
|
||||
ports = PORT_SIZE(out);
|
||||
|
||||
if (PORT_NULL(ctrl))
|
||||
ctrl = 1;
|
||||
else
|
||||
|
|
@ -167,73 +181,145 @@ void cm_seegen(ARGS) /* structure holding parms,
|
|||
|
||||
if (INIT==1) {
|
||||
|
||||
int i;
|
||||
double sum = 0;
|
||||
|
||||
if (have_scaled && PARAM_SIZE(scaling) != ports) {
|
||||
cm_message_send("Error: Number of Output ports and Scaling don't match\n");
|
||||
cm_cexit(1);
|
||||
}
|
||||
|
||||
if (have_scaled && PARAM_SIZE(scdelay) != ports) {
|
||||
cm_message_send("Error: Number of Output ports and SCdelay don't match\n");
|
||||
cm_cexit(1);
|
||||
}
|
||||
|
||||
if (5 * (trise + tfall) > tperiod) {
|
||||
cm_message_send("\nError: tperiod should be at least 5 times the sum of trise and tfall\n");
|
||||
cm_cexit(1);
|
||||
}
|
||||
|
||||
CALLBACK = cm_seegen_callback;
|
||||
|
||||
/* Allocate storage for last_t_value */
|
||||
STATIC_VAR(last_t_value) = (double *) malloc(sizeof(double));
|
||||
last_t_value = (double *) STATIC_VAR(last_t_value);
|
||||
/* no start if ctrl is set */
|
||||
if (PORT_NULL(ctrl))
|
||||
*last_t_value = tdelay;
|
||||
else
|
||||
*last_t_value = 1e12;
|
||||
STATIC_VAR(pulse_number) = (int *) malloc(sizeof(int));
|
||||
pulse_number = (int *) STATIC_VAR(pulse_number);
|
||||
*pulse_number = 1;
|
||||
STATIC_VAR(last_ctrl) = (double *) malloc(sizeof(double));
|
||||
last_ctrl = (double *) STATIC_VAR(last_ctrl);
|
||||
*last_ctrl = ctrl;
|
||||
/* set breakpoints at first pulse start and pulse maximum times */
|
||||
double tatmax = *last_t_value + tfall * trise * log(trise/tfall) / (trise - tfall);
|
||||
cm_analog_set_perm_bkpt(*last_t_value);
|
||||
cm_analog_set_perm_bkpt(tatmax);
|
||||
}
|
||||
else {
|
||||
if (have_scaled) {
|
||||
int j;
|
||||
double del = 1e12;
|
||||
|
||||
last_t_value = (double *) STATIC_VAR(last_t_value);
|
||||
pulse_number = (int *) STATIC_VAR(pulse_number);
|
||||
last_ctrl = (double *) STATIC_VAR(last_ctrl);
|
||||
cm_message_send("Use the scaling option\n");
|
||||
|
||||
/* reset the pulse sequence, to start anew upon a rising ctrl */
|
||||
if (*last_ctrl < ctrlthres && ctrl >= ctrlthres) {
|
||||
*last_t_value = tcurr + tdelay;
|
||||
*pulse_number = 1;
|
||||
}
|
||||
*last_ctrl = ctrl;
|
||||
allpulses = STATIC_VAR(pulses) = (pulse_info_t *) malloc(ports * sizeof(pulse_info_t));
|
||||
|
||||
/* the double exponential current pulse function */
|
||||
if (tcurr < *last_t_value)
|
||||
out = 0;
|
||||
else {
|
||||
/* parameter inull not specified, calculate it */
|
||||
if (inull == 0) {
|
||||
double LETeff = let/cos(angle);
|
||||
double Qc = 1.035e-14 * LETeff * cdepth;
|
||||
inull = Qc / (tfall - trise);
|
||||
}
|
||||
out = inull * (exp(-(tcurr-*last_t_value)/tfall) - exp(-(tcurr-*last_t_value)/trise));
|
||||
|
||||
/* pulse currents are scaled, and find minimum time delay */
|
||||
for (i = 0; i < ports; i++){
|
||||
sum += PARAM(scaling[i]);
|
||||
}
|
||||
if (sum == 0.) {
|
||||
cm_message_send("Error: Scaling parameters are zero\n");
|
||||
cm_cexit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < ports; i++){
|
||||
allpulses[i].iscaled = PARAM(scaling[i]) / sum * inull;
|
||||
allpulses[i].start_time = tdelay + PARAM(scdelay[i]);
|
||||
double tatmax = allpulses[i].start_time + tfall * trise * log(trise/tfall) / (trise - tfall);
|
||||
cm_analog_set_perm_bkpt(allpulses[i].start_time);
|
||||
cm_analog_set_perm_bkpt(tatmax);
|
||||
}
|
||||
}
|
||||
if (tcurr > *last_t_value + tperiod * 0.9) {
|
||||
/* return some info */
|
||||
cm_message_printf("port name: out, node pair no.: %d, \nnode names: %s, %s, pulse time: %e",
|
||||
*pulse_number, cm_get_node_name("out", *pulse_number - 1),
|
||||
cm_get_neg_node_name("out", *pulse_number - 1), *last_t_value);
|
||||
/* set the time for the next pulse */
|
||||
*last_t_value = *last_t_value + tperiod;
|
||||
/* set breakpoints at new pulse start and pulse maximum times */
|
||||
else {
|
||||
/* Allocate storage for last_t_value */
|
||||
STATIC_VAR(last_t_value) = (double *) malloc(sizeof(double));
|
||||
last_t_value = (double *) STATIC_VAR(last_t_value);
|
||||
/* no start if ctrl is set */
|
||||
if (PORT_NULL(ctrl))
|
||||
*last_t_value = tdelay;
|
||||
else
|
||||
*last_t_value = 1e12;
|
||||
STATIC_VAR(last_ctrl) = (double *) malloc(sizeof(double));
|
||||
last_ctrl = (double *) STATIC_VAR(last_ctrl);
|
||||
*last_ctrl = ctrl;
|
||||
STATIC_VAR(pulse_number) = (int *) malloc(sizeof(int));
|
||||
pulse_number = (int *) STATIC_VAR(pulse_number);
|
||||
*pulse_number = 1;
|
||||
|
||||
/* set breakpoints at first pulse start and pulse maximum times */
|
||||
double tatmax = *last_t_value + tfall * trise * log(trise/tfall) / (trise - tfall);
|
||||
cm_analog_set_perm_bkpt(*last_t_value);
|
||||
cm_analog_set_perm_bkpt(tatmax);
|
||||
(*pulse_number)++;
|
||||
if (*pulse_number > PORT_SIZE(out)) {
|
||||
if (PARAM(perlim) == FALSE)
|
||||
*pulse_number = 1;
|
||||
}
|
||||
}
|
||||
/* after initialization */
|
||||
else {
|
||||
/* individual scaling and delay */
|
||||
|
||||
if (have_scaled) {
|
||||
/* */
|
||||
int i;
|
||||
allpulses = (pulse_info_t *) STATIC_VAR(pulses);
|
||||
for (i = 0; i < ports; i++){
|
||||
double tst = allpulses[i].start_time;
|
||||
if (tcurr < tst)
|
||||
out = 0;
|
||||
else
|
||||
*last_t_value = 1e12; /* stop any output */
|
||||
out = allpulses[i].iscaled * (exp(-(tcurr-tst)/tfall) - exp(-(tcurr-tst)/trise));
|
||||
OUTPUT(out[i]) = out;
|
||||
OUTPUT(mon) = out;
|
||||
}
|
||||
}
|
||||
if (*pulse_number - 1 < PORT_SIZE(out)) {
|
||||
OUTPUT(out[*pulse_number - 1]) = out;
|
||||
OUTPUT(mon) = out;
|
||||
/* equal pulses, period, and repetition */
|
||||
else {
|
||||
last_t_value = (double *) STATIC_VAR(last_t_value);
|
||||
pulse_number = (int *) STATIC_VAR(pulse_number);
|
||||
last_ctrl = (double *) STATIC_VAR(last_ctrl);
|
||||
|
||||
/* reset the pulse sequence, to start anew upon a rising ctrl */
|
||||
if (*last_ctrl < ctrlthres && ctrl >= ctrlthres) {
|
||||
*last_t_value = tcurr + tdelay;
|
||||
*pulse_number = 1;
|
||||
}
|
||||
*last_ctrl = ctrl;
|
||||
|
||||
/* the double exponential current pulse function */
|
||||
if (tcurr < *last_t_value)
|
||||
out = 0;
|
||||
else {
|
||||
if (inull == 0) {
|
||||
double LETeff = let/cos(angle);
|
||||
double Qc = 1.035e-14 * LETeff * cdepth;
|
||||
inull = Qc / (tfall - trise);
|
||||
}
|
||||
out = inull * (exp(-(tcurr-*last_t_value)/tfall) - exp(-(tcurr-*last_t_value)/trise));
|
||||
}
|
||||
if (tcurr > *last_t_value + tperiod * 0.9) {
|
||||
/* return some info */
|
||||
cm_message_printf("port name: out, node pair no.: %d, \nnode names: %s, %s, pulse time: %e",
|
||||
*pulse_number, cm_get_node_name("out", *pulse_number - 1),
|
||||
cm_get_neg_node_name("out", *pulse_number - 1), *last_t_value);
|
||||
/* set the time for the next pulse */
|
||||
*last_t_value = *last_t_value + tperiod;
|
||||
/* set breakpoints at new pulse start and pulse maximum times */
|
||||
double tatmax = *last_t_value + tfall * trise * log(trise/tfall) / (trise - tfall);
|
||||
cm_analog_set_perm_bkpt(*last_t_value);
|
||||
cm_analog_set_perm_bkpt(tatmax);
|
||||
(*pulse_number)++;
|
||||
if (*pulse_number > PORT_SIZE(out)) {
|
||||
if (PARAM(perlim) == FALSE)
|
||||
*pulse_number = 1;
|
||||
else
|
||||
*last_t_value = 1e12; /* stop any output */
|
||||
}
|
||||
}
|
||||
if (*pulse_number - 1 < PORT_SIZE(out)) {
|
||||
OUTPUT(out[*pulse_number - 1]) = out;
|
||||
OUTPUT(mon) = out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,25 @@ Vector: no no
|
|||
Vector_Bounds: - -
|
||||
Null_Allowed: yes yes
|
||||
|
||||
|
||||
PARAMETER_TABLE:
|
||||
|
||||
Parameter_Name: scaling scdelay
|
||||
Description: "scale the current" "delay scaled pulses individually"
|
||||
Data_Type: real real
|
||||
Default_Value: 1 0
|
||||
Limits: [0 1] [0, -]
|
||||
Vector: yes yes
|
||||
Vector_Bounds: - -
|
||||
Null_Allowed: yes yes
|
||||
|
||||
STATIC_VAR_TABLE:
|
||||
|
||||
Static_Var_Name: pulses
|
||||
Data_Type: pointer
|
||||
Vector: no
|
||||
Description: "info on pulse for each port"
|
||||
|
||||
STATIC_VAR_TABLE:
|
||||
|
||||
Static_Var_Name: last_t_value
|
||||
|
|
|
|||
Loading…
Reference in New Issue