예제 #1
0
    def nu(self) -> Array[float]:
        nu = np.zeros((self._nbr_channels, self._samples))
        if (self._nbr_channels):
            omega = self.omega
            for i in range(omega.shape[0]):
                nu[i] = Domain.omega_to_nu(omega[i])

        return nu
예제 #2
0
    def __call__(self, domain: Domain) -> Tuple[List[int], List[Field]]:

        output_ports: List[int] = []
        output_fields: List[Field] = []
        field: Field = Field(domain, cst.OPTI, self.field_name)
        # Bit rate initialization --------------------------------------
        rel_pos: List[np.ndarray]
        rel_pos = util.pulse_positions_in_time_window(self.channels,
                                                      self.rep_freq,
                                                      domain.time_window,
                                                      self.position)
        # Check offset -------------------------------------------------
        for i in range(len(self.offset_nu)):
            if (abs(self.offset_nu[i]) > domain.nu_window):
                self.offset_nu[i] = 0.0
                util.warning_terminal(
                    "The offset of channel {} in component "
                    "{} is bigger than half the frequency window, offset will "
                    "be ignored.".format(str(i), self.name))
        # Field initialization -----------------------------------------
        width: float
        for i in range(self.channels):  # Nbr of channels
            if (self.fwhm is None):
                width = self.width[i]
            else:
                width = self.fwhm_to_width(self.fwhm[i])
            res: np.ndarray = np.zeros(domain.time.shape, dtype=cst.NPFT)
            for j in range(len(rel_pos[i])):
                norm_time = domain.get_shift_time(rel_pos[i][j]) / width
                var_time = np.power(norm_time, 2)
                phi = (self.init_phi[i] -
                       Domain.nu_to_omega(self.offset_nu[i]) * domain.time -
                       0.5 * self.chirp[i] * var_time)
                res += (math.sqrt(self.peak_power[i]) / np.cosh(norm_time) *
                        np.exp(1j * phi))
            field.add_channel(res,
                              Domain.lambda_to_omega(self.center_lambda[i]),
                              self.rep_freq[i])
            if (self.noise is not None):
                field.noise = self.noise
        output_fields.append(field)
        output_ports.append(0)

        return output_ports, output_fields
예제 #3
0
    def calc_nl_index(omega, factor, coefficients):
        r"""Calculate the non linear index by help of fitting formula.
        The non linear is assumed to be the sum of the electronic and
        Raman contributions at zero frequency shift. [10]_

        Parameters
        ----------
        omega :
            The angular frequency.  :math:`[rad\cdot ps^{-1}]`
        factor :
            Number which will multiply the fitting formula.
        coefficients :
            Coefficients of the fitting formula. [(coeff, expo), ..]

        Returns
        -------
        :
            Value of the non linear index. :math:`[m^2\cdot W^{-1}]`

        Notes
        -----
        Considering:

        .. math:: n_2(\lambda) = 1.000055 (8.30608 - 27.79971\lambda
                  + 59.66014\lambda^2 - 69.24258\lambda^3
                  + 45.22437\lambda^4 - 15.63666\lambda^5
                  + 2.22585\lambda^6)

        with :math:`\lambda` in :math:`nm` and return with factor
        :math:`10^{-20}`

        References
        ----------
        .. [10] Salceda-Delgado, G., Martinez-Rios, A., Ilan, B. and
               Monzon-Hernandez, D., 2012. Raman response function an
               Raman fraction of phosphosilicate fibers. Optical and
               Quantum Electronics, 44(14), pp.657-671.

        """
        if (isinstance(omega, float)):
            res = 0.0
        else:
            res = np.zeros_like(omega)
        Lambda = Domain.omega_to_lambda(omega)
        Lambda *= 1e-3  # nm -> um
        if (isinstance(omega, float)):
            for elem in coefficients:
                res += elem[0] * Lambda**elem[1]
        else:
            for elem in coefficients:
                res += elem[0] * np.power(Lambda, elem[1])
        res *= factor

        return res * 1e-20  # from fitting formula to m^2 w^-1
예제 #4
0
    def n(self, omega, n_0, N_1):
        r"""Compute the resonant index change.

        Parameters
        ----------
        omega :
            The angular frequency. :math:`[rad\cdot ps^{-1}]`

        Returns
        -------
        :
            The refractive index change.

        Notes
        -----

        .. math:: \Delta n = Q N_1 S

        where:

        .. math:: S = -f_{12}\lambda_{12}g'_{12}(\lambda_s)
                  \big(1 + \frac{g_1}{g_2}\big) - \sum_{j>2} f_{1j}
                  \lambda_{1j}g'_{1j}(\lambda_s)
                  + \sum_{j>2} f_{2j}\lambda_{2j}g'_{2j}(\lambda_s)

        """
        if (isinstance(omega, float)):
            gsa = 0.0
            esa = 0.0
            res = 0.0
        else:
            gsa = np.zeros_like(omega)
            esa = np.zeros_like(omega)
            res = np.zeros_like(omega)

        lambda_s = Domain.omega_to_lambda(omega)
        main_trans = (self._main_trans[0] *
                      self._main_trans[1] * self.lorentzian_lineshape(
                          lambda_s, self._main_trans[1], self._main_trans[2]) *
                      (1 + (self._gs[0] / self._gs[1])))

        # Need to verify for the lambda bw to use here
        # should not change a lot -> very small term
        for uv_gsa in self._gsa[1]:
            gsa += (self._gsa[0] * uv_gsa * self.lorentzian_lineshape(
                lambda_s, uv_gsa, self._main_trans[2]))
        for uv_esa in self._esa[1]:
            esa += (self._esa[0] * uv_esa * self.lorentzian_lineshape(
                lambda_s, uv_esa, self._main_trans[2]))

        res = self.calc_Q(n_0) * N_1 * (esa - gsa - main_trans)

        return res
예제 #5
0
    def calc_ref_index(omega, As, lambdas, dopant_slope=0., dopant_concent=0.):
        r"""Compute the Sellmeier equations.

        Parameters
        ----------
        omega :
            The angular frequency.  :math:`[rad\cdot ps^{-1}]`
        As :
            The A coefficients for the sellmeier equations.
        lambdas :
            The wavelength coefficients for the sellmeier equations.
        dopant_slope :
            The slope coefficient of the dopant linear fitting.
        dopant_concent :
            The concentration of the dopant. [mole%]

        Returns
        -------
        :
            The refractive index.

        Notes
        -----

        .. math:: n^2(\lambda) = 1 + \sum_i A_i
                                 \frac{\lambda^2}{\lambda^2 - \lambda_i}

        If dopant is specified, use linear fitting parameters from
        empirical data at 1300 nm.

        .. math:: n_{new}(\lambda, d) = n(\lambda) + a d

        where :math:`a` is the slope of the linear fitting and :math:`d`
        is the dopant concentration.

        """
        Lambda = Domain.omega_to_lambda(omega)  # nm
        # Lambda in micrometer in formula
        Lambda = Lambda * 1e-3  # um
        if (isinstance(Lambda, float)):
            res = 1.0
            for i in range(len(As)):
                res += (As[i] * Lambda**2) / (Lambda**2 - lambdas[i]**2)
            res = math.sqrt(res)
        else:  # numpy.ndarray
            res = np.ones(Lambda.shape)
            for i in range(len(As)):
                res += (As[i] * Lambda**2) / (Lambda**2 - lambdas[i]**2)
            res = np.sqrt(res)

        res = res + dopant_slope * dopant_concent

        return res
예제 #6
0
def test_same_omega(operator_fixture, op, right_op):
    """Should not fail if the center omega are the same and in the same
    order."""
    length = 12
    field = Field(Domain(samples_per_bit=length), type_op_test)
    center_omegas = [1030., 1025., 1020.]
    rep_freqs = [1., 2., 3.]
    channels = [np.ones(length) * (i + 1) for i in range(len(center_omegas))]
    for i in range(len(center_omegas)):
        field.add_channel(channels[i], center_omegas[i], rep_freqs[i])
    operands = [field]
    res = operator_fixture(op, right_op, channels, type_op_test, center_omegas,
                           rep_freqs, length, *operands)
예제 #7
0
    def fct(op, right_op, field_channel, type, center_omega, rep_freq, samples,
            *operands):
        res = []
        for operand in operands:
            new_field = Field(Domain(samples_per_bit=samples), type)
            for i, channel in enumerate(field_channel):
                new_field.add_channel(channel, center_omega[i], rep_freq[i])
            if (right_op):  # Right operand operator
                res.append(op(operand, new_field))
            else:  # Left operand operator
                res.append(op(new_field, operand))

        return res
예제 #8
0
    def layout(starter, ATT, DISP, SPM, SS, RS, approx):
        domain = Domain()
        lt = Layout(domain)
        dtime = domain.dtime
        domega = domain.domega
        out_temporal_power = []
        out_spectral_power = []
        out_temporal_fwhm = []
        out_spectral_fwhm = []
        nlse_method = "ssfm_symmetric"
        flag = True
        till_nbr = 4 if approx else 5
        for i in range(1, till_nbr):
            if (i == 4):
                flag = False
            fiber = Fiber(length=1.0,
                          nlse_method=nlse_method,
                          alpha=[0.046],
                          nl_approx=flag,
                          ATT=ATT,
                          DISP=DISP,
                          SPM=SPM,
                          SS=SS,
                          RS=RS,
                          steps=1000,
                          save=True,
                          approx_type=i)
            lt.add_link(starter[0], fiber[0])
            lt.run(starter)
            lt.reset()
            out_temporal_power.append(temporal_power(fiber[1][0].channels))
            out_spectral_power.append(spectral_power(fiber[1][0].channels))
            out_temporal_fwhm.append(fwhm(out_temporal_power[-1], dtime))
            out_spectral_fwhm.append(fwhm(out_spectral_power[-1], domega))
        in_temporal_power = temporal_power(starter[0][0].channels)
        in_spectral_power = spectral_power(starter[0][0].channels)
        in_temporal_fwhm = fwhm(in_temporal_power, dtime)
        in_spectral_fwhm = fwhm(in_spectral_power, domega)

        return (in_temporal_power, in_spectral_power, in_temporal_fwhm,
                in_spectral_fwhm, out_temporal_power, out_spectral_power,
                out_temporal_fwhm, out_spectral_fwhm)
예제 #9
0
def test_no_common_omegas(operator_fixture, op, right_op):
    """Should not perform math operators if the center omegas are
    different."""
    length = 12
    field = Field(Domain(samples_per_bit=length), type_op_test)
    center_omegas = [1030., 1025., 1020.]
    rep_freqs = [1., 2., 3.]
    channels = [np.ones(length) * (i + 1) for i in range(len(center_omegas))]
    for i in range(len(center_omegas)):
        field.add_channel(channels[i], center_omegas[i], rep_freqs[i])
    operands = [field]
    center_omegas = [1029., 1021.]
    channels = [np.ones(length) * (i + 1) for i in range(len(center_omegas))]
    rep_freqs = [2., 3.]
    res = operator_fixture(op, right_op, channels, type_op_test, center_omegas,
                           rep_freqs, length, *operands)
    field_res = res[0]
    if (len(field_res) == len(field)):
        assert np.array_equal(field_res[:], field[:])
    else:
        assert np.array_equal(field_res[:], np.asarray(channels))
