Thursday, October 5, 2017

model for piecewise linear source

http://www.designers-guide.org/Forum/YaBB.pl?num=1270820173

Verilog-A pwl implementation using arrays for time/voltage input

`include "disciplines.vams"

module pwl(out);
output out;
electrical out;

parameter integer N = 1 from [2:inf);parameter real t[1:N] = {N{0}};
parameter real y[1:N] = {N{0}};

analog begin : blk
integer nxt_i;
real yp, tp, slope;
integer err;

        @(initial_step) begin
                nxt_i = 1;
                yp = y[1];
                tp = 0.0;
        end

        @(timer(t[nxt_i])) begin
                yp = y[nxt_i];
                tp = t[nxt_i];

                if(nxt_i < N) begin
                        nxt_i = nxt_i + 1;
                        if(t[nxt_i] - tp <= 0) begin
                                err = 1;
                                $debug("Non monotonic time sequence: t[%d] == %e, t[%d] == %e", nxt_i-1, tp, nxt_i, t[nxt_i]);
                                $finish;
                        end
                        if(!err)
                                slope = (y[nxt_i] - yp)/(t[nxt_i] - tp);
                end
        end

        if(!err)
                V(out) <+ yp + slope*($realtime - tp);

end

endmodule




System-Verilog pwl implementation


module strpwl(p, n);
   electrical p, n;
   inout p, n;

   parameter string pwl = "";
   parameter        dcval = 0.0;
  

   analog function real scanval;
      input s;
      inout pos;
      string s;
      integer pos;
      integer ipos;
      string  valstr;
            
      begin
         ipos = pos;
         while(pos < s.len() && s.substr(pos, pos) != ",")
           pos = pos+1;

         valstr = s.substr(ipos, pos-1);
         if(1 == $sscanf(valstr, "%g", scanval))
           pos = pos+1;
         else
           pos = -1;  // Error indicator
      end
   endfunction

   integer pos = 0;
   real    tnext, vnext;
   real    tprev = 0.0;
   real    vprev = dcval;
   real    slope;
  
   integer err;
  
   analog initial begin : blk
      real retVal;

      tprev = 0.0;
      vprev = dcval;
      
      tnext = scanval(pwl, pos);
      vnext = scanval(pwl, pos);
      if (tnext-tprev != 0.0)
          slope = (vnext - vprev)/(tnext - tprev);
      $strobe(tnext, vnext);
   end

   analog begin
      @(timer(tnext)) begin
         tprev = tnext;
         vprev = vnext;
        
         tnext = scanval(pwl, pos);
         vnext = scanval(pwl, pos);

         if(pos > 0)
           begin
              if(tnext - tprev <= 0) begin
                 err = 1;
                 $debug("Non monotonic time sequence.");
                 $finish;
              end
              if(!err)
                slope = (vnext - vprev)/(tnext - tprev);
           end
      end

      if(!err)
        V(p, n) <+ vprev + slope*($abstime - tprev);

   end

endmodule