#######################################################################
#
# $Id: ResultSParameters.py,v 1.2 2008-02-07 05:45:25 lorenz Exp $
# 
# Copyright (C) 2004-2008 Petr Lorenz
# All rights reserved.
# 
# ##### BEGIN LICENSE BLOCK #####
#
# Version: MPL 1.1 / GPL 2.0 / LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
# 
# The Original Code is Petr Lorenz emGine Graphical User Interface (GUI).
# 
# The Initial Developer of the Original Code is Petr Lorenz.
# Portions created by the Initial Developer are Copyright (C) 2004-2008.
# All Rights Reserved.
# 
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the  "GPL"), or the
# GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
# case the provisions of the GPL or the LGPL are applicable instead of those
# above.  If you wish to allow use of your version of this file only under the
# terms of either the GPL or the LGPL and not to allow others to use your
# version of this file under the MPL, indicate your decision by deleting the
# provisions above and replace them with the notice and other provisions
# required by the GPL or LGPL.  If you do not delete the provisions above, a
# recipient may use your version of this file under the terms of any one of the
# MPL License, the GPL or the LGPL.
#
# ##### END LICENSE BLOCK #####
#
#######################################################################
# 
# $Log: ResultSParameters.py,v $
# Revision 1.2  2008-02-07 05:45:25  lorenz
# * Fixed 'Simulation Boundary View' check problem
#   when closing a project.
#
# * Fixed Bounding Box problems when moving/editing a geometry.
#
# Revision 1.1.1.1  2008-01-28 06:15:35  lorenz
# Import emGine GUI v. 0.7.1
#
# Revision 1.4  2007-07-02 06:37:18  lorenz
# Clean up of old code.
#
# Revision 1.3  2007-06-22 04:07:19  lorenz
# Calculation of dt (delta t) from first column of TDSignal.
#
# Small changes in the computation of S-Parameters.
#
# Revision 1.2  2007-05-14 04:53:51  lorenz
# New code for multiport time-domain signals and S-parameters
#
# Revision 1.1.1.1  2007-05-08 06:22:35  lorenz
# Initial Import
#
#######################################################################

# June 2006 - November 2007

from Result import Result

from XYData import XYData
from FFTData import FFTData

import numpy
import math

#from ResultImpedance import ResultImpedance

# TODO: There are more ways how to compute S-Parameters from TD signals.
#       The variable self.type contains the information about how 
#       S-Parameters are obtained. Document that better.
#
# reference_data_ -- reference simulation results (usualy broadband)
#
class ResultSParameters(Result):
  def __init__(self, input_data_, reference_data_ = None, name_ = 'SParameters'):
    Result.__init__(self, name_)
    self.type = "NotSpecified"
    self.sparameters = XYData()
    self.ref_impedance = 50
    self.tdsignal = None
    self.ref_tdsignals = None
    self.number_of_ports = 1
    self.excited_ports = [1]

    self.fmin = 1e8		# default minimum frequency
    self.fmax = 1e9		# default maximum frequency
    self.freq_points = 201	# default number of points
    self.dt = float(1/1e12)	# default time-step

    if isinstance(input_data_, list):
      # if input_data_ is a list then the S-Parameters
      # contain tdsignals for multiple ports
      print "Computing Multiport S-Parameters"
      self.type = "FromTDSignal"
      self.number_of_ports = len(input_data_)
      self.tdsignal = input_data_
      if reference_data_:
	self.ref_tdsignals = reference_data_

    elif isinstance(input_data_, XYData):
      print "SParameters are given as data, good!"
      self.impedance = None
      self.type = "FromTDSignal"
      self.tdsignal = input_data_
    else:
      self.impedance = input_data_
      self.type = "FromImpedance"

  def set_fmin_fmax(self, fmin_, fmax_):
    self.fmin = float(fmin_)
    self.fmax = float(fmax_)

  def set_dt(self, dt_):
    self.dt = dt_

  def set_excited_ports(self, excited_ports_):
    self.excited_ports = excited_ports_

  def update(self):
    if self.type == "FromTDSignal":
      print "computing S-Parameters from TD Signals"

      # first compute the frequency axis
      df = float((self.fmax - self.fmin)/self.freq_points)
      N = round(1/(df*self.dt))
      N_fft = int(2**(math.ceil(math.log(N)/math.log(2))))
      df_new = 1/(N_fft*self.dt)
      Nmin = int(math.floor(self.fmin/df_new)) 
      Nmax = int(math.ceil(self.fmax/df_new))
      self.freq_points = int(Nmax - Nmin + 1)

      #Nmin = 1		# FIXME: This is now hard-coded, no minimum frequency considered
      self.sparameters.set_xvalues( df_new*(numpy.arange(Nmin, Nmax+1)) )

      print "fmin [GHz] =", self.fmin/1e9
      print "fmax [GHz] =", self.fmax/1e9
      print "fmin_new [GHz] =", Nmin*df_new/1e9
      print "fmax_new [GHz] =", Nmax*df_new/1e9
      print "freq_points =", self.freq_points
      print "df [GHz] =", df/1e9
      print "dt [ns] = ", self.dt/1e-9 
      print "df_new [GHz] =", df_new/1e9
      print "N_fft = ", N_fft
      print "Nmin = ", Nmin
      print "Nmax = ", Nmax

      if (self.number_of_ports > 1):
	#
	# s-parameters for multiple ports #
	#
	# FIXME: quick hack to get basic functionality
	if ( len(self.excited_ports) == 1 ):
	  if 1 in self.excited_ports:
	    print "updating S-parameters for two ports but just with 1 port excited"

	    s11 = None
	    s21 = None

	    if self.ref_tdsignals:
	      fftop = FFTData()

	      print ">> using reference data for the computation of S-parameters <<"

	      #e_ref = self.ref_tdsignals[0].get_yarray() + self.ref_tdsignals[1].get_yarray()
	      h_ref = self.ref_tdsignals[0].get_yarray() - self.ref_tdsignals[1].get_yarray()

	      #e_tot1 = self.tdsignal[0].get_yarray() + self.tdsignal[1].get_yarray()
	      h_tot1 = self.tdsignal[0].get_yarray() - self.tdsignal[1].get_yarray()

	      #e_tot2 = self.tdsignal[2].get_yarray() + self.tdsignal[3].get_yarray()
	      h_tot2 = self.tdsignal[2].get_yarray() - self.tdsignal[3].get_yarray()

	      #E_ref = fftop.array_to_array(e_ref, N_fft)
	      H_ref = fftop.array_to_array(h_ref, N_fft)

	      #E_tot1 = fftop.array_to_array(e_tot1, N_fft)
	      H_tot1 = fftop.array_to_array(h_tot1, N_fft)

	      #E_tot2 = fftop.array_to_array(e_tot2, N_fft)
	      H_tot2 = fftop.array_to_array(h_tot2, N_fft)

	      s11 = (H_ref - H_tot1) / H_ref
	      s21 = H_tot2 / H_ref

	    else:
	      # self.sparameters.add_yvalues(self.tdsignal[0].get_yarray())
	      # self.sparameters.add_yvalues(self.tdsignal[1].get_yarray())
	      # self.sparameters.fft_all(N_fft)
	      # s11 = self.sparameters.get_yarray(0)
	      # s21 = self.sparameters.get_yarray(1)
	      None

	    # print s11
	    # print s21
	    # print len(s11)
	    # print len(s21)
	    # print "----------"

	    ## self.sparameters.set_yvalues(s11[Nmin-2:Nmax-1], 0)
	    ## self.sparameters.set_yvalues(s21[Nmin-2:Nmax-1], 1)
	    self.sparameters.set_yvalues(s11[Nmin:Nmax+1])	# elem 0
	    self.sparameters.add_yvalues(s21[Nmin:Nmax+1])	# elem 1
	    self.names = ["s11", "s21"]
      else:
	#
	# just one port s-parameters #
	#
	#self.sparameters.set_yvalues(df*numpy.arange(1, self.freq_points+1))	# just for testing
	self.sparameters.set_yvalues(self.tdsignal.get_yarray())
	self.sparameters.fft(N_fft)
	y_vals = self.sparameters.get_yarray()
	## if Nmin > 1:
	##   Nmin = Nmin - 2
	self.sparameters.set_yvalues(y_vals[Nmin:Nmax+1])
	self.names = ["s11"]
	print "len(y_vals) = ", len(y_vals)
	print "len(self.sparameters.get_yarray()) = ", len(self.sparameters.get_yarray())

    elif self.type == "FromImpedance":
      imp_data = self.impedance.get_data()
      self.sparameters.set_xvalues(imp_data.get_xarray())
      ZL = imp_data.get_yarray()
      Z0 = self.ref_impedance
      self.sparameters.add_yvalues( (ZL - Z0)/(ZL + Z0) )
      self.names = ["s11"]
    
  def get_data(self, name = None):
    return self.sparameters

###############################################
if __name__ == '__main__':
  print "Testing ResultSParameters Module..."