예제 #10
0
    def layout(nbr_channels_seed, peak_powers_seed, center_lambdas_seed,
               nbr_channels_pump, peak_powers_pump, center_lambdas_pump,
               REFL_SEED, REFL_PUMP, NOISE):
        gssn = Gaussian(channels=nbr_channels_seed,
                        peak_power=peak_powers_seed,
                        center_lambda=center_lambdas_seed)
        pump = CW(channels=nbr_channels_pump,
                  peak_power=peak_powers_pump,
                  center_lambda=center_lambdas_pump)
        fiber = FiberYb(length=0.01,
                        steps=10,
                        REFL_SEED=REFL_SEED,
                        REFL_PUMP=REFL_PUMP,
                        BISEED=False,
                        BIPUMP=False,
                        save_all=True,
                        alpha=[0.05],
                        max_nbr_iter=2,
                        NOISE=NOISE)
        lt = Layout(Domain(samples_per_bit=64, noise_samples=10))
        lt.add_unidir_links((gssn[0], fiber[0]), (pump[0], fiber[2]))
        lt.run_all()

        return fiber.storages[0]
예제 #11
0
    def calc_cross_section(omega, dopant="Yb", predict=None):
        r"""Calculate the absorption cross section. Calculate with the
        fitting formula from ref. [4]_ .

        Parameters
        ----------
        omega :
            The angular frequency.  :math:`[rad\cdot ps^{-1}]`
        dopant :
            The doping agent.
        predict :
            A callable object to predict the cross sections.
            The variable must be the wavelength. :math:`[nm]`

        Returns
        -------
        float or numpy.ndarray of float
            Value of the absorption cross section. :math:`[nm^2]`

        Notes
        -----
        Considering:

        .. math:: f(\lambda, \lambda_c, \lambda_w, n)
                  = \exp\Big[-\Big\lvert
                  \frac{\lambda-\lambda_c}{\lambda_w}\Big\rvert^n \Big]

        With :math:`\lambda`, :math:`\lambda_c` and :math:`\lambda_w`
        in :math:`[nm]`

        For Ytterbium:

        .. math:: \sigma_a^{Yb}(\lambda) = 0.09f(\lambda,913,8,2)
                  + 0.13 f(\lambda,950,40,4)
                  + 0.2 f(\lambda, 968, 40, 2.4)
                  + 1.08 f(\lambda, 975.8,3,1.5)

        For Erbium:

        .. math:: \begin{split}
                    \sigma_a^{Er}(\lambda) &= 0.221
                    f(\lambda, 1493, 16.5, 2.2)
                    + 0.342 f(\lambda, 1534, 4.5, 1.4)\\
                    &\quad + 0.158f(\lambda, 1534, 30,4)
                    + 0.037 f(\lambda, 1534, 85, 4)
                    + 0.132 f(\lambda, 1541, 8,0.8)
                  \end{split}

        References
        ----------
        .. [4] Valley, G.C., 2001. Modeling cladding-pumped Er/Yb fiber
               amplifiers. Optical Fiber Technology, 7(1), pp.21-44.

        """
        Lambda = Domain.omega_to_lambda(omega)
        if (predict is None):
            dopant = dopant.lower()
            if (dopant in dopants):
                if (isinstance(Lambda, float)):
                    res = 0.0
                    if (Lambda < dopant_range[dopant][1]
                            and Lambda > dopant_range[dopant][0]):
                        res = Absorption._formula(Lambda,
                                                  dopant_fit_coeff[dopant])
                else:
                    Lambda_down = Lambda[Lambda < dopant_range[dopant][0]]
                    Lambda_up = Lambda[Lambda > dopant_range[dopant][1]]
                    if (len(Lambda_up)):
                        Lambda_in = Lambda[len(Lambda_down):-len(Lambda_up)]
                    else:
                        Lambda_in = Lambda[len(Lambda_down):]
                    res = np.array([])
                    if (Lambda_in.size):
                        res = Absorption._formula(Lambda_in,
                                                  dopant_fit_coeff[dopant])
                    res = np.hstack((np.zeros_like(Lambda_down), res,
                                     np.zeros_like(Lambda_up)))
                res *= 1e-6  # 10^-20 cm^2 -> nm^2
            else:
                util.warning_terminal("The specified doped material is not "
                                      "supported, return 0")
        else:  # Interpolate the data in csv file with scipy fct
            res = predict(Lambda)[0]  # Take only zeroth deriv.

        return res
예제 #12
0
    nlse2 = NLSE(alpha=[0.0], beta=[0.0, 0.0])
    nlse3 = NLSE(alpha=[0.0], beta=[0.0, 0.0])
    nlse4 = NLSE(alpha=[0.0], beta=[0.0, 0.0])
    nlse5 = NLSE(alpha=[0.0], beta=[0.0, 0.0])

    eqs = [nlse1, nlse2, nlse3, nlse4, nlse5]
    method = [
        'ssfm', 'ssfm_super_sym', 'ssfm_symmetric', 'ssfm_reduced', 'ssfm'
    ]
    length = 1.0
    steps = [10, 9, 8, 7, 6, 5]
    step_method = [FIXED, ADAPTATIVE, FIXED]
    solver_sequence = [0, 0, 2, 2, 1]
    solver_order = ALTERNATING
    stepper_method = [FORWARD]

    stepper = Stepper(eqs=eqs,
                      method=method,
                      length=length,
                      steps=steps,
                      step_method=step_method,
                      solver_sequence=solver_sequence,
                      solver_order=solver_order,
                      stepper_method=stepper_method)

    dummy_domain = Domain()
    ggsn = Gaussian(channels=4)
    dummy_ports, dummy_field = ggsn(dummy_domain)

    res = stepper(dummy_domain, dummy_field)
