From 31a0f3eaf6f59b5d491b1285955ef29d615ba10c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 4 Mar 2022 11:43:18 +0100 Subject: [PATCH] d_pwm: Add a hybrid oscillator (analg control in, digital out) with PWM (pulse width modulation) capability, oscillation frequency is a parameter. The model has been derived from the d_osc example. --- src/xspice/icm/digital/d_pwm/cfunc.mod | 485 ++++++++++++++++++++++++ src/xspice/icm/digital/d_pwm/d_pwm.h | 93 +++++ src/xspice/icm/digital/d_pwm/ifspec.ifs | 77 ++++ src/xspice/icm/digital/modpath.lst | 1 + visualc/xspice/digital.vcxproj | 6 + 5 files changed, 662 insertions(+) create mode 100644 src/xspice/icm/digital/d_pwm/cfunc.mod create mode 100644 src/xspice/icm/digital/d_pwm/d_pwm.h create mode 100644 src/xspice/icm/digital/d_pwm/ifspec.ifs diff --git a/src/xspice/icm/digital/d_pwm/cfunc.mod b/src/xspice/icm/digital/d_pwm/cfunc.mod new file mode 100644 index 000000000..af6e323c8 --- /dev/null +++ b/src/xspice/icm/digital/d_pwm/cfunc.mod @@ -0,0 +1,485 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ + +FILE d_pwm/cfunc.mod + +Public Domain + +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +PROJECT A-8503-405 +The ngspice team + +AUTHORS + + 24 Jul 1991 Jeffrey P. Murray + 02 Mar 2022 Holger Vogt + +MODIFICATIONS + + 23 Aug 1991 Jeffrey P. Murray + 30 Sep 1991 Jeffrey P. Murray + + +SUMMARY + + This file contains the model-specific routines used to + functionally describe the d_pwm code model. + + +INTERFACES + + FILE ROUTINE CALLED + + CMmacros.h cm_message_send(); + + CM.c void *cm_analog_alloc() + void *cm_analog_get_ptr() + + CMevt.c void cm_event_queue() + + +REFERENCED FILES + + Inputs from and outputs to ARGS structure. + + +NON-STANDARD FEATURES + + NONE + +===============================================================================*/ + +/*=== INCLUDE FILES ====================*/ + +#include "d_pwm.h" /* ...contains macros & type defns. + for this model. 7/24/91 - JPM */ + + + +/*=== CONSTANTS ========================*/ + + + + +/*=== MACROS ===========================*/ + + + + +/*=== LOCAL VARIABLES & TYPEDEFS =======*/ + + + + +/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ + + + + + +/*============================================================================== + +FUNCTION cm_d_pwm() + +AUTHORS + + 24 Jul 1991 Jeffrey P. Murray + 02 Mar 2022 Holger Vogt + +MODIFICATIONS + + 30 Sep 1991 Jeffrey P. Murray + +SUMMARY + + This function implements the d_pwm code model. + +INTERFACES + + FILE ROUTINE CALLED + + 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 + + NONE + +==============================================================================*/ + +/*=== CM_D_PWM ROUTINE ===*/ + +/************************************************************* +* The following is the model for a duty cycle controlled * +* digital oscillator, derived from the controlled digital * +* oscillator d_osc. * +* * +* Created 3/02/2022 H. Vogt * +*************************************************************/ + +/************************************************************* +* * +* * +* <-----duty_cycle-----> * +* I * +* I t2 t3 * +* I \______________/_____ * +* I | | * +* I | | | | * +* I | | * +* I | | | | * +* I | | * +* I | | | | * +* I-----------------*-----* - - - - - - - - - -*--------- * +* t1 t4 * +* * +* * +* t2 = t1 + rise_delay * +* t4 = t3 + fall_delay * +* * +* Note that for the digital model, unlike for the * +* analog "square" model, t1 and t3 are stored and * +* adjusted values, but t2 & t4 are implied by the * +* rise and fall delays of the model, but are otherwise * +* not stored values. JPM * +* * +*************************************************************/ + +#include + +void cm_d_pwm(ARGS) +{ + + double *x, /* analog input value control array */ + *y, /* frequency array */ + 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 */ + dc = 0.5, /* instantaneous duty cycle value */ + dphase, /* fractional part into cycle */ + frequency, /* frequency value */ + test_double, /* testing variable */ + slope; /* slope value...used to extrapolate + freq values past endpoints. */ + + + int i, /* generic loop counter index */ + cntl_size, /* control array size */ + dc_size; /* duty cycle array size */ + + + + + + + /**** Retrieve frequently used parameters... ****/ + + cntl_size = PARAM_SIZE(cntl_array); + dc_size = PARAM_SIZE(dc_array); + frequency = PARAM(frequency); + + + /* check and make sure that the control array is the + same size as the frequency array */ + + if(cntl_size != dc_size){ + cm_message_send(d_pwm_array_error); + return; + } + + + if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/ + + + /* Allocate storage for internal variables */ + cm_analog_alloc(0, sizeof(double)); + cm_analog_alloc(1, sizeof(double)); + cm_analog_alloc(2, sizeof(double)); + + /* assign internal variables */ + 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); + + } + + else { /*** This is not an initialization pass...retrieve storage + addresses and calculate new outputs, if required. ***/ + + + /** Retrieve previous values... **/ + + + /* assign internal variables */ + phase = (double *) cm_analog_get_ptr(0,0); + phase_old = (double *) cm_analog_get_ptr(0,1); + + t1 = (double *) cm_analog_get_ptr(1,0); + + t3 = (double *) cm_analog_get_ptr(2,0); + + } + + + + + switch (CALL_TYPE) { + + case ANALOG: /** analog call **/ + + test_double = TIME; + + if ( AC == ANALYSIS ) { /* this model does not function + in AC analysis mode. */ + + return; + + } + else { + + if ( 0.0 == TIME ) { /* DC analysis */ + + /* 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; + + + } + + + /* Allocate storage for breakpoint domain & duty cycle range values */ + + x = (double *) calloc((size_t) cntl_size, sizeof(double)); + if (!x) { + cm_message_send(d_pwm_allocation_error); + return; + } + + y = (double *) calloc((size_t) dc_size, sizeof(double)); + if (!y) { + cm_message_send(d_pwm_allocation_error); + if(x) free(x); + return; + } + + /* Retrieve x and y values. */ + for (i=0; i= x[cntl_size-1]) { + + slope = (y[cntl_size-1] - y[cntl_size-2]) / + (x[cntl_size-1] - x[cntl_size-2]); + dc = y[cntl_size-1] + (cntl_input - x[cntl_size-1]) * slope; + + } + else { /*** cntl_input within bounds of end midpoints... + must determine position progressively & then + calculate required output. ***/ + + for (i=0; i= x[i]) ) { + + /* Interpolate to the correct duty cycle value */ + + dc = ( (cntl_input - x[i]) / (x[i+1] - x[i]) ) * + ( y[i+1]-y[i] ) + y[i]; + } + } + } + + /*** If dc < 0.0, clamp to 0 & issue a warning ***/ + if ( 0.0 > dc ) { + dc = 0; +// cm_message_send(d_pwm_negative_dc_error); + } + /*** If dc > 1.0, clamp to 1 & issue a warning ***/ + if ( 1.0 < dc ) { + dc = 1; +// cm_message_send(d_pwm_positive_dc_error); + } + + + /* calculate the instantaneous phase */ + *phase = *phase_old + frequency * (TIME - T(1)); + + /* dphase is the percent into the cycle for + the period */ + dphase = *phase_old - floor(*phase_old); + + + /* Calculate the time variables and the output value + for this iteration */ + + if((*t1 <= TIME) && (TIME <= *t3)) { /* output high */ + + *t3 = T(1) + (1 - dphase)/frequency; + + if(TIME < *t3) { + cm_event_queue(*t3); + } + + + } + else + + if((*t3 <= TIME) && (TIME <= *t1)) { /* output low */ + + if(dphase > (1.0 - dc) ) { + dphase = dphase - 1.0; + } + *t1 = T(1) + ( (1.0 - dc) - dphase)/frequency; + + if(TIME < *t1) { + + cm_event_queue(*t1); + + } + } + else { + + if(dphase > (1.0 - dc) ) { + dphase = dphase - 1.0; + } + *t1 = T(1) + ( (1.0 - dc) - dphase )/frequency; + + if((TIME < *t1) || (T(1) == 0)) { + cm_event_queue(*t1); + } + + *t3 = T(1) + (1 - dphase)/frequency; + + + } + + + + if(x) free(x); + if(y) free(y); + + + } + break; + + + case EVENT: /** discrete call...lots to do **/ + + + test_double = TIME; + + 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 */ + + /* Output is always set to STRONG */ + OUTPUT_STRENGTH(out) = STRONG; + + + + if( *t1 == TIME ) { /* rising edge */ + + 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); + } + + else { /* no change in output */ + + if ( TIME != 0.0 ) { + OUTPUT_CHANGED(out) = FALSE; + } + + if ( (*t1 < TIME) && (TIME < *t3) ) { + OUTPUT_STATE(out) = ONE; + } + else { + OUTPUT_STATE(out) = ZERO; + } + } + } + + break; + + } +} + + + + + + + diff --git a/src/xspice/icm/digital/d_pwm/d_pwm.h b/src/xspice/icm/digital/d_pwm/d_pwm.h new file mode 100644 index 000000000..8dc88c20d --- /dev/null +++ b/src/xspice/icm/digital/d_pwm/d_pwm.h @@ -0,0 +1,93 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ + +FILE d_pwm/d_pwm.h + +Public Domain + +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +PROJECT A-8503-405 +The ngspice team + +AUTHORS + + 25 Jul 1991 Jeffrey P. Murray + 02 Mar 2022 Holger Vogt + + +MODIFICATIONS + + 30 Sept 1991 Jeffrey P. Murray + + +SUMMARY + + This file contains the header information for the d_pwm + code model. + + +INTERFACES + + FILE ROUTINE CALLED + + N/A N/A + + + +REFERENCED FILES + + N/A + + +NON-STANDARD FEATURES + + NONE + +===============================================================================*/ +/* + Structures, etc. for d_pwm oscillator model. + 7/25/90 + Last Modified 7/25/91 J.P.Murray + 3/02/22 H. Vogt */ + +/*=======================================================================*/ + +/*=== INCLUDE FILES =====================================================*/ + +#include +#include +#include +#include + + + + +/*=== CONSTANTS =========================================================*/ + + +/**** Error Messages ****/ +char *d_pwm_allocation_error = "\n**** Error ****\nD_PWM: Error allocating VCO block storage \n"; +char *d_pwm_array_error = "\n**** Error ****\nD_PWM: Size of control array different than duty cycle array \n"; +char *d_pwm_negative_dc_error = "\n**** Error ****\nD_PWM: The extrapolated value for duty cycle\nhas been found to be negative... \n Lower duty cycle level has been clamped to 0.0 \n"; +char *d_pwm_positive_dc_error = "\n**** Error ****\nD_PWM: The extrapolated value for duty cycle\nhas been found to be > 1... \n Upper duty cycle level has been clamped to 1.0 \n"; + + + + + + +/*=== MACROS ============================================================*/ + + + +/*=== LOCAL VARIABLES & TYPEDEFS ========================================*/ + + + +/*=== FUNCTION PROTOTYPE DEFINITIONS ====================================*/ + + +/*=======================================================================*/ + + diff --git a/src/xspice/icm/digital/d_pwm/ifspec.ifs b/src/xspice/icm/digital/d_pwm/ifspec.ifs new file mode 100644 index 000000000..da6ed4da3 --- /dev/null +++ b/src/xspice/icm/digital/d_pwm/ifspec.ifs @@ -0,0 +1,77 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ +Public Domain + +Georgia Tech Research Corporation +Atlanta, Georgia 30332 +The ngspice team + + +AUTHORS + + 30 Sept 1991 Jeffrey P. Murray + 02 Mar 2022 Holger Vogt + + +SUMMARY + + This file contains the interface specification file for the + hybrid d_pwm code model. + +===============================================================================*/ + +NAME_TABLE: + +Spice_Model_Name: d_pwm +C_Function_Name: cm_d_pwm +Description: "duty cycle controlled digital oscillator" + + +PORT_TABLE: + +Port_Name: cntl_in out +Description: "control input" "output" +Direction: in out +Default_Type: v d +Allowed_Types: [v,vd,i,id] [d] +Vector: no no +Vector_Bounds: - - +Null_Allowed: no no + + + +PARAMETER_TABLE: + +Parameter_Name: cntl_array dc_array +Description: "control array" "duty cycle array" +Data_Type: real real +Default_Value: 0.0 0.5 +Limits: - [0 1] +Vector: yes yes +Vector_Bounds: [2 -] [2 -] +Null_Allowed: no no + + +PARAMETER_TABLE: + +Parameter_Name: frequency init_phase +Description: "oscillator frequency" "initial phase of output" +Data_Type: real real +Default_Value: 1e6 0 +Limits: [1e-6 -] [-180.0 +360.0] +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: rise_delay fall_delay +Description: "rise delay" "fall delay" +Data_Type: real real +Default_Value: 1e-9 1e-9 +Limits: [0 -] [0 -] +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + diff --git a/src/xspice/icm/digital/modpath.lst b/src/xspice/icm/digital/modpath.lst index 38d193a83..ab1fa4b6c 100644 --- a/src/xspice/icm/digital/modpath.lst +++ b/src/xspice/icm/digital/modpath.lst @@ -17,6 +17,7 @@ d_or d_osc d_pulldown d_pullup +d_pwm d_ram d_source d_srff diff --git a/visualc/xspice/digital.vcxproj b/visualc/xspice/digital.vcxproj index b97b08a73..1a05a89e8 100644 --- a/visualc/xspice/digital.vcxproj +++ b/visualc/xspice/digital.vcxproj @@ -276,6 +276,10 @@ ..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories) + + ..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories) + + ..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories) @@ -353,6 +357,8 @@ + +