Операции с массивами различной формы - PullRequest
1 голос
/ 30 октября 2019

Немного фона: я хочу вычислить коэффициент массива антенной решетки MxN, который задается следующим уравнением:

eq1 Где w_i - комплексный вес i-го элемента, (x_i, y_i, z_i) - это положение i-го элемента, k - волновое число, theta и phi - соответственно угол места и азимут, а i находится в диапазоне от 0 до MxN-1.

В коде, который у меня есть:

-theta и phi - np.mgrid с формой (200,200) каждый,

-w_i, и (x, y, z) _i - np.array сshape (NxM,) каждый

, так что AF - массив np.ar с формой (200 200) (сумма по i). Пока проблем нет, и я могу легко получить AF, выполнив:

af = zeros([theta.shape[0],phi.shape[0]])
for i in range(self.size[0]*self.size[1]):
            af = af + ( w[i]*e**(-1j*(k * x_pos[i]*sin(theta)*cos(phi) + k * y_pos[i]* sin(theta)*sin(phi)+ k * z_pos[i] * cos(theta))) )

Теперь, каждый w_i зависит от частоты, поэтому AF тоже, и теперь у меня есть w_i с формой (NxM, 1000) (у меня есть 1000 выборок каждого w_i по частоте). Я попытался использовать приведенный выше код, меняющий

af = zeros([1000,theta.shape[0],phi.shape[0]])

, но получаю «операнды не могут быть переданы вместе». Я могу решить эту проблему, используя цикл for для 1000 значений, но он медленный и немного некрасивый. Итак, как правильно сделать суммирование или правильно определить w_i и AF?

Любая помощь будет принята с благодарностью. Спасибо.

edit Код с новым измерением, которое я пытаюсь добавить, следующий:

from numpy import *

class AntennaArray:
    def __init__(self,f,asize=None,tipo=None,dx=None,dy=None):
        self.Lambda = 299792458 / f
        self.k = 2*pi/self.Lambda
        self.size = asize
        self.type = tipo
        self._AF_DATA_SIZE = 200
        self.theta,self.phi =  mgrid[0 : pi : self._AF_DATA_SIZE*1j,0 : 2*pi : self._AF_DATA_SIZE*1j]

        self.element_pos = None
        self.element_amp = None
        self.element_pha = None

        if dx == None:
            self.dx = self.Lambda/2
        else:
            self.dx = dx

        if dy == None:
            self.dy = self.Lambda/2
        else:
            self.dy = dy


        self.generate_array()


    def generate_array(self):


        M = self.size[0]
        N = self.size[1]
        dx = self.dx
        dy = self.dy

        x_pos = arange(0,dx*N,dx)
        y_pos = arange(0,dy*M,dy)
        z_pos = 0

        ele = zeros([N*M,3])

        for i in range(M):
            ele[i*N:(i+1)*N,0] = x_pos[:]


        for i in range(M):
            ele[i*N:(i+1)*N,1] = y_pos[i]


        self.element_pos = ele


        #self.array_factor = self.calculate_array_factor()

    def calculate_array_factor(self):

        theta,phi = self.theta,self.phi

        k = self.k

        x_pos = self.element_pos[:,0]
        y_pos = self.element_pos[:,1]
        z_pos = self.element_pos[:,2]

        w = self.element_amp*exp(1j*self.element_pha)



        if len(self.element_pha.shape) > 1:
            #I have f_size samples of w_i(f)
            f_size = self.element_pha.shape[1]
            af = zeros([f_size,theta.shape[0],phi.shape[0]])
        else:
            #I only have w_i
            af = zeros([theta.shape[0],phi.shape[0]])


        for i in range(self.size[0]*self.size[1]):
        **strong text**#This for loop does the summation over i
            af = af + ( w[i]*e**(-1j*(k * x_pos[i]*sin(theta)*cos(phi) + k * y_pos[i]* sin(theta)*sin(phi)+ k * z_pos[i] * cos(theta))) )
        return af

Я попытался проверить его с помощью следующего основного

from numpy import *
f_points = 10

M = 2
N = 2

a = AntennaArray(5.8e9,[M,N])

a.element_amp = ones([M*N,f_points])
a.element_pha = zeros([M*N,f_points])

af = a.calculate_array_factor()

Но я получаю

ValueError: 'Невозможно передать операнды вместе с фигурами (10,) (200,200)'

Обратите внимание, что если я установлю

a.element_amp = ones([M*N])
a.element_pha = zeros([M*N])

Это хорошо работает.

Спасибо.

1 Ответ

1 голос
/ 30 октября 2019

Я посмотрел на код, и я думаю, что этот цикл for:

af = zeros([theta.shape[0],phi.shape[0]])
for i in range(self.size[0]*self.size[1]):
            af = af + ( w[i]*e**(-1j*(k * x_pos[i]*sin(theta)*cos(phi) + k * y_pos[i]* sin(theta)*sin(phi)+ k * z_pos[i] * cos(theta))) )

неверен во многих отношениях. Вы смешиваете измерения, вы не можете циклически таким образом.
И, кстати, чтобы в полной мере использовать numpy эффективность, никогда не зацикливаться на массивах. Это значительно замедляет выполнение.

Я пытался переработать эту часть.

Во-первых, я советую вам не использовать from numpy import *, это плохая практика (см. здесь ). Используйте import numpy as np. Я снова ввел аббревиатуру np, чтобы вы могли понять, что происходит от numpy.

Случай, не зависящий от частоты

В этом первом фрагменте предполагается, что w - это одномерный массив длины 4:Я пренебрегаю частотной зависимостью w, чтобы показать вам, как вы можете получить то, что вы уже получили без цикла for и используя вместо этого мощность numpy.

af_points = w[:,np.newaxis,np.newaxis]*np.e**(-1j*
           (k * x_pos[:,np.newaxis,np.newaxis]*np.sin(theta)*np.cos(phi) + 
            k * y_pos[:,np.newaxis,np.newaxis]*np.sin(theta)*np.sin(phi) + 
            k * z_pos[:,np.newaxis,np.newaxis]*np.cos(theta)
           ))
af = np.sum(af_points, axis=0)

Я использую NumPy Broadcast для получения трехмерного массива с именем af_points, форма которого (4, 200, 200). Чтобы сделать это, я использую np.newaxis, чтобы расширить номер оси массива, чтобы правильно использовать трансляцию. Подробнее здесь на np.newaxis.
Итак, w[:,np.newaxis,np.newaxis] - это массив фигур (4, 1, 1). Аналогично для x_pos[:,np.newaxis,np.newaxis], y_pos[:,np.newaxis,np.newaxis] и z_pos[:,np.newaxis,np.newaxis]. Поскольку углы имеют форму (200, 200), вещание может быть выполнено, а af_points имеет форму (4, 200, 200). Наконец, сумма получается с помощью np.sum, суммирования по первой оси для получения массива (200, 200).

Частотно-зависимый регистр

Теперь w имеет форму (4, 10), где 10 - частотные точки. Идея та же, просто учтите, что частота - это дополнительное измерение в ваших массивах: теперь af_points будет массивом формы (4, 10, 200, 200), где 10 - это f_points, который вы определили.

Чтобы это было понятно, я разделил вычисления:

#exp_point is only the exponent, frequency independent. Will be a (4, 200, 200) array.
exp_points = np.e**(-1j*
            (k * x_pos[:,np.newaxis,np.newaxis]*np.sin(theta)*np.cos(phi) + 
             k * y_pos[:,np.newaxis,np.newaxis]*np.sin(theta)*np.sin(phi) +
             k * z_pos[:,np.newaxis,np.newaxis]*np.cos(theta)
            ))
af_points = w[:,:,np.newaxis,np.newaxis] * exp_points[:,np.newaxis,:,:]
af = np.sum(af_points, axis=0)

И теперь af имеет форму (10, 200, 200).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...