/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2012
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: Alexander Schloegl <alexander.schloegl@gmx.de>
 */

#include <ns3/log.h>
#include <ns3/type-id.h>
#include <math.h>

#include "plc-cable.h"


namespace ns3 {

NS_LOG_COMPONENT_DEFINE("PLC_Cable");
NS_OBJECT_ENSURE_REGISTERED(PLC_Cable);
NS_OBJECT_ENSURE_REGISTERED(PLC_ThreeCoreConcentricCable);
NS_OBJECT_ENSURE_REGISTERED(PLC_FourSectorPowerSupplyCable);
NS_OBJECT_ENSURE_REGISTERED(PLC_Overheadpowerline);
NS_OBJECT_ENSURE_REGISTERED(PLC_AL3x95XLPE_Cable);
NS_OBJECT_ENSURE_REGISTERED(PLC_NAYY150SE_Cable);
NS_OBJECT_ENSURE_REGISTERED(PLC_NAYY50SE_Cable);
NS_OBJECT_ENSURE_REGISTERED(PLC_NAYY95SE_Cable); //_K
NS_OBJECT_ENSURE_REGISTERED(PLC_NAYY240SE_Cable); //_K
NS_OBJECT_ENSURE_REGISTERED(PLC_NAYY185SE_Cable); //_K
NS_OBJECT_ENSURE_REGISTERED(PLC_AYKY4x50_Cable); 
NS_OBJECT_ENSURE_REGISTERED(PLC_NYCY70SM35_Cable);
NS_OBJECT_ENSURE_REGISTERED(PLC_AlFe4x50_Cable);
NS_OBJECT_ENSURE_REGISTERED(PLC_AYKY3x120_70_Cable);
NS_OBJECT_ENSURE_REGISTERED(PLC_AXEKCY240); //_K
NS_OBJECT_ENSURE_REGISTERED(PLC_AXEKVCEY240); //_K


TypeId
PLC_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("ns3::PLC_Cable")
    		.SetParent<Object> ()
    		;
	return tid;
}

PLC_Cable::PLC_Cable(Ptr<const SpectrumModel> sm)
	: m_spectrum_model(sm)
{
	z_c 	= CreateObject<PLC_FreqSelectiveImpedance>(sm);
	gamma 	= CreateObject<PLC_FreqSelectiveImpedance>(sm);
}

PLC_Cable::PLC_Cable (const PLC_FreqSelectiveResistance& R, const PLC_FreqSelectiveConductance& G, const PLC_FreqSelectiveInductance& L, const PLC_FreqSelectiveCapacitance& C, Ptr<const SpectrumModel> sm)
	: m_spectrum_model(sm)
{
	NS_ASSERT(R.size() == sm->GetNumBands());
	NS_ASSERT(G.size() == sm->GetNumBands());
	NS_ASSERT(C.size() == sm->GetNumBands());
	NS_ASSERT(L.size() == sm->GetNumBands());

	uint32_t cIdx = sm->GetNumBands()/2;

	this->R = R;
	this->G = G;
	this->L = L;
	this->C = C;
	this->v = 1 / sqrt(L[cIdx]*C[cIdx]);

	z_c 	= CreateObject<PLC_FreqSelectiveImpedance>(sm);
	gamma 	= CreateObject<PLC_FreqSelectiveImpedance>(sm);

	this->CalcCharImp();
	this->CalcTransConst();
}

void
PLC_Cable::SetSpectrumModel(Ptr<const SpectrumModel> sm)
{
	m_spectrum_model = sm;
	z_c 	= CreateObject<PLC_FreqSelectiveImpedance>(sm);
	gamma 	= CreateObject<PLC_FreqSelectiveImpedance>(sm);
}

void
PLC_Cable::DoDispose ()
{
	z_c = 0;
	gamma = 0;
	m_spectrum_model = 0;
}

void
PLC_Cable::CalcCharImp (void)
{
	unsigned int i;
	Bands::const_iterator it;
	for (it = this->z_c->GetSpectrumModel()->Begin(), i = 0; it != this->z_c->GetSpectrumModel()->End(); it++, i++) {
		double f = it->fc;
		(*this->z_c)[i] = sqrt(PLC_ImpedanceValue(R[i], 2*M_PI*f*L[i]) / PLC_ImpedanceValue(G[i], 2*M_PI*f*C[i]));
	}
}

void
PLC_Cable::CalcTransConst (void)
{
	unsigned int i;
	Bands::const_iterator it;
	for (it = this->gamma->GetSpectrumModel()->Begin(), i = 0; it != this->gamma->GetSpectrumModel()->End(); it++, i++) {
		double f = it->fc;
		(*this->gamma)[i] = sqrt(PLC_ImpedanceValue(R[i], 2*M_PI*f*L[i]) * PLC_ImpedanceValue(G[i], 2*M_PI*f*C[i]));
	}
}

PLC_FreqSelectiveImpedance
PLC_Cable::GetCharImp(void) const
{
	return (*z_c);
}

PLC_FreqSelectiveImpedance
PLC_Cable::GetTransConst(void) const
{
	return (*gamma);
}

/////////////////////////////ThreeCoreConcentricCable////////////////////////////
TypeId
PLC_ThreeCoreConcentricCable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_ThreeCoreConcentricCable")
    		.SetParent<PLC_Cable> ()
    		;
	return tid;
}

PLC_ThreeCoreConcentricCable::PLC_ThreeCoreConcentricCable(double r, double lconst, double c, double g, double l, Ptr<const SpectrumModel> sm) : PLC_Cable(sm)
{
	Calculate(r, lconst, c, g, l, sm);
}

void PLC_ThreeCoreConcentricCable::Calculate(double r, double lconst, double c, double g, double l, Ptr<const SpectrumModel> sm)
{
	double C_const = c;
	double L_const = lconst;

	Bands::const_iterator it;
		for (it = sm->Begin(); it != sm->End(); it++) {
			double f = it->fc;
			double fa = f;
			this->R.push_back(r * 10e-5 * sqrt(fa));
			this->G.push_back(l * g * 10e-14 * 2 * M_PI * fa);
		}



		this->C = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), C_const);
		this->L = PLC_FreqSelectiveInductance(sm->GetNumBands(), L_const);
		this->v = 1 / sqrt(L_const*C_const);


	this->CalcCharImp();
	this->CalcTransConst();
}

void PLC_ThreeCoreConcentricCable::Calculate(PLC_FreqSelectiveRealValue eps_r, double kappa, double r_a, double r_i, PLC_FreqSelectiveRealValue tand, Ptr<const SpectrumModel> sm)
{
	NS_ASSERT_MSG (sm->GetNumBands() == eps_r.size(), "Vector of frequency selective permittivity eps_r has different size than spectrum model");
	NS_ASSERT_MSG (sm->GetNumBands() == tand.size(), "Vector of frequency selective loss tangent tand has different size than spectrum model");

	double L_const = (MU_0/(2*M_PI))*log(r_a/r_i);
	this->L = PLC_FreqSelectiveInductance(sm->GetNumBands(), L_const);
	this->C = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), 0);
	this->R = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), 0);
	this->G = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), 0);

	size_t i;
	Bands::const_iterator bit = sm->Begin();
	for (i=0; i<sm->GetNumBands(); i++)
	{
		double f = (bit + i)->fc;
		C[i] = (2*M_PI*EPS_0*eps_r[i])/log(r_a/r_i);
		R[i] = 0.5*sqrt(f*MU_0/(kappa*M_PI) * (1/r_a + 1/r_i));
		G[i] = 2*M_PI*f*C[i]*tand[i];
	}

	size_t mIdx = m_spectrum_model->GetNumBands() / 2;
	this->v = 1 / sqrt(L[mIdx]*C[mIdx]);

	this->CalcCharImp();
	this->CalcTransConst();
}

/////////////////////////////PLC_FourSectorPowerSupplyCable////////////////////////////
TypeId
PLC_FourSectorPowerSupplyCable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_FourSectorPowerSupplyCable")
    		.SetParent<PLC_Cable> ()
    		;
	return tid;
}

PLC_FourSectorPowerSupplyCable::PLC_FourSectorPowerSupplyCable(double radius, double conductor_distance, double tan_loss_angle, double epsilon_r, double rho, Ptr<const SpectrumModel> sm) : PLC_Cable(sm)
{
	Calculate(radius, conductor_distance, tan_loss_angle, epsilon_r, rho, sm);
}

PLC_FourSectorPowerSupplyCable::PLC_FourSectorPowerSupplyCable(double radius, double conductor_distance, PLC_FreqSelectiveRealValue tan_loss_angle, PLC_FreqSelectiveRealValue epsilon_r, double rho, Ptr<const SpectrumModel> sm) : PLC_Cable(sm)
{
	Calculate(radius, conductor_distance, tan_loss_angle, epsilon_r, rho, sm);
}

void
PLC_FourSectorPowerSupplyCable::Calculate(double radius, double conductor_distance, double tan_loss_angle, double epsilon_r, double rho, Ptr<const SpectrumModel> sm)
{
	double C_const = 2*EPS_0*epsilon_r*radius/conductor_distance;
	double L_const = MU_0*conductor_distance/(2*radius);

	this->C = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), C_const);
	this->L = PLC_FreqSelectiveInductance(sm->GetNumBands(), L_const);

	this->v = 1 / sqrt(L_const*C_const);

	Bands::const_iterator it;
	for (it = sm->Begin(); it != sm->End(); it++) {
		double f = it->fc;
		this->R.push_back(sqrt(rho*M_PI*f*MU_0/(pow(radius, 2))));
		this->G.push_back(2*M_PI*f*C_const*tan_loss_angle);
	}

	this->CalcCharImp();
	this->CalcTransConst();
}

void
PLC_FourSectorPowerSupplyCable::Calculate(double radius, double conductor_distance, PLC_FreqSelectiveRealValue tan_loss_angle, PLC_FreqSelectiveRealValue epsilon_r, double rho, Ptr<const SpectrumModel> sm)
{
	NS_ASSERT_MSG (sm->GetNumBands() == epsilon_r.size(), "Vector of frequency selective permittivity epsilon_r has different size than spectrum model");
	NS_ASSERT_MSG (sm->GetNumBands() == tan_loss_angle.size(), "Vector of frequency selective loss tangent tand has different size than spectrum model");

	double L_const = MU_0*conductor_distance/(2*radius);

	this->L = PLC_FreqSelectiveInductance(sm->GetNumBands(), L_const);
	this->C = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), 0);
	this->R = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), 0);
	this->G = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), 0);

	size_t i;
	Bands::const_iterator bit = sm->Begin();
	for (i=0; i<sm->GetNumBands(); i++)
	{
		double f = (bit + i)->fc;
		C[i] = 2*EPS_0*epsilon_r[i]*radius/conductor_distance;
		R[i] = sqrt(rho*M_PI*f*MU_0/(pow(radius, 2)));
		G[i] = 2*M_PI*f*C[i]*tan_loss_angle[i];
	}

	this->v = 1 / sqrt(L_const*C[sm->GetNumBands()/2]);

	this->CalcCharImp();
	this->CalcTransConst();
}

// Overhead cable metody pro výpočet, DP Martin Horak
/////////////////////////////PLC_Overheadpowerline////////////////////////////
TypeId
PLC_Overheadpowerline::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_Overheadpowerline")
    		.SetParent<PLC_Cable> ()
    		;
	return tid;
}

PLC_Overheadpowerline::PLC_Overheadpowerline(double radius, double conductor_distance, double mi_r, double epsilon_r, double tand,Ptr<const SpectrumModel> sm) : PLC_Cable(sm)
{
	Calculate(radius,conductor_distance, mi_r, epsilon_r,tand, sm);
}

PLC_Overheadpowerline::PLC_Overheadpowerline(double Rok, double Gok, double radius, double conductor_distance, double mi_r, double eps_r, double rho, Ptr<const SpectrumModel> sm) : PLC_Cable(sm)
{
	Calculate(Rok, Gok, radius, conductor_distance, mi_r, eps_r, rho, sm);

}

void
PLC_Overheadpowerline::Calculate(double radius, double conductor_distance, double mi_r, double epsilon_r, double tand, Ptr<const SpectrumModel> sm)
{

	double zlom = (conductor_distance/(2*radius));
	double aco = acosh(zlom);

	double C_const = (M_PI*mi_r*EPS_0)/aco;
	double L_const = ((mi_r*MU_0)/M_PI)*aco;

	this->C = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), C_const);
	this->L = PLC_FreqSelectiveInductance(sm->GetNumBands(), L_const);

	this->v = 1 / sqrt(L_const*C_const);

	Bands::const_iterator it;
	for (it = sm->Begin(); it != sm->End(); it++) {
		double f = it->fc;
		this->R.push_back((sqrt((mi_r*MU_0*f)/(M_PI*Aluminium_CONDUCTIVITY*pow(radius,2))))*(zlom/(sqrt(pow(zlom,2)-1))));
		this->G.push_back(2*M_PI*f*C_const);
	}

	this->CalcCharImp();
	this->CalcTransConst();

}

