Merge branch 'pre-master' into bt_dev

This commit is contained in:
Brian Taylor 2022-11-12 22:24:31 -08:00
commit 9d13e5dc43
18 changed files with 309 additions and 153 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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),

View File

@ -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);

View File

@ -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)
{

View File

@ -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 <stdlib.h>
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<cntl_size; i++) {
x[i] = PARAM(cntl_array[i]);
y[i] = PARAM(freq_array[i]);
}
}
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
test_double = TIME;
if ( AC == ANALYSIS ) { /* this model does not function
in AC analysis mode. */
return;
return;
}
else {
@ -260,45 +299,26 @@ void cm_d_osc(ARGS)
*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;
}
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<cntl_size; i++) {
x[i] = PARAM(cntl_array[i]);
y[i] = PARAM(freq_array[i]);
}
/* Retrieve cntl_input value. */
/* 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]) {
@ -307,61 +327,59 @@ void cm_d_osc(ARGS)
freq = y[0] + (cntl_input - x[0]) * slope;
}
else
else
/*** cntl_input above highest cntl_voltage ***/
if (cntl_input >= 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<cntl_size-1; i++) {
if ( (cntl_input < x[i+1]) && (cntl_input >= 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;
}
}
}

View File

@ -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