----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 31.05.2022 08:04:28
-- Design Name: 
-- Module Name: autoTuning - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

--  Sollwert/Startsignal (CTRL-Unit) -> AutoTuning -> Regler -> Strecke 

entity autoTuning is
    Port ( clk : in STD_LOGIC;
           prescaler : in signed(63 downto 0) := to_signed(1000000, 64);   -- prescaler für Zeit 1000000
           duration : in signed(63 downto 0) := to_signed(5000000, 64);  -- Zeit in Microsekunden/ oder Clk-Ticks?
           start_Tuning : inout std_logic := '0';
           regler_bruecken : out STD_LOGIC := '0';
           w : in signed(63 downto 0) := (others => '0');       --Sollwert für Regler -> während Outotuing konst!
           y : in signed(63 downto 0) := (others => '0');       --Istwert
           --u : inout signed(63 downto 0) := (others => '0');    --Stellgöße
           KR : out signed(9 downto 0) := to_signed(1, 10);      -- Verstärkung
           T : in signed(9 downto 0) := to_signed(1000, 10);    -- Abtastzeit in us 1000us
           TV : out signed(9 downto 0) := (others => '0');          -- Vorhaltezeit   für Differenzierer interesannt
           TN : out signed(9 downto 0) := to_signed(1, 10));     -- Nachstellzeit);   -- u <= w);
end autoTuning;



architecture Behavioral of autoTuning is

--signal prescaler : signed(63 downto 0) := to_signed(1000000, 64);   -- prescaler für Zeit 1000000

type data_array is array (0 to 2000) of signed(63 downto 0);

begin

process(clk)

variable counter : signed(63 downto 0) := to_signed(0, 64);
variable counter_us : signed(63 downto 0) := to_signed(0, 64);  --Prescaler für Clk-Ticks

variable dt : signed(63 downto 0) := to_signed(0, 64); -- Zeit zwischen Messwerte Scrhittweite (us/Wert)

variable data : data_array; --Array mit Messwerten
variable data_pos : integer := 0;   --iterator für Array

variable steigung : signed(63 downto 0) := to_signed(0, 64);
variable steigung_last : signed(63 downto 0) := to_signed(0, 64);
variable data_pos_wendetangente : integer := 0;

--Hilfsgerade Wendetangente
variable b : signed(63 downto 0) := to_signed(0, 64);

--Messwerte aus Sprungantwort
variable Tu : signed(63 downto 0) := to_signed(0, 64);  -- Verzugszeit  us
variable Tg : signed(63 downto 0) := to_signed(0, 64);  -- Ausgleichstzeit  us
variable Ks : signed(63 downto 0) := to_signed(0, 64);  -- Verstärkungsfaktor us



begin

if(rising_edge(clk)) then

    if(start_Tuning = '1') then
        --Messvorgang starten
        regler_bruecken <= '1';
        

        
        
        counter_us := counter_us + 1;
        --125 MHZ CLK !!! -> 125 Ticks = 1 us
        if(counter_us >= 125) then
            
            counter_us := to_signed(0, 64);
            counter := counter + 1;
            
        --Messwerte aufzeichnen:
        dt := duration / to_signed(2000, 64);    --schrittweite
            
            if(counter >= dt * to_signed(data_pos,64)) then
                --Wert abspeichern -> nicht rdy
                data(data_pos) := y;
            end if;
            
            if(counter >= duration) then
                counter := to_signed(0, 64);
                start_Tuning <= '0';  --Messvorgang beenden
            end if;        
        end if;
        
    else 
        -- autoTuning beenden
        regler_bruecken <= '0';
        counter := to_signed(0, 64);
        counter_us := to_signed(0, 64);
        data_pos := 0;
        
        --Parameter berechnen/setzen:
        
        dt := duration / to_signed(2000, 64);    --schrittweite
        
        for i in 1 to 2000 loop
            steigung_last := steigung;
            --steigung := (data(i) - data(i-1)) / dt; --"Richtig"
            steigung := (data(i) - data(i-1));                
            if (steigung < steigung_last) then
                data_pos_wendetangente := i;
                exit;
            end if;                       
        end loop;
        
        -- y = mx + b
        b := data(data_pos_wendetangente) - steigung * to_signed(data_pos_wendetangente, 32);
        Ks := data(2000);
        Tu := -b * dt / steigung;
        Tg := (Ks - b) * dt / steigung - Tu;
        
        --PI-Regler berechnen:
        --chien, hrones Reswick aperiodischer Verlauf Störung
        KR <= 6*Tg/Tu/Ks/10;
        TV <= to_signed(0, 10);
        TN <= 4 * Tu;
        
        
    end if;

end if;

end process;

end Behavioral;
