Browse Source
d_pwm: Add a hybrid oscillator (analg control in, digital out) with PWM
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.pre-master-46
5 changed files with 662 additions and 0 deletions
-
485src/xspice/icm/digital/d_pwm/cfunc.mod
-
93src/xspice/icm/digital/d_pwm/d_pwm.h
-
77src/xspice/icm/digital/d_pwm/ifspec.ifs
-
1src/xspice/icm/digital/modpath.lst
-
6visualc/xspice/digital.vcxproj
@ -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 <stdlib.h> |
|||
|
|||
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<cntl_size; i++) { |
|||
x[i] = PARAM(cntl_array[i]); |
|||
y[i] = PARAM(dc_array[i]); |
|||
} |
|||
|
|||
/* Retrieve cntl_input value. */ |
|||
cntl_input = INPUT(cntl_in); |
|||
|
|||
/* Determine segment boundaries within which cntl_input resides */ |
|||
/*** cntl_input below lowest cntl_voltage ***/ |
|||
if (cntl_input <= x[0]) { |
|||
|
|||
slope = (y[1] - y[0])/(x[1] - x[0]); |
|||
dc = y[0] + (cntl_input - x[0]) * slope; |
|||
|
|||
} |
|||
else |
|||
/*** cntl_input above highest cntl_voltage ***/ |
|||
|
|||
if (cntl_input >= 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<cntl_size-1; i++) { |
|||
|
|||
if ( (cntl_input < x[i+1]) && (cntl_input >= 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; |
|||
|
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
@ -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 <stdio.h> |
|||
#include <ctype.h> |
|||
#include <math.h> |
|||
#include <string.h> |
|||
|
|||
|
|||
|
|||
|
|||
/*=== 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 ====================================*/ |
|||
|
|||
|
|||
/*=======================================================================*/ |
|||
|
|||
|
|||
@ -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 |
|||
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue