From f45103b3ab5b7e1299ba2a09c2594ed36c43519c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 11 Aug 2025 18:45:21 +0200 Subject: [PATCH] Update to filesource Move tprev out of the loop to enable storing the previous time value. Add some general warning message that an error might have occurred during reading the time or data values from the data input file. Allow empty lines in the data input file. Guard early data values (TIME < time offset) against false reading. Add some simple examples. --- .../xspice/filesource/filesource_variants.cir | 49 +++++++++++++++++++ examples/xspice/filesource/rect_abs.m | 11 +++++ examples/xspice/filesource/rect_abs_dual.m | 11 +++++ examples/xspice/filesource/rect_rel.m | 11 +++++ src/xspice/icm/analog/file_source/cfunc.mod | 37 +++++++++++--- 5 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 examples/xspice/filesource/filesource_variants.cir create mode 100644 examples/xspice/filesource/rect_abs.m create mode 100644 examples/xspice/filesource/rect_abs_dual.m create mode 100644 examples/xspice/filesource/rect_rel.m diff --git a/examples/xspice/filesource/filesource_variants.cir b/examples/xspice/filesource/filesource_variants.cir new file mode 100644 index 000000000..3a57da8d5 --- /dev/null +++ b/examples/xspice/filesource/filesource_variants.cir @@ -0,0 +1,49 @@ +simple filesource, time relative or absolute + +a1 %vd([out1 0]) filesrc + +.model filesrc filesource (file="rect_rel.m" amploffset=[0.1] amplscale=[1] ++ timeoffset=0 timescale=1 ++ timerelative=true amplstep=false) + +a2 %vd([out2 0]) filesrc2 + +.model filesrc2 filesource (file="rect_rel.m" amploffset=[0.15] amplscale=[1] ++ timeoffset=10e-6 timescale=1 ++ timerelative=true amplstep=false) + +a3 %vd([out3 0]) filesrc3 + +.model filesrc3 filesource (file="rect_rel.m" amploffset=[0.2] amplscale=[0.9] ++ timeoffset=5e-6 timescale=1.2 ++ timerelative=true amplstep=false) + +a4 %vd([out4 0]) filesrc4 + +.model filesrc4 filesource (file="rect_rel.m" amploffset=[0.05] amplscale=[1.2] ++ timeoffset=0 timescale=1.2 ++ timerelative=true amplstep=true) + + +a5 %vd([out5 0]) filesrc5 + +.model filesrc5 filesource (file="rect_abs.m" amploffset=[0.05] amplscale=[1.1] ++ timeoffset=5u timescale=1.2 ++ timerelative=false amplstep=false) + +a6 %v([out6 out7]) filesrc6 + +.model filesrc6 filesource (file="rect_abs_dual.m" amploffset=[0.05 -0.05] amplscale=[0.9] ++ timeoffset=5u timescale=1.2 ++ timerelative=false amplstep=false) + +.control +tran 0.1u 100u +set xbrushwidth=3 +plot V(out1) V(out2)+2 V(out3)+4 V(out4)+6 V(out5)+8 V(out6)+11 V(out7)+11 +.endc + +.end + + + diff --git a/examples/xspice/filesource/rect_abs.m b/examples/xspice/filesource/rect_abs.m new file mode 100644 index 000000000..057ce7074 --- /dev/null +++ b/examples/xspice/filesource/rect_abs.m @@ -0,0 +1,11 @@ +# simple input, time absolute +0 0 +10e-6 0 +11e-6 1.8 +21e-6 1.8 +22e-6 0 +32e-6 0 +33e-6 1.8 +43e-6 1.8 +44e-6 0 +1 0 diff --git a/examples/xspice/filesource/rect_abs_dual.m b/examples/xspice/filesource/rect_abs_dual.m new file mode 100644 index 000000000..2e4fd716e --- /dev/null +++ b/examples/xspice/filesource/rect_abs_dual.m @@ -0,0 +1,11 @@ +# simple input, time absolut +0 0 0 +10e-6 0 0 +11e-6 1.8 -0.3 +21e-6 1.8 -0.3 +22e-6 0 -0.6 +32e-6 0 -0.6 +33e-6 1.8 -0.3 +43e-6 1.8 -0.3 +44e-6 0 0 +1 0 diff --git a/examples/xspice/filesource/rect_rel.m b/examples/xspice/filesource/rect_rel.m new file mode 100644 index 000000000..5d2c7b425 --- /dev/null +++ b/examples/xspice/filesource/rect_rel.m @@ -0,0 +1,11 @@ +# simple input, time relative +0 0 +10e-6 0 +1e-6 1.8 +10e-6 1.8 +1e-6 0 +10e-6 0 +1e-6 1.8 +10e-6 1.8 +1e-6 0 +1 0 diff --git a/src/xspice/icm/analog/file_source/cfunc.mod b/src/xspice/icm/analog/file_source/cfunc.mod index 4e5765b8d..2190b1a67 100644 --- a/src/xspice/icm/analog/file_source/cfunc.mod +++ b/src/xspice/icm/analog/file_source/cfunc.mod @@ -14,6 +14,7 @@ AUTHORS 03 Sep 2012 Holger Vogt 27 Feb 2017 Marcel Hendrix 23 JUL 2018 Holger Vogt + 11 Aug 2025 Holger Vogt MODIFICATIONS @@ -171,6 +172,17 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. if (INIT == 1) { int count; + double tprev; /* store the previous time, used when time relative is set */ + bool terr = MIF_FALSE; /* Cumulative warning message upon error during time reading */ + bool derr = MIF_FALSE; /* Cumulative warning message upon error during data reading */ + + /* add time offset only once to tprev */ + if (!PARAM_NULL(timeoffset)) { + tprev = PARAM(timeoffset); + } + else + tprev = 0.; + /*** allocate static storage for *loc ***/ if ((loc = (Local_Data_t *) (STATIC_VAR(locdata) = calloc(1, @@ -240,11 +252,12 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. amplscalesize = PARAM_NULL(amplscale) ? 0 : PARAM_SIZE(amplscale); amploffssize = PARAM_NULL(amploffset) ? 0 : PARAM_SIZE(amploffset); count = 0; + while (!loc->state->atend) { char line[512]; char *cp, *cpdel; char *cp2; - double t, tprev = 0; + double t = 0, d = 0; int i; if (!fgets(line, sizeof(line), loc->state->fp)) { loc->state->atend = 1; @@ -260,13 +273,14 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. /* read the time channel; update the time difference */ while (*cp && isspace_c(*cp)) ++cp; - if (*cp == '*' || *cp == '#' || *cp == ';') { + if (*cp == '*' || *cp == '#' || *cp == ';' || *cp == '\0') { free(cpdel); continue; } t = strtod(cp, &cp2); if (cp2 == cp) { free(cpdel); + terr = MIF_TRUE; continue; } cp = cp2; @@ -297,15 +311,17 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. for (i = 0; i < size; ++i) { while (*cp && (isspace_c(*cp) || *cp == ',')) ++cp; - t = strtod(cp, &cp2); - if (cp2 == cp) + d = strtod(cp, &cp2); + if (cp2 == cp) { + derr = MIF_TRUE; break; + } cp = cp2; if (i < amplscalesize) - t *= PARAM(amplscale[i]); + d *= PARAM(amplscale[i]); if (i < amploffssize) - t += PARAM(amploffset[i]); - loc->indata->datavec[count++] = t; + d += PARAM(amploffset[i]); + loc->indata->datavec[count++] = d; } free(cpdel); } @@ -318,6 +334,11 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. /* set the start time data */ loc->timeinterval[0] = loc->indata->datavec[loc->indata->actpointer]; loc->timeinterval[1] = loc->indata->datavec[loc->indata->actpointer + stepsize]; + + if (terr) + cm_message_printf("WARNING: some error occured during reading the time values"); + if (derr) + cm_message_printf("WARNING: some error occured during reading the data values"); } loc = STATIC_VAR (locdata); @@ -326,7 +347,7 @@ void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. * If TIME steps backward, for example due to a second invocation of a 'tran' analysis * step back in datavec[loc->indata->actpointer] . */ - if (TIME < loc->timeinterval[0]) { + if (TIME < loc->timeinterval[0] && loc->indata->actpointer >= stepsize) { while (TIME < loc->indata->datavec[loc->indata->actpointer] && loc->indata->actpointer >= 0) loc->indata->actpointer -= stepsize; loc->timeinterval[0] = loc->indata->datavec[loc->indata->actpointer];