void PLC_Overheadpowerline::Calculate(double Rok, double Gok, double radius, double conductor_distance, double mi_r, double epsilon_r, double rho, Ptr<const SpectrumModel> sm)
{
	double C_const = ((29*epsilon_r)/(log(conductor_distance/radius)))*10e-12;
	double L_const = 0.4*(log(conductor_distance/radius)+0.25)*10e-6;

	this->C = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), C_const);
	this->L = PLC_FreqSelectiveInductance(sm->GetNumBands(), L_const);

	this->v = 1 / sqrt(L_const*C_const);

	Bands::const_iterator it;
	for (it = sm->Begin(); it != sm->End(); it++) {
		double f = it->fc;
		this->R.push_back((Rok*((radius*(sqrt(((f/1000)*mi_r)/rho)))+0.2))*10e-3);
		this->G.push_back((Gok+(0.05*f/1000))*10e-9);
	}

	this->CalcCharImp();
	this->CalcTransConst();

}

/////////////////////////////PLC_MediumVoltageline////////////////////////////////////////////////////_K DP JAKUB PETRŮJ///////////////////////////
TypeId
PLC_MediumVoltageline::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_MediumVoltageline")
    		.SetParent<PLC_Cable> ()
    		;
	return tid;
}

PLC_MediumVoltageline::PLC_MediumVoltageline(double L_, double C_, Ptr<const SpectrumModel> sm) : PLC_Cable(sm)
{
	Calculate(L_,C_, sm);
}


void
PLC_MediumVoltageline::Calculate(double L_, double C_, Ptr<const SpectrumModel> sm)
{
	double G_const = 0; //vodivost se zanedbává

	Bands::const_iterator it;
		for (it = sm->Begin(); it != sm->End(); it++) {
			double f = it->fc;
			//this->R.push_back(((-9e-15)*f*f)+((2e-8)*f)+0.0055);
			this->R.push_back(((-4.58e-15)*f*f)+((1.1e-8)*f)+0.0087);
		}

		this->G = PLC_FreqSelectiveConductance(sm->GetNumBands(), G_const);
		this->C = PLC_FreqSelectiveCapacitance(sm->GetNumBands(), C_);
		this->L = PLC_FreqSelectiveInductance(sm->GetNumBands(), L_);
		this->v = 1 / sqrt(L_*C_);


	this->CalcCharImp();
	this->CalcTransConst();
}


///////////////////PLC_AL3x95XLPE_Cable///////////////////

PLC_AL3x95XLPE_Cable::PLC_AL3x95XLPE_Cable(Ptr<const SpectrumModel> sm) : PLC_ThreeCoreConcentricCable(AL3X95XLPE_EPS_R, AL3X95XLPE_SIGMA, AL3X95XLPE_A, AL3X95XLPE_D, AL3X95XLPE_TAND, sm)
{
}

TypeId
PLC_AL3x95XLPE_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_AL3x95XLPE_Cable")
    		.SetParent<PLC_ThreeCoreConcentricCable> ()
    		.AddConstructor<PLC_AL3x95XLPE_Cable> ()
    		;
	return tid;
}

void
PLC_AL3x95XLPE_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_ThreeCoreConcentricCable::Calculate(AL3X95XLPE_EPS_R, AL3X95XLPE_SIGMA, AL3X95XLPE_A, AL3X95XLPE_D, AL3X95XLPE_TAND, m_spectrum_model);
}

///////////////////PLC_NYCY70SM35_Cable///////////////////

PLC_NYCY70SM35_Cable::PLC_NYCY70SM35_Cable(Ptr<const SpectrumModel> sm) : PLC_ThreeCoreConcentricCable(AL3X95XLPE_EPS_R, AL3X95XLPE_KAPPA, AL3X95XLPE_R_A, AL3X95XLPE_R_I, AL3X95XLPE_TAND, sm)
{
}

TypeId
PLC_NYCY70SM35_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_NYCY70SM35_Cable")
    		.SetParent<PLC_ThreeCoreConcentricCable> ()
    		.AddConstructor<PLC_NYCY70SM35_Cable> ()
    		;
	return tid;
}

void
PLC_NYCY70SM35_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);

	PLC_FreqSelectiveRealValue eps_r(m_spectrum_model->GetNumBands(), 0);
	PLC_FreqSelectiveRealValue tand(m_spectrum_model->GetNumBands(), 0);

	size_t i;
	for (i=0; i<m_spectrum_model->GetNumBands(); i++)
	{
		double f = (m_spectrum_model->Begin() + i)->fc;
		eps_r[i] = 7.95 - ((0.9/std::log10(20))*std::log10(f));
		tand[i] = 0.2345 - ((0.04/std::log10(20))*std::log10(f));
	}

	PLC_ThreeCoreConcentricCable::Calculate(eps_r, COPPER_CONDUCTIVITY, NYCY70SM35_R_O, NYCY70SM35_R_I, tand, m_spectrum_model);
}

///////////////////PLC_NAYY150SE_Cable///////////////////

TypeId
PLC_NAYY150SE_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_NAYY150SE_Cable")
    		.SetParent<PLC_FourSectorPowerSupplyCable> ()
    		.AddConstructor<PLC_NAYY150SE_Cable> ()
    		;
	return tid;
}

PLC_NAYY150SE_Cable::PLC_NAYY150SE_Cable(Ptr<const SpectrumModel> sm)
	: PLC_FourSectorPowerSupplyCable(NAYY150SE_R, NAYY150SE_THETA, TAND, EPS_R, RHO, sm)
{
}

void
PLC_NAYY150SE_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);

	PLC_FreqSelectiveRealValue eps_r(m_spectrum_model->GetNumBands(), 0);
	PLC_FreqSelectiveRealValue tand(m_spectrum_model->GetNumBands(), 0);

	size_t i;
	for (i=0; i<m_spectrum_model->GetNumBands(); i++)
	{
		double f = (m_spectrum_model->Begin() + i)->fc;
		eps_r[i] = 7.95 - ((0.9/std::log10(20))*std::log10(f));
		tand[i] = 0.2345 - ((0.04/std::log10(20))*std::log10(f));
	}

	PLC_FourSectorPowerSupplyCable::Calculate(NAYY150SE_R, NAYY150SE_THETA, tand, eps_r, RHO, m_spectrum_model);
}

///////////////////PLC_NAYY50SE_Cable///////////////////

TypeId
PLC_NAYY50SE_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_NAYY50SE_Cable")
    		.SetParent<PLC_FourSectorPowerSupplyCable> ()
    		.AddConstructor<PLC_NAYY50SE_Cable> ()
    		;
	return tid;
}

PLC_NAYY50SE_Cable::PLC_NAYY50SE_Cable(Ptr<const SpectrumModel> sm)
	: PLC_FourSectorPowerSupplyCable(NAYY50SE_R, NAYY50SE_THETA, TAND, EPS_R, RHO, sm)
{
}

void
PLC_NAYY50SE_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_FourSectorPowerSupplyCable::Calculate(NAYY50SE_R, NAYY50SE_THETA, TAND, EPS_R, RHO, m_spectrum_model);
}

///////////////////PLC_NAYY95SE_Cable///////////////////
///////////////////_K DP JAKUB PETRŮJ//////////////////////

TypeId
PLC_NAYY95SE_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_NAYY95SE_Cable")
    		.SetParent<PLC_FourSectorPowerSupplyCable> ()
    		.AddConstructor<PLC_NAYY95SE_Cable> ()
    		;
	return tid;
}

PLC_NAYY95SE_Cable::PLC_NAYY95SE_Cable(Ptr<const SpectrumModel> sm)
	: PLC_FourSectorPowerSupplyCable(NAYY95SE_R, NAYY95SE_THETA, TAND, EPS_R, RHO, sm)
{
}

void
PLC_NAYY95SE_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_FourSectorPowerSupplyCable::Calculate(NAYY95SE_R, NAYY95SE_THETA, TAND, EPS_R, RHO, m_spectrum_model);
}

///////////////////PLC_NAYY240SE_Cable///////////////////
///////////////////_K DP JAKUB PETRŮJ//////////////////////

