Fix a bug reported by Tom Hajjar with title "XSPICE d_osc usage" in
Help, 2024/12/5. Also correct the timing of the request for the next call and modify a constant to make the method more robust. To support the main change, cm_analog_set_temp_bkpt() now reports when a breakpoint request is ignored, and T(x) values are set before an EVENT call.
This commit is contained in:
parent
68228ca33f
commit
721aab9624
|
|
@ -420,7 +420,6 @@ int cm_analog_set_temp_bkpt(
|
|||
{
|
||||
CKTcircuit *ckt;
|
||||
|
||||
|
||||
/* Get the address of the ckt and instance structs from g_mif_info */
|
||||
ckt = g_mif_info.ckt;
|
||||
|
||||
|
|
@ -436,7 +435,8 @@ int cm_analog_set_temp_bkpt(
|
|||
(fabs(time - ckt->CKTbreaks[0]) < ckt->CKTminBreak ||
|
||||
fabs(time - ckt->CKTbreaks[1]) < ckt->CKTminBreak)) ||
|
||||
fabs(time - ckt->CKTtime) < ckt->CKTminBreak) {
|
||||
return(MIF_OK);
|
||||
g_mif_info.errmsg = "WARNING - time is too close to existing break.";
|
||||
return MIF_ERROR;
|
||||
}
|
||||
|
||||
/* If < current dynamic breakpoint, make it the current breakpoint */
|
||||
|
|
@ -447,8 +447,6 @@ int cm_analog_set_temp_bkpt(
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cm_analog_set_perm_bkpt()
|
||||
|
||||
|
|
|
|||
|
|
@ -127,10 +127,23 @@ int EVTload_with_event(
|
|||
cm_data.circuit.anal_init = MIF_FALSE;
|
||||
cm_data.circuit.anal_type = g_mif_info.circuit.anal_type;
|
||||
|
||||
if(g_mif_info.circuit.anal_type == MIF_TRAN)
|
||||
/* Set simulation times. */
|
||||
|
||||
if (g_mif_info.circuit.anal_type == MIF_TRAN) {
|
||||
cm_data.circuit.time = g_mif_info.circuit.evt_step;
|
||||
else
|
||||
if (type == MIF_STEP_PENDING) {
|
||||
cm_data.circuit.t[0] = ckt->CKTtime;
|
||||
cm_data.circuit.t[1] = ckt->CKTtime - ckt->CKTdeltaOld[0];
|
||||
} else {
|
||||
cm_data.circuit.t[0] = ckt->CKTtime + ckt->CKTdelta;
|
||||
cm_data.circuit.t[1] = ckt->CKTtime;
|
||||
}
|
||||
if (cm_data.circuit.t[1] < 0.0)
|
||||
cm_data.circuit.t[1] = 0.0;
|
||||
} else {
|
||||
cm_data.circuit.time = 0.0;
|
||||
cm_data.circuit.t[0] = cm_data.circuit.t[1] = 0.0;
|
||||
}
|
||||
|
||||
/* Instances that have declared themselves as irreversible
|
||||
* are expected to distinguish STEP_PENDING from ordinary events.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define FACTOR 0.75 // Controls timing of next scheduled call. */
|
||||
// Controls for timing of next scheduled call. */
|
||||
|
||||
#define FACTOR1 0.75
|
||||
#define FACTOR2 0.8
|
||||
|
||||
/* PWL table entry. */
|
||||
|
||||
|
|
@ -65,7 +68,7 @@ void cm_d_osc(ARGS)
|
|||
{
|
||||
struct pwl *table;
|
||||
struct state *state;
|
||||
double ctl, delta, when;
|
||||
double ctl, period, delta, when;
|
||||
int csize, i;
|
||||
|
||||
CALLBACK = cm_d_osc_callback;
|
||||
|
|
@ -122,7 +125,7 @@ void cm_d_osc(ARGS)
|
|||
/* Set initial output and state data. */
|
||||
|
||||
ctl = INPUT(cntl_in);
|
||||
delta = get_period(ctl, table, csize);
|
||||
period = get_period(ctl, table, csize);
|
||||
|
||||
phase = PARAM(init_phase);
|
||||
phase /= 360.0;
|
||||
|
|
@ -131,12 +134,12 @@ void cm_d_osc(ARGS)
|
|||
|
||||
/* When would a hypothetical previous transition have been? */
|
||||
|
||||
state->last_time = delta * (1.0 - PARAM(duty_cycle) - phase);
|
||||
state->last_time = period * (1.0 - PARAM(duty_cycle) - phase);
|
||||
if (state->last_time < 0.0) {
|
||||
state->last = ONE;
|
||||
} else {
|
||||
state->last = ZERO;
|
||||
state->last_time = -delta * phase;
|
||||
state->last_time = -period * phase;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
@ -149,30 +152,45 @@ void cm_d_osc(ARGS)
|
|||
if (TIME == 0.0) {
|
||||
OUTPUT_STATE(out) = state->last;
|
||||
OUTPUT_STRENGTH(out) = STRONG;
|
||||
return;
|
||||
}
|
||||
|
||||
/* When is the next transition due? */
|
||||
|
||||
ctl = INPUT(cntl_in);
|
||||
delta = get_period(ctl, table, csize);
|
||||
period = get_period(ctl, table, csize);
|
||||
if (state->last)
|
||||
delta *= PARAM(duty_cycle);
|
||||
delta = period * PARAM(duty_cycle);
|
||||
else
|
||||
delta *= (1.0 - PARAM(duty_cycle));
|
||||
delta = period * (1.0 - PARAM(duty_cycle));
|
||||
when = state->last_time + delta;
|
||||
|
||||
if (TIME >= when) {
|
||||
/* If the frequency rose rapidly, the transition has been missed.
|
||||
* Force a shorter time-step and schedule then.
|
||||
* Also some choices of phase and duty cycle may be rounded
|
||||
* to produce an expected transition before time zero.
|
||||
*/
|
||||
|
||||
cm_analog_set_temp_bkpt(state->last_time + FACTOR * delta);
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
return;
|
||||
if (!cm_analog_set_temp_bkpt(state->last_time + FACTOR2 * delta)) {
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Requested breakpoint was in the fixed past, or otherwise ignored:
|
||||
* request it later.
|
||||
*/
|
||||
|
||||
if (when > T(1) && !cm_analog_set_temp_bkpt((T(1) + when) / 2)) {
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Force output immediately. */
|
||||
|
||||
when = TIME;
|
||||
}
|
||||
|
||||
if (TIME >= state->last_time + FACTOR * delta) {
|
||||
if (TIME >= state->last_time + FACTOR1 * delta) {
|
||||
/* TIME is reasonably close to transition time. Request output. */
|
||||
|
||||
state->last_time = when;
|
||||
|
|
@ -180,10 +198,16 @@ void cm_d_osc(ARGS)
|
|||
OUTPUT_STATE(out) = state->last;
|
||||
OUTPUT_STRENGTH(out) = STRONG;
|
||||
OUTPUT_DELAY(out) = when - TIME;
|
||||
if (OUTPUT_DELAY(out) < 0.0)
|
||||
OUTPUT_DELAY(out) = 0.0;
|
||||
|
||||
/* Request a call in the next half-cycle. */
|
||||
|
||||
cm_event_queue(when + FACTOR * delta);
|
||||
if (state->last)
|
||||
delta = period * PARAM(duty_cycle);
|
||||
else
|
||||
delta = period * (1.0 - PARAM(duty_cycle));
|
||||
cm_event_queue(state->last_time + FACTOR2 * delta);
|
||||
} else {
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
|
||||
|
|
@ -194,7 +218,7 @@ void cm_d_osc(ARGS)
|
|||
} else {
|
||||
/* Request a call nearer to transition time. */
|
||||
|
||||
cm_event_queue(state->last_time + FACTOR * delta);
|
||||
cm_event_queue(state->last_time + FACTOR2 * delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define FACTOR 0.75 // Controls timing of next scheduled call. */
|
||||
// Controls for timing of next scheduled call. */
|
||||
|
||||
#define FACTOR1 0.75
|
||||
#define FACTOR2 0.8
|
||||
|
||||
/* PWL table entry. */
|
||||
|
||||
|
|
@ -164,7 +167,6 @@ void cm_d_pwm(ARGS)
|
|||
if (TIME == 0.0) {
|
||||
OUTPUT_STATE(out) = state->last;
|
||||
OUTPUT_STRENGTH(out) = STRONG;
|
||||
return;
|
||||
}
|
||||
|
||||
/* When is the next transition due? */
|
||||
|
|
@ -181,12 +183,26 @@ void cm_d_pwm(ARGS)
|
|||
// If the frequency rose rapidly, the transition has been missed.
|
||||
// Force a shorter time-step and schedule then.
|
||||
|
||||
cm_analog_set_temp_bkpt(state->last_time + FACTOR * delta);
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
return;
|
||||
if (!cm_analog_set_temp_bkpt(state->last_time + FACTOR2 * delta)) {
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Requested breakpoint was in the fixed past, or otherwise ignored:
|
||||
* request it later.
|
||||
*/
|
||||
|
||||
if (when > T(1) && !cm_analog_set_temp_bkpt((T(1) + when) / 2)) {
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Force output immediately. */
|
||||
|
||||
when = TIME;
|
||||
}
|
||||
|
||||
if (TIME >= state->last_time + FACTOR * delta) {
|
||||
if (TIME >= state->last_time + FACTOR1 * delta) {
|
||||
/* TIME is reasonably close to transition time. Request output. */
|
||||
|
||||
state->last_time = when;
|
||||
|
|
@ -194,10 +210,16 @@ void cm_d_pwm(ARGS)
|
|||
OUTPUT_STATE(out) = state->last;
|
||||
OUTPUT_STRENGTH(out) = STRONG;
|
||||
OUTPUT_DELAY(out) = when - TIME;
|
||||
if (OUTPUT_DELAY(out) < 0.0)
|
||||
OUTPUT_DELAY(out) = 0.0;
|
||||
|
||||
/* Request a call in the next half-cycle. */
|
||||
|
||||
cm_event_queue(when + FACTOR * delta);
|
||||
if (state->last)
|
||||
delta *= ddc;
|
||||
else
|
||||
delta *= (1.0 - ddc);
|
||||
cm_event_queue(when + FACTOR2 * delta);
|
||||
} else {
|
||||
OUTPUT_CHANGED(out) = FALSE;
|
||||
|
||||
|
|
@ -208,7 +230,7 @@ void cm_d_pwm(ARGS)
|
|||
} else {
|
||||
/* Request a call nearer to transition time. */
|
||||
|
||||
cm_event_queue(state->last_time + FACTOR * delta);
|
||||
cm_event_queue(state->last_time + FACTOR2 * delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue