import numpy as np
import matplotlib.pyplot as plt

colors = {
    "U": "tab:blue",      # Voltage
    "I": "tab:orange",    # Current
    "P": "tab:green",     # Real power
    "S": "tab:red",       # Apparent power
    "Q": "tab:purple"     # Reactive power
}

def convert_voltage(v):
    Vu = np.divide(10, 566)
    return np.divide(v, Vu)

def convert_back_voltage(v):
    Vu = np.divide(10, 566)
    return np.multiply(v, Vu)

def convert_current(i):
    Vi = np.divide(10, 0.9)
    return np.divide(i, Vi)

def convert_back_current(i):
    Vi = np.divide(10, 0.9)
    return np.multiply(i, Vi)

def convert_power(p):
    Vu = np.divide(10, 566)
    Vi = np.divide(10, 0.9)
    p = np.divide(p, Vu)
    return np.divide(p, Vi)

def convert_back_power(p):
    Vu = np.divide(10, 566)
    Vi = np.divide(10, 0.9)
    p = np.multiply(p, Vu)
    return np.multiply(p, Vi)

class Messung5:
    def __init__(self, data, name):
        self.name = name
        if name == "Leuchtstoffröhre":
            self.voltage = np.multiply(convert_voltage(data[0]),np.sqrt(3))
        else:
            self.voltage = convert_voltage(data[0])
        self.current = convert_current(data[1])

        self.u_rms = np.sqrt(np.mean(np.square(self.voltage)))
        self.i_rms = np.sqrt(np.mean(np.square(self.current)))

        self.pltvoltage = self.voltage[0:1200]
        self.pltcurrent = self.current[0:1200]

        self.P = np.mean(self.voltage * self.current)

        self.S = self.u_rms * self.i_rms

        self.Q = np.sqrt(np.square(self.S) - np.square(self.P))
        
        self.cos_phi = self.P / self.S

    def augenblickleistung(self):
        print(f"{self.name}:\nAugenblickleistung: {self.u_eff * self.i_eff}\n")
    
    def print(self):
        print(
            f"{self.name}:\n"
            f"cos_phi1\t = {self.cos_phi}\n"
            f"Scheinleistung\t = {self.S} W\n"
            f"Wirkleistung\t = {self.P} W\n"
            f"Blindleistung\t = {self.Q} W\n"
        )

    def plot(self, show=False):
        plt.plot(self.pltvoltage, label='voltage in V')
        plt.plot(self.pltcurrent*1000, label='current in mA')
        plt.plot(self.P, label='Leistung in W')
        plt.legend()
        plt.grid()
        plt.xlabel('time in ms')
        plt.ylabel('value')
        if show:
            plt.show()

def task_5_4_1():
    birne = Messung5(np.load('prak5/5.4.1_glueh.npy'), "Glühbirne")
    led = Messung5(np.load('prak5/5.4.1_LED.npy'), "LED")
    roehre = Messung5(np.load('prak5/5.4.1_Leuchtstoffroehre.npy'), "Leuchtstoffröhre")

    # birne.plot(show=True)

    birne.print()
    led.print()
    roehre.print()

class Messwerte:
    def __init__(self, name, p, q, u_eff, i_eff):
        self.name = name
        self.u_eff = convert_voltage(u_eff)
        self.i_eff = convert_current(i_eff)
        self.p = convert_power(p)
        self.q = np.divide(convert_power(q), np.sqrt(3))
        self.s = self.u_eff * self.i_eff
        self.q_calc = np.sqrt((np.square(self.s)-np.square(self.p)))

    def print(self):
        print(
            f"{self.name}:\n"
            f"\t Spannung\t\t = {self.u_eff} V\n"
            f"\t Strom\t\t\t = {self.i_eff} A\n"
            f"\t Wirkleistung\t\t = {self.p} W\n"
            f"\t Blindleistung\t\t = {self.q} var\n"
            f"\t Scheinleistung\t\t = {self.s} AV\n"
            f"\t Blindleistung Mess\t = {self.q_calc} var\n"
        )

def task_5_4_2():
    glueh = Messwerte("Glühlampe", 10.9, 0.06, 3.94, 2.801)
    led = Messwerte("LED", 1.15, 0.25, 3.94, 0.4)
    roehre = Messwerte("Leuchtstoffröhre", 4.57, 23, 3.93, 3.8)

    glueh.print()
    led.print()
    roehre.print()

def dimmer_messung(ax):
    delta_t = np.divide([1.8, 3.2, 4.2, 5.2, 6.2, 7.2, 8.2], 1.31)
    U_eff=np.empty(len(delta_t)); 
    U_eff.fill(3.93)
    U_eff = convert_voltage(U_eff)
    I_eff = [2.794, 2.729, 2.57, 2.38, 2.219, 1.82, 1.443]
    I_eff = convert_current(I_eff)
    P = [10.8, 10.1, 8.7, 6.95, 5.68, 3.18, 1.62]
    P = convert_power(P)
    S = np.multiply(I_eff, U_eff)
    Q = np.sqrt(np.square(S)-np.square(P))
    ax.plot(anschnittzeit_zu_winkel(delta_t), np.divide(U_eff, 10), label='Spannung gemessen in daV', linestyle='--', marker='x', markersize=8,  color=colors["U"])
    ax.plot(anschnittzeit_zu_winkel(delta_t), np.multiply(100, I_eff), label='Strom gemessen in cA', linestyle='--', marker='x', markersize=8,   color=colors["I"])
    ax.plot(anschnittzeit_zu_winkel(delta_t), P, label='Wirkleistung gemessen in W', linestyle='--', marker='x', markersize=8,          color=colors["P"])
    ax.plot(anschnittzeit_zu_winkel(delta_t), S, label='Scheinleistung gemessen in VA', linestyle='--', marker='x', markersize=8,       color=colors["S"])
    ax.plot(anschnittzeit_zu_winkel(delta_t), Q, label='Blindleistung gemessen in var', linestyle='--', marker='x', markersize=8,       color=colors["Q"])
    # plt.legend()
    # plt.grid()
    # plt.xlabel('Anchnitt in °')
    # plt.ylabel('Wert in cA/W/VA/var')
    # plt.savefig(f"prak5/dimmer_mesung.svg", format="svg")
    # plt.show()

def generate_sin_wave(frequency, amplitude, duration, phase_shift=0, anschnitt=0):
    sample_rate = 44100
    num_samples = int(duration * sample_rate)
    t = np.linspace(0, duration, num_samples)
    omega = 2 * np.pi * frequency
    y = amplitude * np.sin(omega * t + phase_shift)
    if anschnitt > 0:
        phi = np.mod(omega * t + phase_shift, np.pi)
        conduction = phi >= anschnitt
        y = np.where(conduction, y, 0)

    return t, y

def anschnittwinkel_zu_zeit(winkel):
    f = 50
    T = 1/f

    theta = np.deg2rad(winkel)
    t_sec = np.divide(theta, (2*np.pi) * T)
    t_ms = t_sec * 1000
    return t_ms

def anschnittrad_zu_zeit(rad):
    f = 50
    T = 4*1/f
    theta = rad
    t_sec = np.divide(theta, (2*np.pi) * T)
    t_ms = t_sec * 1000
    return t_ms

def anschnittzeit_zu_winkel(t_ms):
    f = 50
    T = 1/f
    t_sec = np.divide(t_ms, 1000)
    theta = t_sec * (2*np.pi) / T
    return np.rad2deg(theta)

def anschnittzeit_zu_rad(t_ms):
    f = 50
    T = 1/f
    t_sec = np.divide(t_ms, 1000)
    theta = t_sec * (2*np.pi) / T
    return theta

def calc_P(u_t, i_t, T):
    return np.divide(np.sum(u_t * i_t), T)

def dimmer_theorie(ax):
    f = 50
    T = 1/f
    U = 222.438
    theta_winkel = np.arange(0, 180, 1)
    theta = np.deg2rad(theta_winkel)
    t, u = generate_sin_wave(f, U*np.sqrt(2), T)

    v_hat = np.max(u)
    V_RMS = np.divide(v_hat, np.sqrt(2))

    U_RMS=np.empty(len(theta)); 
    U_RMS.fill(V_RMS)

    I = 0.25209000000000004
    I_RMS = []
    P = [] 
    for angle in theta:
        _, i = generate_sin_wave(f, np.multiply(I, np.sqrt(2)), T, anschnitt=angle)
        i_eff = np.sqrt(np.mean(np.square(i)))
        I_RMS.append(i_eff)
        P.append(np.mean(i * u))
    
    S = np.multiply(U_RMS, I_RMS)
    Q = np.sqrt(np.square(S)-np.square(P))
    ax.plot(theta_winkel, np.divide(U_RMS, 10),     label='Voltage in daV',         color=colors["U"])
    ax.plot(theta_winkel, np.multiply(I_RMS, 100),  label='Strom in cA',            color=colors["I"])
    ax.plot(theta_winkel, P,                        label='Wirkleistung in W',      color=colors["P"])
    ax.plot(theta_winkel, S,                        label='Scheinleistung in VA',   color=colors["S"])
    ax.plot(theta_winkel, Q,                        label='Blindleistung in var',   color=colors["Q"])


if __name__ == '__main__':
    # task_5_4_1()
    # task_5_4_2()

    fig, ax = plt.subplots(figsize=(8, 5))
    dimmer_messung(ax)
    dimmer_theorie(ax)

    ax.grid()
    ax.set_xlabel('Anchnitt in °')
    ax.set_ylabel('Wert in daV/cA/W/var')

    ax.legend(
        loc="upper center",
        bbox_to_anchor=(0.5, -0.18),  # push legend below axes
        ncol=3,                      # spread entries horizontally
        frameon=False
    )
    plt.tight_layout()
    plt.savefig("prak5/dimmer.svg", format="svg", bbox_inches="tight")
    plt.show()