-- -----------------------------------------------------------
-- 
-- Additional material to the book
-- Modeling and Simulation for RF System Design
-- 
--
-- THIS MODEL IS LICENSED TO YOU "AS IT IS" AND WITH NO WARRANTIES, 
-- EXPRESSED OR IMPLIED. THE AUTHORS SPECIFICALLY DISCLAIM ALL IMPLIED 
-- WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-- THEY MUST NOT HAVE ANY RESPONSIBILITY FOR ANY DAMAGES, FINANCIAL OR
-- LEGAL CLAIMS WHATEVER.
-- -----------------------------------------------------------

-- Name:      Piece-Wise Linear Quantity Source
-- 
-- Description:
-- The model describes a PWL nonconservative source in a similar way as 
-- a SPICE piece-wise independent voltage source. The parameter WAVE is 
-- a one dimensional real array with time value pairs T1, V1, T2, V2, ... 
-- Each pair of values Ti, Vi specifies that the value of the source 
-- is Vi at time Ti.  The value of the source at intermediate values 
-- is determined by using linear interpolation. The times must be given 
-- in ascending order.
--
-- Literature:
-- T. Quarles et al: SPICE3 Version 3f3 User's Manual.
-- University of California, May 1993.
--
-- Model Library FUNDAMENTALS_VDA of VDA/FAT-AK30: 
-- http://fat-ak30.eas.iis.fraunhofer.de
-- 
-- Dependencies: 
-- -----------------------------------------------------------
-- Logical Library         Design unit
-- -----------------------------------------------------------
-- 
-- -----------------------------------------------------------
--
-- Source:
-- qpwl.vhd
-- -----------------------------------------------------------

-- -----------------------------------------------------------
-- Note:
--
-- The model is based on QPWL_VDA(SPICE) of the FUNDAMENTALS_VDA
-- library of the VDA/FAT-AK 30 (http://fat-ak30.eas.iis.fraunhofer.de)
--
-- Modifications:
-- * Entity and architecture names were changed. 
-- * Arguments ACMAG and ACPHASE were removed.
-- * Replacement of comments. 
--
-- Date: 2005/04/30
--
-- The original models contains the following disclaimer:
--
-- Copyright (c) 2004 VDA / FAT
--
-- This model is a component of the open source library created by the VDA / FAT 
-- working group number 30 and is covered by this license agreement . 
-- This model including any updates, modifications, revisions, copies, and 
-- documentation are copyrighted works of the VDA / FAT.
-- USE OF THIS MODEL INDICATES YOUR COMPLETE AND 
-- UNCONDITIONAL ACCEPTANCE OF THE TERMS AND CONDITIONS 
-- SET FORTH IN THIS LICENSE AGREEMENT. 
-- The VDA / FAT grants a non-exclusive license to use, reproduce, 
-- modify and distribute this model under the condition, that:
-- (a) no fee or other consideration is charged for any distribution except 
-- compilations distributed in accordance with Section (d) of this license 
-- agreement
-- (b) the comment text embedded in this model is included verbatim
-- in each copy of this model made or distributed by you, whether or not such
-- version is modified
-- (c) any modified version must include a conspicuous
-- notice that this model has been modified and the date of modification; and
-- (d) any compilations sold by you that include this model must include a 
-- conspicuous notice that this model is available from the VDA / FAT in its
-- original form at no charge.
--
-- THIS MODEL IS LICENSED TO YOU "AS IT IS" AND WITH NO WARRANTIES, 
-- EXPRESSED OR IMPLIED. THE VDA / FAT AND ALL COMPANIES CONTRIBUTING 
-- TO THIS LIBRARY SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF 
-- MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-- THE VDA / FAT AND ALL COMPANIES ORGANIZED WITHIN MUST NOT
-- HAVE ANY RESPONSIBILITY FOR ANY DAMAGES, FINANCIAL OR LEGAL CLAIMS 
-- WHATEVER.
-- -----------------------------------------------------------


entity QPWL is
   generic  (
      WAVE    : REAL_VECTOR       -- time value pairs T1/ V1/ T2/ V2/ ...
      );
   port     (
      quantity OUTP : out REAL    -- output
      );
end entity QPWL;


architecture BASIC of QPWL is 

  function WAVE_PAIRS (WAVE : REAL_VECTOR) 
  return NATURAL is
   constant ILEFT  : INTEGER := WAVE'LEFT;
   variable RESULT : NATURAL := 0;
  begin
   if WAVE'LENGTH < 4 then
    report "ERROR: Not enough elements in WAVE."
    severity error;
   else
    if WAVE'ASCENDING /= TRUE then
     report "ERROR: Index range of WAVE must be in ascending order."
     severity error;
    else
     if WAVE'LENGTH MOD 2 = 0 then
      RESULT := WAVE'LENGTH/2;
      for I in 1 to RESULT-1 loop
       if WAVE(ILEFT + 2*I) <= WAVE(ILEFT + 2*(I-1)) then
        report "ERROR: Times must be in ascending order."
        severity error;
       end if;
      end loop;
     else
      report "ERROR: Even number of elements in WAVE required."
      severity error;
     end if;
    end if;
   end if;
  return RESULT;
  end function WAVE_PAIRS;

  function REAL2TIME (TT: REAL) return TIME is
  begin
  return INTEGER(TT * 1.0e15) * 1 fs;
  end function REAL2TIME;
      
  constant PAIRS      : INTEGER := WAVE_PAIRS(WAVE); 

  signal   VALUE_OLD : REAL := 0.0;  -- left bound of approximation interval
  signal   TIME_OLD  : REAL := -1.0; -- left bound of approximation interval
  signal   VALUE_NEW : REAL := 0.0;  -- right bound of approximation interval
  signal   TIME_NEW  : REAL := 0.0;  -- right bound of approximation interval

begin

P1:  process is
      constant ILEFT       : INTEGER := WAVE'LEFT;  
      variable ISTART      : INTEGER;  
      variable TIME_VALUE  : REAL;  -- last times value that was read
      variable VALUE       : REAL;  -- last value that was read
   begin
 
      -- Last time point less equal 0.0
      -- Constant waveform equal last value

L1:  if WAVE(ILEFT+2*(PAIRS-1)) <= 0.0 then
         TIME_OLD  <=  WAVE(ILEFT+2*(PAIRS-1))-1.0;
         VALUE_OLD <=  WAVE(ILEFT+2*(PAIRS-1)+1);
         TIME_NEW  <=  WAVE(ILEFT+2*(PAIRS-1));
         VALUE_NEW <=  WAVE(ILEFT+2*(PAIRS-1)+1);
         wait;
      end if;

      -- Last time point greater 0.0

      ISTART := 0;

L2:   for I in 0 to PAIRS-1 loop
          ISTART := I;
          if WAVE(ILEFT+2*I) >= 0.0 then
             exit;
          end if;
      end loop L2;

L3:   if ISTART = 0 then
         TIME_OLD   <= WAVE(ILEFT)-1.0;
         VALUE_OLD  <= WAVE(ILEFT+1);
         TIME_NEW   <= WAVE(ILEFT);
         VALUE_NEW  <= WAVE(ILEFT+1);
         TIME_VALUE := WAVE(ILEFT);
         VALUE      := WAVE(ILEFT+1);
      else
         TIME_OLD   <= WAVE(ILEFT+2*(ISTART-1));
         VALUE_OLD  <= WAVE(ILEFT+2*(ISTART-1)+1);
         TIME_NEW   <= WAVE(ILEFT+2*ISTART);
         VALUE_NEW  <= WAVE(ILEFT+2*ISTART+1);
         TIME_VALUE := WAVE(ILEFT+2*ISTART);
         VALUE      := WAVE(ILEFT+2*ISTART+1);
      end if;

      wait for TIME_VALUE;

      -- values for PWL approximation

L4:   for I in ISTART+1 to PAIRS-1 loop
          TIME_OLD   <= TIME_VALUE;
          VALUE_OLD  <= VALUE;

          TIME_VALUE := WAVE(ILEFT+2*I);
          VALUE      := WAVE(ILEFT+2*I+1);

          TIME_NEW   <= TIME_VALUE;
          VALUE_NEW  <= VALUE;
         
          wait until TIME_NEW'EVENT;

          if REAL2TIME(TIME_VALUE) > TIME'HIGH then
             report "WARNING: Time value greater TIME'HIGH."
             severity note;
             wait;
          end if;      

          wait for TIME_VALUE-NOW;
      end loop L4;

      -- constant continuation after last time - value - pair
    
      TIME_OLD  <= TIME_VALUE;
      VALUE_OLD <= VALUE;
      TIME_NEW  <= TIME_VALUE + 1.0;
      VALUE_NEW <= VALUE;

      wait;
   end process P1;

   OUTP == VALUE_OLD + (VALUE_NEW - VALUE_OLD)/(TIME_NEW - TIME_OLD)*(NOW - TIME_OLD);
   break on VALUE_OLD, VALUE_NEW, TIME_NEW, TIME_OLD;

end architecture BASIC;
  
