--EDIT: Следуя комментарию Жюльена, я сделал минимальный воспроизводимый пример! Это в конце исходного поста :) --
У меня есть код на Python, который помогает мне найти точки пересечения двух кривых; каждый раз f(frequency)
равен одному из тангенсов (или котангенсов). Я сохраняю те значения, которые соответствуют режимам, доступным для данной частоты. Я перебираю несколько частот, чтобы знать, какие моды на каких частотах распространяются.
Для каждой частоты (или пульсации) в моем цикле for я нахожу точки пересечения с помощью программы Intersection
, которая возвращает позиции x и y в массиве. Мне нужны только значения x, поэтому я храню их в массиве с именем X_inter
. Я сохраняю каждый X_inter в более крупный массив под названием arr_KX
для облегчения дальнейших манипуляций.
Следовательно, строки arr_KX
соответствуют заданной частоте, а столбцы соответствуют заданному режиму (первый столбец соответствует 0-му режиму и т. д.).
Я не могу знать, какой будет самый большой режим и, следовательно, сколько столбцов должно быть в моем массиве, пока я не завершу цикл if.
Проблема в том, что для более низких частот у меня будет меньше мод, чем для более высоких частот. Как вы можете видеть в следующем коде, когда я попытаюсь изменить размер arr_KX, я потеряю всю предыдущую информацию.
В идеальном случае должно произойти следующее: если первая частота имеет 2 режима, а вторая частота — 4, то arr_KX показывает:
arr_KX = [[mode 1 of f1, mode 2 of f1, nan , nan ] , [ mode 1 of f2, mode 2 of f2, mode 3 of f2, mode 4 of f2]]
Или более читабельно:
arr_KX = [[m1,m2,nan,nan],[m1,m2,m3,m4]]
import numpy as np
import matplotlib.pyplot as plt
import Intersection as inter
np.seterr(all='ignore')
plt.clf()
height, width, lenght = 500e-6, 500e-6, 100e-6
d = height/2
c0 = 3e8
n_core = 5.2
n_cladding = 1.
FntSze = 15
"""
Solve this equations
"""
def cot(angle):
return np.cos(angle)/np.sin(angle)
def TE_LHS_sym(var1):
return np.tan(var1*d)
def TE_LHS_antisym(var2):
return -cot(var2*d)
def TE_RHS(var3,pulsation_):
return ((pulsation_**2*d**2*
(n_core**2-n_cladding**2)/(c0**2*var3**2*d**2))-1)**(0.5)
start, end, Nx, NN = 100e9, 1000e9 + 1, 1001 ,21
##Start and end of pulsation range, with NN the number of frequencies we work with and Nx the number of kx generated
f_range = np.linspace(start,end,NN)
w_range = f_range*2*np.pi
k = np.linspace(0,4*np.pi,Nx)/d
tol = 40. ##To limit the float points at discontinuity of tangents/cotangents
y_tan = TE_LHS_sym(k) ##Draw tan(kx*d)
y_tan[y_tan > tol] = np.nan ##Limits the aberrations at discontinuity
y_tan[y_tan < -tol] = np.nan
y_cot = TE_LHS_antisym(k) ##Draw cot(kx*d)
y_cot[y_cot > tol] = np.nan
y_cot[y_cot < -tol] = np.nan
init=0
size = 0
##PlOTTING
plt.figure(1)
plt.plot(k*d,y_tan,label='tan($k_{x0}d$)' )
plt.plot(k*d,y_cot)#,label='-cot($k_{x0}d$)')
for init,omega in enumerate(w_range): #Loop for pulsations, starting at max and ending at min
y_RHS = TE_RHS(k,omega) #Draws RHS, intersaction points with tan/cot will give kx_mode
y_RHS[y_RHS > tol] = np.nan
plt.plot(k*d,y_RHS,marker='',label='RHS at $f$ = '+ str(round(omega*1e-9/(2*np.pi),2)) + ' GHz')
##Find intersection points between tan/cot, they will give kx_mode for a given w
x_inter_tan,y_inter_tan = inter.intersection(k, y_tan, k, y_RHS)
x_inter_cot,y_inter_cot = inter.intersection(k, y_cot, k, y_RHS)
plt.plot(x_inter_cot*d, y_inter_cot, '+k') ##Draws inter points cot//RHS
plt.plot(x_inter_tan*d, y_inter_tan, '+k') ##Draws inter points tan//RHS
plt.xlabel("$k_{x}d$ (in $rad.m^{-1}$)",fontsize=FntSze)
plt.ylabel("",fontsize=FntSze)
X_inter = np.sort(np.concatenate([x_inter_cot.copy(),x_inter_tan.copy()])*d) #Gives kx_m*d for a w
KX_inter = X_inter/d
if KX_inter.shape[0] > size : #In order to know how many columns we need
size = KX_inter.shape[0]
arr_KX = np.zeros((NN,size)) #Create matrix NN*size == w_n*kx_modes
bb = KX_inter.resize(size) #Higher w_m have higher kx_modes, this sets them up in the same shape
arr_KX[int(init),:] = KX_inter #Matrix w_n*kx_modes appends line at w_n of the kx_modes
Столкнувшись с этой проблемой, я много раз пытался ее решить, но так и не нашел хорошего решения. Поэтому я применил обходной путь и решил генерировать частоты от самой высокой до самой низкой, чтобы всегда начинать с максимально возможного количества мод. В большинстве случаев это работает (подчеркивается большую часть времени), но я хочу знать, как я могу решить эту проблему с массивом, не инвертируя генерацию частот, поскольку это вызовет у меня некоторые серьезные проблемы, поскольку я продолжаю работать над физикой этого проблема.
Я не могу точно вспомнить, что я сделал, поскольку прошли недели с тех пор, как я остановился на своем обходном пути, но я попробовал столько «решений», сколько смог найти в Google. Либо с numpy
, либо с базовыми командами Python проблема все равно сохранится или возникнет новая.
При изменении формы (я думаю) проблема заключалась в том, что значения режима с одной частоты переходили на другую частоту.
Итак, я бы:
arr_KX =[[mode1 of f1,mode2 of f1,mode1 of f2,mode2 of 2],[mode3 of f2, mode 4 of f2, nan, nan]]
РЕДАКТИРОВАТЬ Вот минимальный воспроизводимый пример:
import numpy as np
from numpy.random import default_rng
NN = [2,2,4,6,6]
size = 0
init = 0
for n in NN:
KX_inter = default_rng().random((n)) #shape (n,)
print(KX_inter)
if KX_inter.shape[0] > size :
size = KX_inter.shape[0] #In order to know how many columns we need
arr_KX = np.zeros((len(NN),size)) #Create matrix Nx*size == w_n*kx_modes
bb = KX_inter.resize(size) #Higher w_m have higher kx_modes, this sets them up in the same shape
arr_KX[int(init),:] = KX_inter
init = init + 1
print(arr_KX)
Вы также можете видеть, что если вы инвертируете NN, у вас не возникнет проблема, которая на данный момент и была моим решением. Но мне бы хотелось написать этот код без этого обходного пути.
Не совсем разбираясь в проблеме, я предполагаю, что если вы не знаете размер массива, numpy aray, вероятно, не является правильной структурой, и вы, возможно, захотите придерживаться собственных списков?
Вы действительно не хотите пытаться расширять существующие массивы numpy, вы можете просмотреть этот ТАК-вопрос/ответ, который описывает его более подробно. Не используйте массивы numpy, если вы хотите продолжать расширять/изменять их размер.
@Julien Я добавил минимальный воспроизводимый пример, так легче понять? Кроме того, я не могу использовать собственный список, потому что у меня возникла проблема, о которой я упоминаю в конце исходного сообщения.
Спасибо за комментарий @KaranShishoo, но у меня возникли проблемы с пониманием поста, на который вы ссылаетесь. Если я правильно понимаю, в моем случае мне абсолютно необходимо работать с массивами, мне нужно будет создать очень большой массив, а затем разрезать его, чтобы он работал?
Вы можете создать структуру данных, используя списки, а затем преобразовать ее в массив numpy, поскольку в этот момент вы будете знать размер.
Спасибо @JohnColeman за ваш ответ. Знаешь, как я мог бы продолжать это делать? Я не очень хорошо владею Python, и в последний раз, когда я пытался использовать списки, у меня возникла проблема, которую я описал в конце моего исходного поста.
Где ты это описываешь? Я не вижу упоминания о списках в вопросе. Обязательно избегайте этой проблемы
Большое спасибо @Barmar! Завтра утром я обновлю исходный вопрос, я нашел способ сделать то, что пытался сделать в конце концов. Я использовал списки, чтобы решить эту проблему, jeje
После обновления вопроса опубликуйте решение в ответе ниже, а не в вопросе.
Готово @Barmar, надеюсь, я сделал это правильно. Спасибо еще раз за помощь!
Чтобы решить эту проблему, мне пришлось сделать циклы. Исходный вариант, в котором я нахожу точки пересечения, но на этот раз я добавляю их в пустой список, а не в массив. Я также ищу самый длинный размер своих отдельных списков.
X_inter = np.sort(np.concatenate([x_inter_cot.copy(),x_inter_tan.copy()])*d)
KX_inter_ = X_inter/d
KX_inter = list(KX_inter_)
KX_list.append(KX_inter)
if len(KX_inter) > size:
size = len(KX_inter)
Теперь, когда они сгруппированы внутри «KX_list», я запускаю еще один цикл, чтобы добавить необходимый «np.nan» в каждый отдельный список. Затем я конвертирую их в np.array.
i = 0
for r in KX_list:
s = len(r)
arr0 = [ np.nan for _ in range (size-s)]
KX_list[i].extend(arr0)
i += 1
arr_KX = np.array(KX_list)
Вот простой пример, который можно попробовать на своих консолях:
fruit = [[1,2],[2,3,3,4,2],[1,2,3]]
size = 0
for r in fruit :
if size < len(r):
size = len(r)
it = 0
for r in fruit :
s = len(r)
arr0 = [np.nan]*(size-s)
print(arr0)
fruit[it].extend(arr0)
it = it+1
arr_fruit = np.array(fruit)
print(arr_fruit)
Столько слов, а я так и не понял проблемы. Пожалуйста, отбросьте ненужное и перейдите к сути с помощью упрощенного минимально воспроизводимого примера.