예제 #13
0
    from optcom.domain import Domain
    from optcom.utils.utilities_user import CSVFit

    folder = './data/fiber_amp/cross_section/absorption/'
    files = ['yb']
    file_range = [(900.0, 1050.0)]

    x_data = []
    y_data = []
    plot_titles = []

    for dopant in dopants:
        nbr_samples = 1000
        lambdas = np.linspace(dopant_range[dopant][0], dopant_range[dopant][1],
                              nbr_samples)
        omegas = Domain.omega_to_lambda(lambdas)
        absorp = Absorption(dopant=dopant)
        sigmas = absorp.get_cross_section(omegas)
        x_data.append(lambdas)
        y_data.append(sigmas)
        dopant_name = dopant[0].upper() + dopant[1:]
        plot_titles.append(
            'Cross sections {} from formula'.format(dopant_name))

    for i, file in enumerate(files):
        nbr_samples = 1000
        lambdas = np.linspace(file_range[i][0], file_range[i][1], nbr_samples)
        omegas = Domain.omega_to_lambda(lambdas)
        file_name = folder + file + '.txt'
        predict = CSVFit(file_name=file_name, conv_factor=[1e9, 1e18])  # in nm
        absorp = Absorption(predict=predict)
예제 #14
0
            res = math.sqrt(res)
        else:   # numpy.ndarray
            res = np.ones(Lambda.shape)
            for i in range(len(self._Bs)):
                res += (self._Bs[i]*Lambda**2) / (Lambda**2 - self._Cs[i])
            res = np.sqrt(res)

        return res


if __name__ == "__main__":

    import optcom.utils.plot as plot
    from optcom.domain import Domain

    sellmeier = Sellmeier("sio2")

    center_omega = Domain.lambda_to_omega(1050.0)
    print(sellmeier.n(center_omega))

    Lambda = np.linspace(120, 2120, 2000)
    omega = Domain.lambda_to_omega(Lambda)
    n = sellmeier.n(omega)

    x_labels = ['Lambda']
    y_labels = ['Refractive index']
    plot_titles = ["Refractive index of Silica from Sellmeier equations"]

    plot.plot2d(Lambda, n, x_labels=x_labels, y_labels=y_labels,
                plot_titles=plot_titles, opacity=0.0)
예제 #15
0
        return Dispersion.calc_dispersion(beta_2, Lambda) * length


if __name__ == "__main__":

    import optcom.utils.plot as plot
    from optcom.domain import Domain
    from optcom.equations.sellmeier import Sellmeier

    center_omega = 1929.97086814  #Domain.lambda_to_omega(976.0)
    sellmeier = Sellmeier("Sio2")
    betas = Dispersion.calc_beta_coeffs(center_omega, 13, sellmeier)
    print('betas: ', betas)

    Lambda = np.linspace(900, 1600, 1000)
    omega = Domain.lambda_to_omega(Lambda)
    beta_2 = Dispersion.calc_beta_deriv(omega, 2, "SiO2")
    x_data = [Lambda]
    y_data = [beta_2]

    x_labels = ['Lambda']
    y_labels = ['beta2']
    plot_titles = ["Group velocity dispersion coefficients in Silica"]

    disp = Dispersion.calc_dispersion(Lambda, beta_2)
    x_data.append(Lambda)
    y_data.append(disp)
    x_labels.append('Lambda')
    y_labels.append('dispersion')
    plot_titles.append('Dispersion of Silica')
예제 #16
0
    def calc_kappa(omega, v_nbr, a, d, ref_index):
        r"""Calculate the coupling coefficient for the parameters given
        for two waveguides. (assuming the two waveguides are
        symmetric) [3]_

        Parameters
        ----------
        omega :
            The angular frequency.  :math:`[rad\cdot ps^{-1}]`
        v_nbr :
            The fiber parameter.
        a :
            The core radius. :math:`[\mu m]`
        d :
            The center to center spacing between the two cores.
            :math:`[\mu m]`
        ref_index :
            The refractive index outside of the two fiber cores.

        Returns
        -------
        :
            Value of the coupling coefficient. :math:`[km^{-1}]`

        Notes
        -----

        .. math:: \kappa = \frac{\pi V}{2 k_0 n_0 a^2}
                            e^{-(c_0 + c_1 d + c_2 d^2)}

        This equation is accurate to within 1% for values of the fiber
        parameter :math:`1.5\leq V\leq 2.5` and of the normalized
        center-to-center spacing :math:`\bar{d} = d/a`,
        :math:`2\leq \bar{d}\leq 4.5` .

        References
        ----------
        .. [3] Govind Agrawal, Chapter 2: Fibers Couplers,
           Applications of Nonlinear Fiber Optics (Second Edition),
           Academic Press, 2008, Page 59.

        """
        lambda_0 = Domain.omega_to_lambda(omega)
        a *= 1e-9  # um -> km
        d *= 1e-9  # um -> km
        lambda_0 *= 1e-12  # nm -> km
        norm_d = d / a
        k_0 = 2 * cst.PI / lambda_0
        c_0 = 5.2789 - 3.663 * v_nbr + 0.3841 * v_nbr**2
        c_1 = -0.7769 + 1.2252 * v_nbr - 0.0152 * v_nbr**2
        c_2 = -0.0175 - 0.0064 * v_nbr - 0.0009 * v_nbr**2
        # Check validity of formula paramater --------------------------
        if (np.mean(v_nbr) < 1.5 or np.mean(v_nbr) > 2.5):
            util.warning_terminal(
                "Value of the fiber parameter is V = {}, "
                "kappa fitting formula is valid only for : 1.5 <= V <= 2.5, "
                "might lead to unrealistic results.".format(np.mean(v_nbr)))
        if (norm_d < 2.0 or norm_d > 4.5):
            util.warning_terminal(
                "Value of the normalized spacing is d = {}, "
                "kappa fitting formula is valid only for : 2.0 <= d <= 4.5, "
                "might lead to unrealistic results.".format(norm_d))
        # Formula ------------------------------------------------------
        if (isinstance(omega, float)):
            res = (cst.PI * v_nbr / (2 * k_0 * ref_index * a**2) *
                   math.exp(-(c_0 + c_1 * norm_d + c_2 * norm_d**2)))
        else:
            res = (cst.PI * v_nbr / (2 * k_0 * ref_index * a**2) *
                   np.exp(-(c_0 + c_1 * norm_d + c_2 * norm_d**2)))

        return res