TypeId
PLC_NAYY240SE_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_NAYY240SE_Cable")
    		.SetParent<PLC_FourSectorPowerSupplyCable> ()
    		.AddConstructor<PLC_NAYY240SE_Cable> ()
    		;
	return tid;
}

PLC_NAYY240SE_Cable::PLC_NAYY240SE_Cable(Ptr<const SpectrumModel> sm)
	: PLC_FourSectorPowerSupplyCable(NAYY240SE_R, NAYY240SE_THETA, TAND, EPS_R, RHO, sm)
{
}

void
PLC_NAYY240SE_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_FourSectorPowerSupplyCable::Calculate(NAYY240SE_R, NAYY240SE_THETA, TAND, EPS_R, RHO, m_spectrum_model);
}

///////////////////PLC_NAYY185SE_Cable///////////////////
///////////////////_K DP JAKUB PETRŮJ//////////////////////

TypeId
PLC_NAYY185SE_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_NAYY185SE_Cable")
    		.SetParent<PLC_FourSectorPowerSupplyCable> ()
    		.AddConstructor<PLC_NAYY185SE_Cable> ()
    		;
	return tid;
}

PLC_NAYY185SE_Cable::PLC_NAYY185SE_Cable(Ptr<const SpectrumModel> sm)
	: PLC_FourSectorPowerSupplyCable(NAYY185SE_R, NAYY185SE_THETA, TAND, EPS_R, RHO, sm)
{
}

void
PLC_NAYY185SE_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_FourSectorPowerSupplyCable::Calculate(NAYY185SE_R, NAYY185SE_THETA, TAND, EPS_R, RHO, m_spectrum_model);
}

///////////////////PLC_AYKY4x50_Cable///////////////////

TypeId
PLC_AYKY4x50_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_AYKY4x50_Cable")
    		.SetParent<PLC_FourSectorPowerSupplyCable> ()
    		.AddConstructor<PLC_AYKY4x50_Cable> ()
    		;
	return tid;
}

PLC_AYKY4x50_Cable::PLC_AYKY4x50_Cable(Ptr<const SpectrumModel> sm)
	: PLC_FourSectorPowerSupplyCable(AYKY4x50_R, AYKY4x50_THETA, TAND, EPS_R, RHO, sm)
{
}

void
PLC_AYKY4x50_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);

	PLC_FreqSelectiveRealValue eps_r(m_spectrum_model->GetNumBands(), 0);
	PLC_FreqSelectiveRealValue tand(m_spectrum_model->GetNumBands(), 0);

	size_t i;
	for (i=0; i<m_spectrum_model->GetNumBands(); i++)
	{
		double f = (m_spectrum_model->Begin() + i)->fc;
		eps_r[i] = 7.95 - ((0.9/std::log10(20))*std::log10(f));
		tand[i] = 0.2345 - ((0.04/std::log10(20))*std::log10(f));
	}

	PLC_FourSectorPowerSupplyCable::Calculate(AYKY4x50_D, AYKY4x50_THETA, tand, eps_r, RHO, m_spectrum_model);
}

///////////////////PLC_AES4x120_Cable///////////////////

TypeId
PLC_AES4x120_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_AES4x120_Cable")
    		.SetParent<PLC_Overheadpowerline> ()
    		.AddConstructor<PLC_AES4x120_Cable> ()
    		;
	return tid;
}

PLC_AES4x120_Cable::PLC_AES4x120_Cable(Ptr<const SpectrumModel> sm)
	: PLC_Overheadpowerline(AES4x120_R, AES4x120_CD, AES4x120_MR, AES4x120_ER, AES4x120_TAND,sm)
{
}

void
PLC_AES4x120_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_Overheadpowerline::Calculate(AES4x120_R, AES4x120_CD, AES4x120_MR, AES4x120_ER, AES4x120_TAND, m_spectrum_model);
}

///////////////////PLC_CYKY_Cable///////////////////

PLC_CYKY_Cable::PLC_CYKY_Cable(Ptr<const SpectrumModel> sm) : PLC_ThreeCoreConcentricCable(CYKY_R0, CYKY_L, CYKY_C, CYKY_G0, CYKY_l, sm)
{
}

TypeId
PLC_CYKY_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_CYKY_Cable")
    		.SetParent<PLC_ThreeCoreConcentricCable> ()
			.AddConstructor<PLC_CYKY_Cable> ()
    		;
	return tid;
}

void
PLC_CYKY_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_ThreeCoreConcentricCable::Calculate(CYKY_R0, CYKY_L, CYKY_C, CYKY_G0, CYKY_l, m_spectrum_model);
}

///////////////////PLC_AlFe4x50_Cable///////////////////

TypeId
PLC_AlFe4x50_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_AlFe4x50_Cable")
    		.SetParent<PLC_Overheadpowerline> ()
    		.AddConstructor<PLC_AlFe4x50_Cable> ()
    		;
	return tid;
}

PLC_AlFe4x50_Cable::PLC_AlFe4x50_Cable(Ptr<const SpectrumModel> sm)
	: PLC_Overheadpowerline(AlFe4x50_R0k, AlFe4x50_G0k, AlFe4x50_r, AlFe4x50_d, AlFe4x50_mir, AlFe4x50_epsr, AlFe4x50_rho, sm)
{
}

void
PLC_AlFe4x50_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_Overheadpowerline::Calculate(AlFe4x50_R0k, AlFe4x50_G0k, AlFe4x50_r, AlFe4x50_d, AlFe4x50_mir, AlFe4x50_epsr, AlFe4x50_rho, m_spectrum_model);


}

///////////////////PLC_AlFe4x35_Cable///////////////////

TypeId
PLC_AlFe4x35_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_AlFe4x35_Cable")
    		.SetParent<PLC_Overheadpowerline> ()
    		.AddConstructor<PLC_AlFe4x35_Cable> ()
    		;
	return tid;
}

PLC_AlFe4x35_Cable::PLC_AlFe4x35_Cable(Ptr<const SpectrumModel> sm)
	: PLC_Overheadpowerline(AlFe4x35_R0k, AlFe4x35_G0k, AlFe4x35_r, AlFe4x35_d, AlFe4x35_mir, AlFe4x35_epsr, AlFe4x35_rho, sm)
{
}

void
PLC_AlFe4x35_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_Overheadpowerline::Calculate(AlFe4x35_R0k, AlFe4x35_G0k, AlFe4x35_r, AlFe4x35_d, AlFe4x35_mir, AlFe4x35_epsr, AlFe4x35_rho, m_spectrum_model);
}

///////////////////PLC_AlFe4x25_Cable///////////////////

TypeId
PLC_AlFe4x25_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_AlFe4x25_Cable")
    		.SetParent<PLC_Overheadpowerline> ()
    		.AddConstructor<PLC_AlFe4x25_Cable> ()
    		;
	return tid;
}

PLC_AlFe4x25_Cable::PLC_AlFe4x25_Cable(Ptr<const SpectrumModel> sm)
	: PLC_Overheadpowerline(AlFe4x25_R0k, AlFe4x25_G0k, AlFe4x25_r, AlFe4x25_d, AlFe4x25_mir, AlFe4x25_epsr, AlFe4x25_rho, sm)
{
}

void
PLC_AlFe4x25_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_Overheadpowerline::Calculate(AlFe4x25_R0k, AlFe4x25_G0k, AlFe4x25_r, AlFe4x25_d, AlFe4x25_mir, AlFe4x25_epsr, AlFe4x25_rho, m_spectrum_model);
}

///////////////////PLC_NAYY4x150_Cable///////////////////

TypeId
PLC_NAYY4x150_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_NAYY4x150_Cable")
    		.SetParent<PLC_FourSectorPowerSupplyCable> ()
    		.AddConstructor<PLC_NAYY4x150_Cable> ()
    		;
	return tid;
}

PLC_NAYY4x150_Cable::PLC_NAYY4x150_Cable(Ptr<const SpectrumModel> sm)
	: PLC_FourSectorPowerSupplyCable(NAYY150SE_R, NAYY150SE_THETA, TAND, EPS_R, RHO, sm)
{
}

void
PLC_NAYY4x150_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);

	PLC_FreqSelectiveRealValue eps_r(m_spectrum_model->GetNumBands(), 0);
	PLC_FreqSelectiveRealValue tand(m_spectrum_model->GetNumBands(), 0);

	size_t i;
	for (i=0; i<m_spectrum_model->GetNumBands(); i++)
	{
		double f = (m_spectrum_model->Begin() + i)->fc;
		eps_r[i] = 7.95 - ((0.9/std::log10(20))*std::log10(f));
		tand[i] = 0.2345 - ((0.04/std::log10(20))*std::log10(f));
	}

	PLC_FourSectorPowerSupplyCable::Calculate(NAYY150SE_R, NAYY150SE_THETA, tand, eps_r, RHO, m_spectrum_model);
}

///////////////////PLC_AYKY3x120_70_Cable///////////////////

TypeId
PLC_AYKY3x120_70_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_NAYY4x150_Cable")
    		.SetParent<PLC_FourSectorPowerSupplyCable> ()
    		.AddConstructor<PLC_NAYY4x150_Cable> ()
    		;
	return tid;
}

PLC_AYKY3x120_70_Cable::PLC_AYKY3x120_70_Cable(Ptr<const SpectrumModel> sm)
	: PLC_FourSectorPowerSupplyCable(AYKY3x120_70_R, AYKY3x120_70_THETA, TAND, EPS_R, RHO, sm)
{
}

void
PLC_AYKY3x120_70_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);

	PLC_FreqSelectiveRealValue eps_r(m_spectrum_model->GetNumBands(), 0);
	PLC_FreqSelectiveRealValue tand(m_spectrum_model->GetNumBands(), 0);

	size_t i;
	for (i=0; i<m_spectrum_model->GetNumBands(); i++)
	{
		double f = (m_spectrum_model->Begin() + i)->fc;
		eps_r[i] = 7.95 - ((0.9/std::log10(20))*std::log10(f));
		tand[i] = 0.2345 - ((0.04/std::log10(20))*std::log10(f));
	}

	PLC_FourSectorPowerSupplyCable::Calculate(AYKY3x120_70_D, AYKY3x120_70_THETA, tand, eps_r, RHO, m_spectrum_model);
}

///////////////////PLC_AES4x50_Cable///////////////////

TypeId
PLC_AES4x50_Cable::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_AES4x50_Cable")
    		.SetParent<PLC_Overheadpowerline> ()
    		.AddConstructor<PLC_AES4x50_Cable> ()
    		;
	return tid;
}

PLC_AES4x50_Cable::PLC_AES4x50_Cable(Ptr<const SpectrumModel> sm)
	: PLC_Overheadpowerline(AES4x50_R, AES4x50_CD, AES4x50_MR, AES4x50_ER, AES4x50_TAND,sm)
{
}

void
PLC_AES4x50_Cable::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_Overheadpowerline::Calculate(AES4x50_R, AES4x50_CD, AES4x50_MR, AES4x50_ER, AES4x50_TAND, m_spectrum_model);
}

///////////////////PLC_AXEKCY240///////////////////
///////////////////_K DP JAKUB PETRŮJ//////////////////////

TypeId
PLC_AXEKCY240::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_AXEKCY240")
    		.SetParent<PLC_MediumVoltageline> ()
    		.AddConstructor<PLC_AXEKCY240> ()
    		;
	return tid;
}

PLC_AXEKCY240::PLC_AXEKCY240(Ptr<const SpectrumModel> sm)
	: PLC_MediumVoltageline(AXEKCY240_L, AXEKCY240_C, sm)
{
}


void //metoda 1, výpočet s pomocí frekvence
PLC_AXEKCY240::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_MediumVoltageline::Calculate(AXEKCY240_L, AXEKCY240_C, m_spectrum_model); //první metoda výpočtu
}


///////////////////PLC_AXEKVCEY240///////////////////
///////////////////_K DP JAKUB PETRŮJ//////////////////////

TypeId
PLC_AXEKVCEY240::GetTypeId (void)
{
	static TypeId tid = ns3::TypeId("PLC_AXEKVCEY240")
    		.SetParent<PLC_MediumVoltageline> ()
    		.AddConstructor<PLC_AXEKVCEY240> ()
    		;
	return tid;
}

PLC_AXEKVCEY240::PLC_AXEKVCEY240(Ptr<const SpectrumModel> sm)
	: PLC_MediumVoltageline(AXEKVCEY240_L, AXEKVCEY240_C, sm)
{
}

void //metoda 1, výpočet s pomocí frekvence
PLC_AXEKVCEY240::Calculate(void)
{
	NS_ASSERT(m_spectrum_model);
	PLC_MediumVoltageline::Calculate(AXEKVCEY240_L, AXEKVCEY240_C, m_spectrum_model); //první metoda výpočtu
}


}






