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