diff --git a/examples/xspice/pwm-osc/fmcw-dosc.cir b/examples/xspice/pwm-osc/fmcw-dosc.cir new file mode 100644 index 000000000..64c9945fe --- /dev/null +++ b/examples/xspice/pwm-osc/fmcw-dosc.cir @@ -0,0 +1,46 @@ +Emulate FMCW RADAR +* with two controlled digital oscillators +* signal delay between Vin1 and Vin2 --> frequency shift +* delay 20m --> shift 900 Hz, 10m --> 450 Hz + +.param rdelay = 20m + +* emitted signal (repeated frequency ramp) +Vin1 ain1 0 pulse (-1 1 0 200m 200m 1n 200m) +aosc1 ain1 dout1 var_clock +* emulate backscattered signal with delay (due to distant target) +Vin2 ain2 0 pulse (-1 1 {rdelay} 200m 200m 1n 200m) +aosc2 ain2 dout2 var_clock + +.model var_clock d_osc(cntl_array = [-2 -1 1 2] ++ freq_array = [1e3 1e3 10e3 10e3] ++ duty_cycle = 0.4 init_phase = 180.0 ++ rise_delay = 10e-9 fall_delay=8e-9) + +** generate the beat frequency +* AND gate as analog multiplier with i/o amplitude 1 +aand1 [dout1 dout2] mout and1 +.model and1 d_and(rise_delay = 0.5e-9 fall_delay = 0.3e-9 ++ input_load = 0.5e-12) + +* low pass filter +Rf1 mout afout 1k +Cf1 afout 0 1u + +.tran 10u 1 + +.control +run +rusage +plot ain1 ain2 dout1 dout2 +plot mout afout +plot afout +* measure the beat frequency (aka instantaneous frequency shift) +linearize afout +fft afout +let mafout = mag(afout) +plot mafout xlimit 0 1k ylimit 0 0.2 +meas sp maxout max mafout from=10 to=1k +.endc + +.end diff --git a/examples/xspice/pwm-osc/pwm-sin.cir b/examples/xspice/pwm-osc/pwm-sin.cir new file mode 100644 index 000000000..7a5299a47 --- /dev/null +++ b/examples/xspice/pwm-osc/pwm-sin.cir @@ -0,0 +1,45 @@ +*** XSPICE_PWM for audio demo ***************************** +* sin in --> pwm --> filter --> sin out to load + +* PWM with input frequency 1200k, variable duty cycle +apwm in dout pwm +.model pwm d_pwm( ++ frequency = 1.2Meg ++ cntl_array = [-1 -0.99 0.99 1] ++ dc_array = [0.01 0.01 0.99 0.99] ++ init_phase = 90) + +* D to A including inverted output +aout [~dout dout] [outn outp] dac1 + +.model dac1 dac_bridge(out_low = 0 out_high = 1 out_undef = 0 ++ input_load = 5.0e-12 t_rise = 2e-9 ++ t_fall = 2e-9) + +* LC filter ********************* +L1 outn outflcn 33u +CLfiltern outflcn 0 0.1u + +Cboth outflcn outflcp 0.47u + +L2 outp outflcp 33u +CLfilterp outflcp 0 0.1u +********************************* + +* load +RLooad outflcp outflcn 8 + +* input voltage +Vin in 0 dc 0 sin (0 0.95 1.01k) +* reference for comparison (input shifted by 3.05 degrees for compensating latency) +Vref ref 0 dc 0 sin (0 0.95 1.01k 0 0 -3.05) + +.control +tran 0.5u 20m uic +rusage +plot v(outn) v(outp) v(in)+2 xlimit 11.65m 12.15m ylabel 'digital output versus vin' +plot 0.99 * v(ref) - v(outflcp) + v(outflcn) ylimit -2m 2m ylabel 'Difference between input and output' +plot 0.99 * v(ref) v(outflcp)-v(outflcn) ylabel 'Input and output' +.endc + +.end diff --git a/examples/xspice/analog_models1_transient.sp b/examples/xspice/various/analog_models1_transient.sp similarity index 100% rename from examples/xspice/analog_models1_transient.sp rename to examples/xspice/various/analog_models1_transient.sp diff --git a/examples/xspice/fstest.sp b/examples/xspice/various/filesource-test.sp similarity index 100% rename from examples/xspice/fstest.sp rename to examples/xspice/various/filesource-test.sp diff --git a/examples/xspice/pwlts1.cir b/examples/xspice/various/pwlts1.cir similarity index 100% rename from examples/xspice/pwlts1.cir rename to examples/xspice/various/pwlts1.cir diff --git a/examples/xspice/simple-diode.cir b/examples/xspice/various/simple-diode.cir similarity index 100% rename from examples/xspice/simple-diode.cir rename to examples/xspice/various/simple-diode.cir diff --git a/examples/xspice/sine.m b/examples/xspice/various/sine.m similarity index 100% rename from examples/xspice/sine.m rename to examples/xspice/various/sine.m diff --git a/examples/xspice/vswitch-test-lin.cir b/examples/xspice/various/vswitch-test-lin.cir similarity index 100% rename from examples/xspice/vswitch-test-lin.cir rename to examples/xspice/various/vswitch-test-lin.cir diff --git a/examples/xspice/vswitch-test-log.cir b/examples/xspice/various/vswitch-test-log.cir similarity index 100% rename from examples/xspice/vswitch-test-log.cir rename to examples/xspice/various/vswitch-test-log.cir diff --git a/examples/xspice/xspice_c1.cir b/examples/xspice/various/xspice_c1.cir similarity index 100% rename from examples/xspice/xspice_c1.cir rename to examples/xspice/various/xspice_c1.cir diff --git a/examples/xspice/xspice_c2.cir b/examples/xspice/various/xspice_c2.cir similarity index 100% rename from examples/xspice/xspice_c2.cir rename to examples/xspice/various/xspice_c2.cir diff --git a/examples/xspice/xspice_c3.cir b/examples/xspice/various/xspice_c3.cir similarity index 100% rename from examples/xspice/xspice_c3.cir rename to examples/xspice/various/xspice_c3.cir diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index 3ce568223..f4732ef74 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -773,7 +773,31 @@ operate(char op, double x, double y) x = x / y; break; case '^': /* power */ - x = pow(fabs(x), y); + if (newcompat.hs) { + if (x < 0) + x = pow(x, round(y)); + else if (x == 0) + x = 0; + else + x = pow(x, y); + } + else if (newcompat.lt) { + if (x >= 0) + x = pow(x, y); + else { + /* If arg2 is quasi an integer, round it to have pow not fail + when arg1 is negative. Takes into account the double + representation which sometimes differs in the last digit(s). */ + if (AlmostEqualUlps(nearbyint(y), y, 10)) + x = pow(x, round(y)); + else + /* As per LTSPICE specification for ** */ + x = 0; + } + } + else { + x = pow(fabs(x), y); + } break; case 'A': /* && */ x = ((x != 0.0) && (y != 0.0)) ? 1.0 : 0.0; diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index ea9cb3cac..4d725077b 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -123,7 +123,7 @@ static struct op { PT_MINUS, "-", (void(*)(void)) PTminus}, { PT_TIMES, "*", (void(*)(void)) PTtimes}, { PT_DIVIDE, "/", (void(*)(void)) PTdivide}, { - PT_POWER, "^", (void(*)(void)) PTpower} + PT_POWER, "^", (void(*)(void)) PTpowerH} }; #define NUM_OPS (int)NUMELEMS(ops) @@ -158,7 +158,6 @@ static struct func { { "floor", PTF_FLOOR, (void(*)(void)) PTfloor } , { "nint", PTF_NINT, (void(*)(void)) PTnint } , { "-", PTF_UMINUS, (void(*)(void)) PTuminus }, - /* MW. cif function added */ { "u2", PTF_USTEP2, (void(*)(void)) PTustep2}, { "pwl", PTF_PWL, (void(*)(void)) PTpwl}, { "pwl_derivative", PTF_PWL_DERIVATIVE, (void(*)(void)) PTpwl_derivative}, @@ -331,7 +330,7 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) #define b p->right if (b->type == PT_CONSTANT) { arg1 = PTdifferentiate(a, varnum); - if (newcompat.lt) { + if (newcompat.hs || newcompat.lt) { newp = mkb(PT_TIMES, mkb(PT_TIMES, mkcon(b->constant), @@ -545,8 +544,6 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) arg1 = mkcon(0.0); break; - - /* MW. PTF_CIF for new cif function */ case PTF_USTEP2: /* ustep2=uramp(x)-uramp(x-1) ustep2'=ustep(x)-ustep(x-1) */ arg1 = mkb(PT_MINUS, mkf(PTF_USTEP, p->left), diff --git a/src/spicelib/parser/inpxx.h b/src/spicelib/parser/inpxx.h index afbb9d162..77e4a2143 100644 --- a/src/spicelib/parser/inpxx.h +++ b/src/spicelib/parser/inpxx.h @@ -43,6 +43,7 @@ double PTminus(double arg1, double arg2); double PTtimes(double arg1, double arg2); double PTdivide(double arg1, double arg2); double PTpower(double arg1, double arg2); +double PTpowerH(double arg1, double arg2); double PTpwr(double arg1, double arg2); double PTacos(double arg); double PTacosh(double arg); diff --git a/src/spicelib/parser/ptfuncs.c b/src/spicelib/parser/ptfuncs.c index 6abfff6d2..a4ed04a3c 100644 --- a/src/spicelib/parser/ptfuncs.c +++ b/src/spicelib/parser/ptfuncs.c @@ -77,8 +77,8 @@ PTpower(double arg1, double arg2) else { /* If arg2 is quasi an integer, round it to have pow not fail when arg1 is negative. Takes into account the double - representation which sometimes differs in the last digit. */ - if (AlmostEqualUlps(trunc(arg2), arg2, 3)) + representation which sometimes differs in the last digit(s). */ + if (AlmostEqualUlps(nearbyint(arg2), arg2, 10)) res = pow(arg1, round(arg2)); else /* As per LTSPICE specification for ** */ @@ -90,6 +90,42 @@ PTpower(double arg1, double arg2) return res; } +double +PTpowerH(double arg1, double arg2) +{ + double res; + + if (newcompat.hs) { + if (arg1 < 0) + res = pow(arg1, round(arg2)); + else if (arg1 == 0){ + res = 0; + } + else + { + res = pow(arg1, arg2); + } + } + else if (newcompat.lt) { + if (arg1 >= 0) + res = pow(arg1, arg2); + else { + /* If arg2 is quasi an integer, round it to have pow not fail + when arg1 is negative. Takes into account the double + representation which sometimes differs in the last digit(s). */ + if (AlmostEqualUlps(nearbyint(arg2), arg2, 10)) + res = pow(arg1, round(arg2)); + else + /* As per LTSPICE specification for ** */ + res = 0; + } + } + else + res = pow(fabs(arg1), arg2); + return res; +} + + double PTpwr(double arg1, double arg2) { diff --git a/src/xspice/icm/digital/d_osc/cfunc.mod b/src/xspice/icm/digital/d_osc/cfunc.mod index c893b888a..b76386132 100644 --- a/src/xspice/icm/digital/d_osc/cfunc.mod +++ b/src/xspice/icm/digital/d_osc/cfunc.mod @@ -8,18 +8,18 @@ Public Domain Georgia Tech Research Corporation Atlanta, Georgia 30332 PROJECT A-8503-405 - -AUTHORS + +AUTHORS 24 Jul 1991 Jeffrey P. Murray -MODIFICATIONS +MODIFICATIONS 23 Aug 1991 Jeffrey P. Murray 30 Sep 1991 Jeffrey P. Murray - + 09 Nov 2022 Holger Vogt SUMMARY @@ -27,12 +27,12 @@ SUMMARY functionally describe the d_osc code model. -INTERFACES +INTERFACES - FILE ROUTINE CALLED + FILE ROUTINE CALLED + + CMmacros.h cm_message_send(); - CMmacros.h cm_message_send(); - CM.c void *cm_analog_alloc() void *cm_analog_get_ptr() @@ -42,7 +42,7 @@ INTERFACES REFERENCED FILES Inputs from and outputs to ARGS structure. - + NON-STANDARD FEATURES @@ -55,7 +55,7 @@ NON-STANDARD FEATURES #include "d_osc.h" /* ...contains macros & type defns. for this model. 7/24/91 - JPM */ - + /*=== CONSTANTS ========================*/ @@ -66,27 +66,31 @@ NON-STANDARD FEATURES - -/*=== LOCAL VARIABLES & TYPEDEFS =======*/ + +/*=== LOCAL VARIABLES & TYPEDEFS =======*/ + + +typedef struct { + double *x; + double *y; +} Local_Data_t; - - /*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ - + /*============================================================================== FUNCTION cm_d_osc() -AUTHORS +AUTHORS 24 Jul 1991 Jeffrey P. Murray -MODIFICATIONS +MODIFICATIONS 30 Sep 1991 Jeffrey P. Murray @@ -94,23 +98,23 @@ SUMMARY This function implements the d_osc code model. -INTERFACES +INTERFACES - FILE ROUTINE CALLED + FILE ROUTINE CALLED + + CMmacros.h cm_message_send(); - CMmacros.h cm_message_send(); - CM.c void *cm_analog_alloc() void *cm_analog_get_ptr() CMevt.c void cm_event_queue() RETURNED VALUE - + Returns inputs and outputs via ARGS structure. GLOBAL VARIABLES - + NONE NON-STANDARD FEATURES @@ -119,6 +123,26 @@ NON-STANDARD FEATURES ==============================================================================*/ +static void cm_d_osc_callback(ARGS, + Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: { + Local_Data_t *loc = STATIC_VAR(locdata); + if (loc) { + if (loc->x) + free(loc->x); + if(loc->y) + free(loc->y); + free(loc); + STATIC_VAR(locdata) = loc = NULL; + } + break; + } /* end of case MIF_CB_DESTROY */ + } /* end of switch over reason being called */ +} /* end of function cm_d_osc_callback */ + + /*=== CM_D_OSC ROUTINE ===*/ /************************************************************* @@ -141,7 +165,7 @@ NON-STANDARD FEATURES * I | | | | * * I | | * * I | | | | * -* I-----------------*-----* - - - - - - - - - -*--------- * +* I-----------------*-----* - - - - - - - - - -*--------- * * t1 t4 * * * * * @@ -158,7 +182,7 @@ NON-STANDARD FEATURES #include -void cm_d_osc(ARGS) +void cm_d_osc(ARGS) { double *x, /* analog input value control array */ @@ -166,11 +190,11 @@ void cm_d_osc(ARGS) cntl_input, /* control input value */ *phase, /* instantaneous phase of the model */ *phase_old, /* previous phase of the model */ - *t1, /* pointer to t1 value */ - *t3, /* pointer to t3 value */ - /*time1,*/ /* variable for calculating new time1 value */ - /*time3,*/ /* variable for calculating new time3 value */ - freq = 0.0, /* instantaneous frequency value */ + *t1, /* pointer to t1 value */ + *t3, /* pointer to t3 value */ + /*time1,*/ /* variable for calculating new time1 value */ + /*time3,*/ /* variable for calculating new time3 value */ + freq = 0.0, /* instantaneous frequency value */ dphase, /* fractional part into cycle */ duty_cycle, /* duty_cycle value */ test_double, /* testing variable */ @@ -181,16 +205,17 @@ void cm_d_osc(ARGS) int i, /* generic loop counter index */ cntl_size, /* control array size */ freq_size; /* frequency array size */ - - + + Local_Data_t *loc; /* Pointer to local static data, not to be included + in the state vector (save memory!) */ /**** Retrieve frequently used parameters... ****/ - cntl_size = PARAM_SIZE(cntl_array); - freq_size = PARAM_SIZE(freq_array); + cntl_size = PARAM_SIZE(cntl_array); + freq_size = PARAM_SIZE(freq_array); duty_cycle = PARAM(duty_cycle); @@ -202,9 +227,8 @@ void cm_d_osc(ARGS) return; } - - if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/ + if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/ /* Allocate storage for internal variables */ cm_analog_alloc(0, sizeof(double)); @@ -215,42 +239,57 @@ void cm_d_osc(ARGS) phase = phase_old = (double *) cm_analog_get_ptr(0,0); t1 = (double *) cm_analog_get_ptr(1,0); - + t3 = (double *) cm_analog_get_ptr(2,0); + /*** allocate static storage for *loc ***/ + STATIC_VAR (locdata) = calloc (1 , sizeof ( Local_Data_t )); + loc = STATIC_VAR (locdata); + CALLBACK = cm_d_osc_callback; + + x = loc->x = (double *) calloc((size_t) cntl_size, sizeof(double)); + if (!x) { + cm_message_send(d_osc_allocation_error); + return; + } + y = loc->y = (double *) calloc((size_t) cntl_size, sizeof(double)); + if (!y) { + cm_message_send(d_osc_allocation_error); + if(x) + free(x); + return; + } + /* Retrieve x and y values. */ + for (i=0; i *phase ) { *phase = *phase + 360.0; - } + } *phase = *phase / 360.0; /* set phase value to init_phase */ *phase_old = *phase; - + /* preset time values to harmless values... */ *t1 = -1; *t3 = -1; - } + loc = STATIC_VAR (locdata); + x = loc->x; + y = loc->y; - /* Allocate storage for breakpoint domain & freq. range values */ - - x = (double *) calloc((size_t) cntl_size, sizeof(double)); - if (!x) { - cm_message_send(d_osc_allocation_error); - return; - } - - y = (double *) calloc((size_t) freq_size, sizeof(double)); - if (!y) { - cm_message_send(d_osc_allocation_error); - if(x) free(x); - return; - } - - /* Retrieve x and y values. */ - for (i=0; i= x[cntl_size-1]) { + + if (cntl_input >= x[cntl_size-1]) { slope = (y[cntl_size-1] - y[cntl_size-2]) / (x[cntl_size-1] - x[cntl_size-2]); freq = y[cntl_size-1] + (cntl_input - x[cntl_size-1]) * slope; - - } - else { /*** cntl_input within bounds of end midpoints... - must determine position progressively & then + + } + else { /*** cntl_input within bounds of end midpoints... + must determine position progressively & then calculate required output. ***/ - + for (i=0; i= x[i]) ) { - + + if ( (cntl_input < x[i+1]) && (cntl_input >= x[i]) ) { + /* Interpolate to the correct frequency value */ - - freq = ( (cntl_input - x[i]) / (x[i+1] - x[i]) ) * - ( y[i+1]-y[i] ) + y[i]; - } + + freq = ( (cntl_input - x[i]) / (x[i+1] - x[i]) ) * + ( y[i+1]-y[i] ) + y[i]; + } } } - + /*** If freq < 0.0, clamp to 1e-16 & issue a warning ***/ if ( 0.0 > freq ) { freq = 1.0e-16; - cm_message_send(d_osc_negative_freq_error); + cm_message_send(d_osc_negative_freq_error); } /* calculate the instantaneous phase */ *phase = *phase_old + freq * (TIME - T(1)); - + /* dphase is the percent into the cycle for - the period */ + the period */ dphase = *phase_old - floor(*phase_old); /* Calculate the time variables and the output value - for this iteration */ - + for this iteration */ + if((*t1 <= TIME) && (TIME <= *t3)) { /* output high */ *t3 = T(1) + (1 - dphase)/freq; - + if(TIME < *t3) { cm_event_queue(*t3); } - - - } - else + } + else if((*t3 <= TIME) && (TIME <= *t1)) { /* output low */ @@ -369,13 +387,12 @@ void cm_d_osc(ARGS) dphase = dphase - 1.0; } *t1 = T(1) + ( (1.0 - duty_cycle) - dphase)/freq; - + if(TIME < *t1) { cm_event_queue(*t1); - } - } + } else { if(dphase > (1.0 - duty_cycle) ) { @@ -388,66 +405,51 @@ void cm_d_osc(ARGS) } *t3 = T(1) + (1 - dphase)/freq; - - } - - - - if(x) free(x); - if(y) free(y); - - } break; - + case EVENT: /** discrete call...lots to do **/ + test_double = TIME; - test_double = TIME; - - if ( 0.0 == TIME ) { /* DC analysis...preset values, + if ( 0.0 == TIME ) { /* DC analysis...preset values, as appropriate.... */ /* retrieve & normalize phase value */ *phase = PARAM(init_phase); if ( 0 > *phase ) { *phase = *phase + 360.0; - } + } *phase = *phase / 360.0; /* set phase value to init_phase */ *phase_old = *phase; - + /* preset time values to harmless values... */ *t1 = -1; *t3 = -1; } - - /* Calculate the time variables and the output value - for this iteration */ - + for this iteration */ + /* Output is always set to STRONG */ - OUTPUT_STRENGTH(out) = STRONG; - - + OUTPUT_STRENGTH(out) = STRONG; if( *t1 == TIME ) { /* rising edge */ - OUTPUT_STATE(out) = ONE; - OUTPUT_DELAY(out) = PARAM(rise_delay); - + OUTPUT_STATE(out) = ONE; + OUTPUT_DELAY(out) = PARAM(rise_delay); } else { if ( *t3 == TIME ) { /* falling edge */ - OUTPUT_STATE(out) = ZERO; - OUTPUT_DELAY(out) = PARAM(fall_delay); + OUTPUT_STATE(out) = ZERO; + OUTPUT_DELAY(out) = PARAM(fall_delay); } else { /* no change in output */ @@ -457,18 +459,17 @@ void cm_d_osc(ARGS) } if ( (*t1 < TIME) && (TIME < *t3) ) { - OUTPUT_STATE(out) = ONE; + OUTPUT_STATE(out) = ONE; } else { - OUTPUT_STATE(out) = ZERO; + OUTPUT_STATE(out) = ZERO; } } } break; - } -} +} diff --git a/src/xspice/icm/digital/d_osc/ifspec.ifs b/src/xspice/icm/digital/d_osc/ifspec.ifs index 8d9e56164..d28b93014 100644 --- a/src/xspice/icm/digital/d_osc/ifspec.ifs +++ b/src/xspice/icm/digital/d_osc/ifspec.ifs @@ -6,14 +6,14 @@ Georgia Tech Research Corporation Atlanta, Georgia 30332 -AUTHORS +AUTHORS 30 Sept 1991 Jeffrey P. Murray - + 09 Nov 2022 Holger Vogt SUMMARY - This file contains the interface specification file for the + This file contains the interface specification file for the hybrid d_osc code model. ===============================================================================*/ @@ -40,14 +40,14 @@ Null_Allowed: no no PARAMETER_TABLE: -Parameter_Name: cntl_array freq_array +Parameter_Name: cntl_array freq_array Description: "control array" "frequency array" Data_Type: real real -Default_Value: 0.0 1.0e6 -Limits: - [0 -] +Default_Value: 0.0 1.0e6 +Limits: - [0 -] Vector: yes yes -Vector_Bounds: [2 -] [2 -] -Null_Allowed: no no +Vector_Bounds: [2 -] [2 -] +Null_Allowed: no no PARAMETER_TABLE: @@ -59,7 +59,7 @@ Default_Value: 0.5 0 Limits: [1e-6 0.999999] [-180.0 +360.0] Vector: no no Vector_Bounds: - - -Null_Allowed: yes yes +Null_Allowed: yes yes PARAMETER_TABLE: @@ -71,5 +71,11 @@ Default_Value: 1e-9 1e-9 Limits: [0 -] [0 -] Vector: no no Vector_Bounds: - - -Null_Allowed: yes yes +Null_Allowed: yes yes + +STATIC_VAR_TABLE: + +Static_Var_Name: locdata +Description: "local static data" +Data_Type: pointer