예제 #17
0
        return res

    return fct


# ----------------------------------------------------------------------
# Tests ----------------------------------------------------------------
# ----------------------------------------------------------------------

scale = 2
length = 12
type_op_test = 1
center_omega_op_test = [1550.]
rep_freq_op_test = [1e3]
field_ = Field(Domain(samples_per_bit=length), type_op_test)
field_.add_channel(scale * np.ones(length), center_omega_op_test[0],
                   rep_freq_op_test[0])
operand_args = [
    int(scale),
    float(scale),
    complex(scale), scale * np.ones(length), field_
]


@pytest.mark.field_op
@pytest.mark.parametrize("op, field_channel, op_res, operands", [
    (operator.__iadd__, [np.arange(1, length + 1)],
     np.array([np.arange(1, length + 1) +
               (scale * np.ones(length))]), operand_args),
    (operator.__isub__, [np.arange(1, length + 1)],
예제 #18
0
    def calc_sigma(omega, coefficients, lambda_range=None):
        r"""Calculate the absorption cross section. Calculate with the
        fitting formula from ref. [1]_ .

        Parameters
        ----------
        omega :
            The angular frequency.  :math:`[rad\cdot ps^{-1}]`
        coefficients :
            The coefficients for the fitting formula.
            :math:`[\text{factor}, l_c, l_w, n]`
        lambda_range :
            The range of wavelength in which the fitting formula is
            valid. (lower_bound, upper_bound)

        Returns
        -------
        float or numpy.ndarray of float
            Value of the absorption cross section. :math:`[nm^2]`

        Notes
        -----
        Considering:

        .. math:: f(\lambda, \lambda_c, \lambda_w, n)
                  = \exp\Big[-\Big\lvert
                  \frac{\lambda-\lambda_c}{\lambda_w}\Big\rvert^n \Big]

        With :math:`\lambda`, :math:`\lambda_c` and :math:`\lambda_w`
        in :math:`[nm]`

        For Ytterbium:

        .. math:: \sigma^{Yb}(\lambda) = 0.09f(\lambda,913,8,2)
                  + 0.13 f(\lambda,950,40,4)
                  + 0.2 f(\lambda, 968, 40, 2.4)
                  + 1.08 f(\lambda, 975.8,3,1.5)

        For Erbium:

        .. math:: \begin{split}
                    \sigma^{Er}(\lambda) &= 0.221
                    f(\lambda, 1493, 16.5, 2.2)
                    + 0.342 f(\lambda, 1534, 4.5, 1.4)\\
                    &\quad + 0.158f(\lambda, 1534, 30,4)
                    + 0.037 f(\lambda, 1534, 85, 4)
                    + 0.132 f(\lambda, 1541, 8,0.8)
                  \end{split}

        References
        ----------
        .. [1] Valley, G.C., 2001. Modeling cladding-pumped Er/Yb fiber
               amplifiers. Optical Fiber Technology, 7(1), pp.21-44.

        """
        Lambda = Domain.omega_to_lambda(omega)
        res = 0.0 if isinstance(Lambda, float) else np.zeros_like(Lambda)
        if (isinstance(Lambda, float)):
            if (lambda_range is None):
                res = AbsorptionSection._formula(Lambda, coefficients)
            else:
                if (Lambda < lambda_range[1] and Lambda > lambda_range[0]):
                    res = AbsorptionSection._formula(Lambda, coefficients)
        else:
            if (lambda_range is not None):
                Lambda_down = Lambda[Lambda < lambda_range[0]]
                Lambda_up = Lambda[Lambda > lambda_range[1]]
                if (len(Lambda_up)):
                    Lambda_in = Lambda[len(Lambda_down):-len(Lambda_up)]
                else:
                    Lambda_in = Lambda[len(Lambda_down):]
                res = np.array([])
                if (Lambda_in.size):
                    res = AbsorptionSection._formula(Lambda_in, coefficients)
                res = np.hstack((np.zeros_like(Lambda_down), res,
                                 np.zeros_like(Lambda_up)))
            else:
                res = AbsorptionSection._formula(Lambda, coefficients)
        res *= 1e-6  # 10^-20 cm^2 -> nm^2

        return res
예제 #19
0
파일: cw.py 프로젝트: gitter-badger/optcom
        output_fields.append(field)
        output_ports.append(0)

        return output_ports, output_fields


if __name__ == "__main__":

    import optcom.utils.plot as plot
    import optcom.layout as layout
    import optcom.domain as domain
    from optcom.utils.utilities_user import temporal_power, spectral_power,\
                                            phase

    lt = layout.Layout(Domain(samples_per_bit=4096))

    channels = 3
    center_lambda = [1552.0, 1549.0, 1596.0]
    peak_power = [1e-3, 2e-3, 6e-3]
    offset_nu = [0.0, 1.56, -1.6]
    init_phi = [1.0, 1.0, 0.0]

    cw = CW(channels=channels,
            center_lambda=center_lambda,
            peak_power=peak_power,
            offset_nu=offset_nu,
            init_phi=init_phi,
            save=True)

    lt.run(cw)
예제 #20
0
    import optcom.utils.constants as cst
    import optcom.utils.plot as plot
    from optcom.domain import Domain
    from optcom.utils.fft import FFT

    samples = 1000
    time, dtime = np.linspace(0.0, 0.3, samples, False, True)  # ps
    freq_window = 1.0 / dtime

    x_data = []
    y_data = []
    plot_labels = []

    f_R: float = cst.F_R
    n_0: float = 1.40
    center_omega = Domain.lambda_to_omega(1550.0)

    f_a: float = cst.F_A
    f_b: float = cst.F_B
    f_c: float = cst.F_C
    x_data.append(time)
    h_R = Raman.calc_h_R(time, f_a=f_a, f_b=f_b, f_c=f_c)
    y_data.append(h_R)
    plot_labels.append('Isotropic and anisotropic part')
    f_a = 1.0
    f_b = 0.0
    f_c = 1.0
    x_data.append(time)
    h_R = Raman.calc_h_R(time, f_a=f_a, f_b=f_b, f_c=f_c)
    y_data.append(h_R)
    plot_labels.append('W/o anisotropic part')
예제 #21
0
        def __call__(self, domain):

            return ([4], [Field(Domain(), 1)])
예제 #22
0
    # dopant_range = {dopant:(bottom, up), \ldots} # in nm
    dopant_range = {"yb": (900, 1050), "er": (1400, 1650)}

    folder = './data/fiber_amp/cross_section/emission/'
    files = ['yb']
    file_range = [(900.0, 1050.0)]

    x_data = []
    y_data = []
    plot_titles = []

    for dopant in dopants:
        nbr_samples = 1000
        lambdas = np.linspace(dopant_range[dopant][0], dopant_range[dopant][1],
                              nbr_samples)
        omegas = Domain.lambda_to_omega(lambdas)
        center_lambda = (dopant_range[dopant][0] + dopant_range[dopant][1]) / 2
        center_omega = Domain.lambda_to_omega(center_lambda)
        N_0 = 0.01  # nm^-3
        N_1 = 0.01 * 1.5  # nm^-3
        T = 293.5
        stimu = StimulatedEmission(dopant=dopant)
        sigmas = stimu.get_cross_section(omegas, center_omega, N_0, N_1, T)
        x_data.append(lambdas)
        y_data.append(sigmas)
        dopant_name = dopant[0].upper() + dopant[1:]
        plot_titles.append("Cross sections {} from formula and McCumber "
                           "relations".format(dopant_name))

    for i, file in enumerate(files):
        nbr_samples = 1000
예제 #23
0
    def calc_cross_section(omega,
                           dopant="Yb",
                           predict=None,
                           center_omega=None,
                           N_0=None,
                           N_1=None,
                           T=None):
        r"""Calculate the emission cross section. There is no analytical
        formula for the emission cross section. Calculate first the
        absorption cross sections with the fitting formula from ref.
        [5]_ and then use the McCumber relations to deduce the emission
        cross sections.

        Parameters
        ----------
        omega :
            The angular frequency.  :math:`[rad\cdot ps^{-1}]`
        dopant :
            The type of the doped medium.
        predict :
            A callable object to predict the cross sections.
            The variable must be the wavelength. :math:`[nm]`
        center_omega :
            The center angular frequency.  :math:`[rad\cdot ps^{-1}]`
        N_0 :
            The population in ground state. :math:`[nm^{-3}]`
        N_1 :
            The population in the excited state. :math:`[nm^{-3}]`
        T :
            The temperature. :math:`[K]`

        Returns
        -------
        :
            Value of the emission cross section. :math:`[nm^2]`

        References
        ----------
        .. [5] Valley, G.C., 2001. Modeling cladding-pumped Er/Yb fiber
               amplifiers. Optical Fiber Technology, 7(1), pp.21-44.

        """

        if (isinstance(omega, float)):
            res = 0.0
        else:
            res = np.zeros_like(omega)
        Lambda = Domain.omega_to_lambda(omega)
        if (predict is None):
            if (N_0 is not None and N_1 is not None and T is not None
                    and center_omega is not None):
                sigma_a = Absorption.calc_cross_section(omega, dopant)
                res = McCumber.calc_cross_section_emission(
                    sigma_a, omega, center_omega, N_0, N_1, T)
            else:
                util.warning_terminal(
                    "Not enough information to calculate "
                    "the value of the emission cross sections, will return "
                    "null values.")

        else:  # Interpolate the data from csv file with scipy fct
            res = predict(Lambda)[0]  # Take only zeroth deriv.

        return res
예제 #24
0
def test_interplay_dispersion_and_spm():
    """Should fail if (i) fwhm of temporal output powers for small
    N square number is greater than fwhm of initial pulse or (ii)
    fwhm of temporal output powers for big N square number is
    greater than initial fwhm in case of positive GVD and smaller
    than initial fwhm in case of negative GVD.

    Notes
    -----
    Test case::

    gssn ___ fiber

    """
    # Environment creation
    domain = Domain()
    lt = Layout(domain)
    dtime = domain.dtime
    fwhms_pos_gvd = []
    fwhms_neg_gvd = []
    time_pos_gvd = []
    time_neg_gvd = []
    nlse_method = "ssfm_symmetric"
    # Make sure to have a positive GVD to pass the test
    gssn = Gaussian(channels=1, peak_power=[1.0], center_lambda=[1030.])
    flag = True
    for i in range(1, 5):
        if (i == 4):
            flag = False
        fiber = Fiber(length=1.0,
                      nlse_method=nlse_method,
                      alpha=[0.46],
                      gamma=2.0,
                      nl_approx=flag,
                      ATT=False,
                      DISP=True,
                      SPM=True,
                      SS=False,
                      RS=False,
                      steps=1000,
                      save=True,
                      approx_type=i,
                      beta=[1e5, 1e3, 20.0])
        lt.add_link(gssn[0], fiber[0])
        lt.run(gssn)
        lt.reset()
        time_pos_gvd.append(fiber[1][0].time)
        fwhms_pos_gvd.append(fwhm(temporal_power(fiber[1][0].channels), dtime))
    flag = True
    for i in range(1, 5):
        if (i == 4):
            flag = False
        fiber = Fiber(length=1.0,
                      nlse_method=nlse_method,
                      alpha=[0.46],
                      gamma=2.0,
                      nl_approx=flag,
                      ATT=False,
                      DISP=True,
                      SPM=True,
                      SS=False,
                      RS=False,
                      steps=1000,
                      save=True,
                      approx_type=i,
                      beta=[1e5, 1e3, -20.0])
        lt.add_link(gssn[0], fiber[0])
        lt.run(gssn)
        lt.reset()
        time_neg_gvd.append(fiber[1][0].time)
        fwhms_neg_gvd.append(fwhm(temporal_power(fiber[1][0].channels), dtime))
    fwhm_temporal_gssn = fwhm(temporal_power(gssn[0][0].channels), dtime)
    time_gssn = gssn[0][0].time
    # Testing
    for i in range(len(fwhms_neg_gvd)):
        assert_array_less(time_gssn, time_pos_gvd[i])
        assert_array_less(time_gssn, time_neg_gvd[i])
        assert fwhm_temporal_gssn[0] < fwhms_pos_gvd[i][0]
        assert fwhms_neg_gvd[i][0] < fwhm_temporal_gssn[0]
예제 #25
0
        return 1.0 / (power * nl_coeff)


if __name__ == "__main__":

    import numpy as np

    import optcom.utils.plot as plot
    from optcom.domain import Domain
    from optcom.parameters.fiber.effective_area import EffectiveArea
    from optcom.parameters.fiber.nl_index import NLIndex

    medium = "SiO2"
    # With float
    omega = Domain.lambda_to_omega(1552.0)
    core_radius = 5.0
    n_core = 1.43
    n_clad = 1.425

    eff_area = EffectiveArea.calc_effective_area(omega,
                                                 core_radius=core_radius,
                                                 n_core=n_core,
                                                 n_clad=n_clad)
    nl_index = NLIndex.calc_nl_index(omega, medium=medium)
    print(
        NLCoefficient.calc_nl_coefficient(omega,
                                          nl_index=nl_index,
                                          eff_area=eff_area))

    # With numpy ndarray
예제 #26
0

if __name__ == "__main__":
    """Give an example of GaussianFilter usage.
    This piece of code is standalone, i.e. can be used in a separate
    file as an example.
    """

    from typing import Callable, List, Optional

    import numpy as np

    import optcom as oc

    # Plot transfer function
    domain = Domain(samples_per_bit=2**12)
    center_lambda = 1030.
    center_nu = oc.lambda_to_nu(center_lambda)
    nu = domain.nu + center_nu
    lambda_bw = 2.
    nu_bw = oc.lambda_bw_to_nu_bw(lambda_bw, center_lambda)
    tf = oc.GaussianFilter.transfer_function(nu, center_nu, nu_bw, 0.0)  #1.5)
    lambdas = oc.nu_to_lambda(nu)
    oc.plot2d(lambdas,
              tf,
              x_labels=['nu'],
              y_labels=['Amplitude (a.u.)'],
              plot_titles=[
                  "Transfer function centered at "
                  "{} nm with bandwidth {} nm".format(round(center_lambda, 2),
                                                      round(lambda_bw))
예제 #27
0
    Lambda: float = 1030.0
    pulse: Gaussian = Gaussian(channels=1,
                               peak_power=[1.0, 1.0],
                               center_lambda=[Lambda])

    steps: int = int(1e1)
    beta_01: float = 1e5
    beta_02: float = 1e5
    beta: List[Union[List[float], Callable, None]] =\
        [[beta_01,10.0,-0.0],[beta_02,10.0,-0.0]]
    v_nbr_value = 2.0
    v_nbr: List[Union[float, Callable, None]] = [v_nbr_value]
    core_radius: List[float] = [5.0]
    c2c_spacing: List[List[float]] = [[15.0]]
    n_clad: float = 1.02
    omega: float = Domain.lambda_to_omega(Lambda)
    kappa_: Union[float, Callable]
    kappa_ = CouplingCoeff.calc_kappa(omega, v_nbr_value, core_radius[0],
                                      c2c_spacing[0][0], n_clad)
    kappa: List[List[Union[List[float], Callable, None]]] = [[None]]
    delta_a: float = 0.5 * (beta_01 - beta_02)
    length_c: float = cst.PI / (2 * math.sqrt(delta_a**2 + kappa_**2))
    length: float = length_c / 2

    for j, method in enumerate(ode_methods):
        coupler = FiberCoupler(length=length,
                               kappa=kappa,
                               v_nbr=v_nbr,
                               core_radius=core_radius,
                               n_clad=n_clad,
                               c2c_spacing=c2c_spacing,
예제 #28
0
            field.append(res, Domain.lambda_to_omega(self.center_lambda[i]))

        output_fields.append(field)
        output_ports.append(0)

        return output_ports, output_fields


if __name__ == "__main__":

    import optcom.utils.plot as plot
    import optcom.layout as layout
    import optcom.domain as domain
    from optcom.utils.utilities_user import temporal_power, spectral_power

    lt = layout.Layout(Domain(samples_per_bit=4096))

    channels = 3
    center_lambda = [1552.0, 1549.0, 1596.0]
    position = [0.3, 0.5]
    width = [5.3, 6]
    peak_power = [1e-3, 2e-3, 6e-3]
    bit_rate = [0.03, 0.04]
    offset_nu = [1.56, -1.6]
    chirp = [0.5, 0.1]
    init_phi = [1.0, 0.0]

    sech = Sech(channels=channels,
                center_lambda=center_lambda,
                position=position,
                width=width,
예제 #29
0
    def calc_nl_index(omega, medium):
        r"""Calculate the non linear index by help of fitting formula.
        The non linear is assumed to be the sum of the electronic and
        Raman contributions at zero frequency shift. [5]_

        Parameters
        ----------
        omega :
            The angular frequency.  :math:`[rad\cdot ps^{-1}]`
        medium :
            The medium in which to consider the non linear index.

        Returns
        -------
        :
            Value of the non linear index. :math:`[m^2\cdot W^{-1}]`

        Notes
        -----
        Considering:

        .. math:: n_2(\lambda) = 1.000055 (8.30608 - 27.79971\lambda
                  + 59.66014\lambda^2 - 69.24258\lambda^3
                  + 45.22437\lambda^4 - 15.63666\lambda^5
                  + 2.22585\lambda^6)

        with :math:`\lambda` in :math:`nm` and return with factor
        :math:`10^{-20}`

        References
        ----------
        .. [5] Salceda-Delgado, G., Martinez-Rios, A., Ilan, B. and
               Monzon-Hernandez, D., 2012. Raman response function an
               Raman fraction of phosphosilicate fibers. Optical and
               Quantum Electronics, 44(14), pp.657-671.

        """
        medium = medium.lower()
        if (isinstance(omega, float)):
            res = 0.0
        else:
            res = np.zeros_like(omega)
        Lambda = Domain.omega_to_lambda(omega)
        Lambda *= 1e-3  # nm -> um
        coeff = POLY_COEFF.get(medium)
        if (coeff is not None):
            if (isinstance(omega, float)):
                for elem in coeff:
                    res += elem[0] * Lambda**elem[1]
            else:
                for elem in coeff:
                    res += elem[0] * np.power(Lambda, elem[1])
            factor = POLY_FACTOR.get(medium)
            if (factor is not None):
                res *= factor
        else:
            util.warning_terminal(
                "The medium provided to calculate the "
                "non linear index is not recognised. Return null values.")

        return res * 1e-20  # from fitting formula to m^2 w^-1
예제 #30
0
    def calc_res_index(omega, n_0, N, main_trans, gs, esa, gsa):
        r"""Compute the resonant index change.

        Parameters
        ----------
        omega :
            The angular frequency. :math:`[rad\cdot ps^{-1}]`
        n_0 :
            The raw refratvie index of the medium.
        N :
            The population of the metastable level. :math:`[nm^{-3}]`
        main_trans :
            The main transition parameters. :math:`[nm]`
            [:math:`f_{12}`, :math:`\lambda_{12}`, FWHM]
        gs :
            The degeneracy factor of the metastable and ground state.
            (:math:`g_{ground}, g_{metastable}`)
        esa :
            The transition strength of the metastable state and the
            relevant UV levels. :math:`[nm]`
            (:math:`f_{esa}`, [:math:`UV_{esa,1}`, ...])
        gsa :
            The transition strength of the ground state and the
            relevant UV levels. :math:`[nm]`
            (:math:`f_{gsa}`, [:math:`UV_{gsa,1}`, ...])


        Returns
        -------
        :
            The refractive index change.

        Notes
        -----

        .. math:: \Delta n = Q N S

        where:

        .. math:: S = -f_{12}\lambda_{12}g'_{12}(\lambda_s)
                  \big(1 + \frac{g_1}{g_2}\big) - \sum_{j>2} f_{1j}
                  \lambda_{1j}g'_{1j}(\lambda_s)
                  + \sum_{j>2} f_{2j}\lambda_{2j}g'_{2j}(\lambda_s)

        """
        if (isinstance(omega, float)):
            gsa_ = 0.0
            esa_ = 0.0
        else:
            gsa_ = np.zeros_like(omega)
            esa_ = np.zeros_like(omega)

        lambda_s = Domain.omega_to_lambda(omega)
        ln = ResonantIndex.lorentzian_lineshape(lambda_s, main_trans[1],
                                                main_trans[2])
        main_trans_ = main_trans[0] * main_trans[1] * ln * (1 + (gs[0]/gs[1]))

        # Need to verify for the lambda bw to use here
        # should not change a lot -> very small term
        for uv_gsa in gsa[1]:
            ln = ResonantIndex.lorentzian_lineshape(lambda_s, uv_gsa,
                                                    main_trans[2])
            gsa_ += gsa[0] * uv_gsa * ln
        for uv_esa in esa[1]:
            ln = ResonantIndex.lorentzian_lineshape(lambda_s, uv_esa,
                                                    main_trans[2])
            esa_ += esa[0] * uv_esa * ln

        res = ResonantIndex.calc_Q(n_0) * N * (esa_ - gsa_ - main_trans_)

        return res