Skip to content

Add taper support and refactor array-factor calculation #2726

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

George-Guryev-flxcmp
Copy link
Contributor

@George-Guryev-flxcmp George-Guryev-flxcmp commented Aug 8, 2025

Add taper support to RectangularAntennaArrayCalculator; refactor array factor computation for clarity and efficiency.

  • Implemented taper integration
  • Refactored AF calculation
  • Updated tests and docs

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 7 comments

Edit Code Review Bot Settings | Greptile

Copy link
Contributor

github-actions bot commented Aug 8, 2025

Diff Coverage

Diff: origin/develop...HEAD, staged and unstaged changes

  • tidy3d/plugins/microwave/array_factor.py (94.2%): Missing lines 655,704,918,938,958,978,1031,1195

Summary

  • Total: 137 lines
  • Missing: 8 lines
  • Coverage: 94%

tidy3d/plugins/microwave/array_factor.py

  651             amp_z = amp_z[:, None, None]
  652 
  653         # Tapers with non-separable amplitude weights are not supported by this function
  654         else:
! 655             raise ValueError(f"Unsupported taper type {type(self.taper)} was passed.")
  656 
  657         # Calculate individual array factors in x, y, and z directions
  658         af_x = np.sum(
  659             amp_x * exp_x,

  700         amps = self.taper.amp_multipliers(self.array_size)
  701 
  702         # ensure amplitude weights are in format tuple[ArrayLike, ]
  703         if len(amps) != 1:
! 704             raise ValueError(
  705                 "Non-cartesian taper was expected. Please ensure a valid taper is used."
  706             )
  707 
  708         # compute array factor: AF(theta,f) = sum_{x,y,z} amp(x,y,z) * exp_x(x,theta,f)*exp_y(y,theta,f)*exp_z(z,theta,f)

  914         -------
  915         ArrayLike
  916             1D array of Hamming window weights.
  917         """
! 918         return hamming(N)
  919 
  920 
  921 class BlackmanWindow(AbstractWindow):
  922     """Standard Blackman window for tapering or spectral shaping."""

  934         -------
  935         ArrayLike
  936             1D array of Blackman window weights.
  937         """
! 938         return blackman(N)
  939 
  940 
  941 class BlackmanHarrisWindow(AbstractWindow):
  942     """Standard Blackman-Harris window for tapering or spectral shaping."""

  954         -------
  955         ArrayLike
  956             1D array of Blackman-Harris window weights.
  957         """
! 958         return blackmanharris(N)
  959 
  960 
  961 class HannWindow(AbstractWindow):
  962     """Hann window with configurable sidelobe suppression and sidelobe count."""

  974         -------
  975         ArrayLike
  976             1D array of Hann window weights.
  977         """
! 978         return hann(N)
  979 
  980 
  981 class ChebWindow(AbstractWindow):
  982     """Standard Chebyshev window for tapering with configurable sidelobe attenuation."""

  1027         -------
  1028         ArrayLike
  1029             1D array of Kaiser window weights.
  1030         """
! 1031         return kaiser(N, self.beta)
  1032 
  1033 
  1034 class _Taylor1D(AbstractWindow):
  1035     """Taylor window with configurable sidelobe suppression and sidelobe count."""

  1191             Weights sampled from the Taylor window.
  1192         """
  1193         if self.mode == "1d":
  1194             if not isinstance(arg, int):
! 1195                 raise TypeError("1D Taylor expects integer size.")
  1196             return _Taylor1D(sll=self.sll, nbar=self.nbar).get_weights(N=arg)
  1197         else:
  1198             locs = np.asarray(arg)
  1199             return _TaylorRadial(sll=self.sll, nbar=self.nbar).get_weights(p_vec=locs)

Copy link
Contributor

@dbochkov-flexcompute dbochkov-flexcompute left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great start! Still not sure about at, sll, nbar, etc vs attenuation, side_lobe_level, num_constant_sidelobes, etc. @yaugenst what's our policy on using pydantic alias feature on frontend?

… calculation

- Implemented taper integration to allow amplitude weighting in antenna arrays
- Refactored array factor computation for improved clarity and efficiency
- Updated relevant tests and documentation accordingly
Copy link
Collaborator

@weiliangjin2021 weiliangjin2021 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice work!

discriminator=TYPE_TAG_STR,
title="Antenna Array Taper",
description="Amplitude weighting of array elements to control main lobe width and suppress side lobes.",
# discriminator=
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be removed?

Parameters:
----------
Parameters
---------
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one missing "-"?

class ChebWindow(AbstractWindow):
"""Standard Chebyshev window for tapering with configurable sidelobe attenuation."""

at: pd.PositiveFloat = pd.Field(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more informative to name the field "attenuation", unless "at" is widely used in the field.


# validate that at least one window is provided
@classmethod
def all_dims(cls, window: RectangularWindowType) -> RectangularTaper:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe isotropic_window for clarity?

else np.ones(effective_size[1]),
self.window_z.get_weights(effective_size[2])
if self.window_z is not None
else np.ones(effective_size[2]),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid repetition with a for loop, e.g.

amps = (window.get_weights(effective_size[ind]) if window is not None
            else np.ones(effective_size[ind]) for ind, window in enumerate([self.windows_x, self.windows_y, self.windows_z]))

..., title="Window Object", description="Window type used to taper array antenna."
)

# Change TaylorWindow mode to call _TaylorRadial
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should raise an error if TaylorWindow's mode is not radial, rather than changing it silently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants