# -*- coding: utf-8 -*-
from __future__ import annotations
from h5py import Group
import numpy as np
from hermespy.channel.channel import InterpolationMode
from hermespy.core import Device, ChannelStateInformation, ChannelStateFormat, Signal
from .channel import Channel, ChannelRealization
__author__ = "Jan Adler"
__copyright__ = "Copyright 2023, Barkhausen Institut gGmbH"
__credits__ = ["Andre Noll Barreto", "Tobias Kronauer", "Jan Adler"]
__license__ = "AGPLv3"
__version__ = "1.2.0"
__maintainer__ = "Jan Adler"
__email__ = "jan.adler@barkhauseninstitut.org"
__status__ = "Prototype"
[docs]
class IdealChannelRealization(ChannelRealization):
"""Realization of an ideal channel.
Generated by the :meth:`realize()<IdealChannel.realize>` routine of :class:`IdealChannels<IdealChannel>`.
"""
[docs]
def state(
self,
transmitter: Device,
receiver: Device,
delay: float,
sampling_rate: float,
num_samples: int,
num_taps: int,
) -> ChannelStateInformation:
# MISO case
if receiver.num_receive_antennas == 1:
spatial_response = np.ones((1, transmitter.num_receive_antennas), dtype=np.complex_)
# SIMO case
elif transmitter.num_transmit_antennas == 1:
spatial_response = np.ones((receiver.num_receive_antennas, 1), dtype=np.complex_)
# MIMO case
else:
spatial_response = np.eye(
receiver.num_receive_antennas, transmitter.num_transmit_antennas, dtype=np.complex_
)
# Scale response by channel gain
spatial_response *= np.sqrt(self.gain)
sampled_state = np.expand_dims(
np.repeat(spatial_response[:, :, np.newaxis], num_samples, 2), axis=3
)
return ChannelStateInformation(ChannelStateFormat.IMPULSE_RESPONSE, sampled_state)
def _propagate(
self,
signal: Signal,
transmitter: Device,
receiver: Device,
interpolation: InterpolationMode,
) -> Signal:
# Single antenna transmitter case
if transmitter.num_transmit_antennas == 1:
propagated_samples = np.repeat(
signal.samples[[0], :], receiver.num_receive_antennas, axis=0
)
# Single antenna receiver case
elif receiver.num_receive_antennas == 1:
propagated_samples = np.sum(signal.samples, axis=0, keepdims=True)
# No receiving antenna case
elif receiver.num_receive_antennas == 0:
propagated_samples = np.empty((0, signal.num_samples), dtype=np.complex_)
# MIMO case
else:
propagated_samples = signal.samples
if transmitter.num_transmit_antennas < receiver.num_receive_antennas:
propagated_samples = np.append(
propagated_samples,
np.zeros(
(
receiver.num_receive_antennas - transmitter.num_transmit_antennas,
signal.num_samples,
),
dtype=np.complex_,
),
axis=0,
)
return Signal(
propagated_samples,
signal.sampling_rate,
signal.carrier_frequency,
signal.delay,
signal.noise_power,
)
[docs]
class IdealChannel(Channel[IdealChannelRealization]):
"""An ideal distortion-less channel.
Refer to :doc:`/api/channel.ideal` for further information.
For MISO systems, the received signal is the addition of the signal transmitted at all
antennas.
For SIMO systems, the received signal is the signal transmitted at the single antenna.
For MIMO systems, the received signal is the signal transmitted at all antennas.
"""
yaml_tag: str = "Channel"
def _realize(self) -> IdealChannelRealization:
return IdealChannelRealization(self.alpha_device, self.beta_device, self.gain)
[docs]
def recall_realization(self, group: Group) -> IdealChannelRealization:
return IdealChannelRealization.From_HDF(group, self.alpha_device, self.beta_device)