Initial ARSS. Need to improve and add functions.

This commit is contained in:
2026-03-02 14:48:21 +09:00
commit 775668afdb
20 changed files with 1610 additions and 0 deletions
@@ -0,0 +1,68 @@
function PatternArray = build_antenna_patterns(NumAnt, PatternType, MaxGain, AzSquintStep, AzBeamwidth, ElBeamwidth, FileList)
% build_antenna_patterns: 안테나 방사 패턴 구조체 배열을 생성하거나 파일에서 로드합니다.
%
% [입력]
% - FileList (선택사항): 각 안테나 패턴 파일 경로가 담긴 Cell Array.
% 예: {'tx1.mat', 'tx2.mat', ''} (빈 문자열이면 수식 생성)
% 기본 각도 그리드 (수식 생성용)
az_angles_default = -90:1:90;
el_angles_default = -90:1:90;
% nargin을 체크하여 FileList가 안 들어왔으면 빈 셀로 초기화
if nargin < 7
FileList = {};
end
for n = 1:NumAnt
PatternArray(n).Type = PatternType;
% -------------------------------------------------------------
% Case A: 파일 경로가 주어졌고, 실제로 파일이 존재하는 경우 (Load)
% -------------------------------------------------------------
if length(FileList) >= n && ~isempty(FileList{n}) && isfile(FileList{n})
filePath = FileList{n};
loadedData = load(filePath); % .mat 파일 로드
% 파일 내부에 약속된 변수명(az_angles, el_angles 등)이 있다고 가정합니다.
PatternArray(n).az_angles = loadedData.az_angles;
PatternArray(n).el_angles = loadedData.el_angles;
if strcmpi(PatternType, '2D')
PatternArray(n).gain_dBi = loadedData.gain_dBi;
elseif strcmpi(PatternType, '1D')
PatternArray(n).max_gain_dBi = loadedData.max_gain_dBi;
PatternArray(n).gain_az_dBi = loadedData.gain_az_dBi;
PatternArray(n).gain_el_dBi = loadedData.gain_el_dBi;
end
% 파일 로드 성공
continue; % 로드가 성공했으므로 다음 안테나로 건너뜀
end
% -------------------------------------------------------------
% Case B: 파일이 없거나 경로가 비어있는 경우 (수식 기반 자동 생성)
% -------------------------------------------------------------
PatternArray(n).az_angles = az_angles_default;
PatternArray(n).el_angles = el_angles_default;
% 안테나 번호에 따라 빔이 조향된 각도(Squint Angle) 계산
% 예 (3개): (1-2)*5 = -5도, (2-2)*5 = 0도, (3-2)*5 = +5도
squint_az = (n - (NumAnt + 1)/2) * AzSquintStep;
if strcmpi(PatternType, '2D')
[AZ, EL] = meshgrid(PatternArray(n).az_angles, PatternArray(n).el_angles);
PatternArray(n).gain_dBi = MaxGain - 3*((AZ - squint_az)/AzBeamwidth).^2 - 3*(EL/ElBeamwidth).^2;
PatternArray(n).gain_dBi(PatternArray(n).gain_dBi < -20) = -20;
elseif strcmpi(PatternType, '1D')
PatternArray(n).max_gain_dBi = MaxGain;
PatternArray(n).gain_az_dBi = MaxGain - 3*((PatternArray(n).az_angles - squint_az)/AzBeamwidth).^2;
PatternArray(n).gain_az_dBi(PatternArray(n).gain_az_dBi < -20) = -20;
PatternArray(n).gain_el_dBi = MaxGain - 3*(PatternArray(n).el_angles/ElBeamwidth).^2;
PatternArray(n).gain_el_dBi(PatternArray(n).gain_el_dBi < -20) = -20;
end
end
end
@@ -0,0 +1,81 @@
function fig = visualize_antenna_pattern(PatternArray, AntennaName)
% visualize_antenna_pattern: 여러 개의 안테나 패턴 단면을 겹쳐서 도시합니다.
% 입력에 AntennaName (예: 'TX', 'RX')을 추가하여 창 이름을 구분합니다.
if nargin < 2
AntennaName = 'Antenna'; % 기본값
end
fig_name = sprintf('%s Radiation Pattern Cuts', AntennaName);
fig = figure('Name', fig_name, 'Position', [200, 200, 1000, 700]);
NumAnt = length(PatternArray);
colors = lines(NumAnt);
% [전역 Y축 범위 탐색]
y_min_total = inf;
y_max_total = -inf;
for i = 1:NumAnt
pat = PatternArray(i);
if strcmpi(pat.Type, '2D')
y_min_total = min(y_min_total, min(pat.gain_dBi(:)));
y_max_total = max(y_max_total, max(pat.gain_dBi(:)));
else
y_min_total = min(y_min_total, min([pat.gain_az_dBi(:); pat.gain_el_dBi(:)]));
y_max_total = max(y_max_total, max([pat.gain_az_dBi(:); pat.gain_el_dBi(:)]));
end
end
% ---------------------------------------------------------
% [Subplot 1] 상단: Azimuth Pattern Cut
% ---------------------------------------------------------
subplot(2, 1, 1);
hold on; grid on;
for i = 1:NumAnt
pat = PatternArray(i);
if strcmpi(pat.Type, '2D')
el0_idx = find(abs(pat.el_angles - 0) < 1e-6, 1);
az_gain_cut = pat.gain_dBi(el0_idx, :);
else
az_gain_cut = pat.gain_az_dBi;
end
plot(pat.az_angles, az_gain_cut, '-', 'Color', colors(i,:), 'LineWidth', 2.5, 'DisplayName', sprintf('%s %d', AntennaName, i));
end
title(sprintf('[%s] Azimuth Radiation Pattern Cut (at Elevation = 0^\\circ)', AntennaName), 'FontSize', 12);
xlabel('Azimuth Angle (deg)', 'FontSize', 11);
ylabel('Antenna Gain (dBi)', 'FontSize', 11);
xlim([min(PatternArray(1).az_angles), max(PatternArray(1).az_angles)]);
ylim([y_min_total - 2, y_max_total + 2]);
legend('show', 'Location', 'south');
hold off;
% ---------------------------------------------------------
% [Subplot 2] 하단: Elevation Pattern Cut
% ---------------------------------------------------------
subplot(2, 1, 2);
hold on; grid on;
for i = 1:NumAnt
pat = PatternArray(i);
if strcmpi(pat.Type, '2D')
az0_idx = find(abs(pat.az_angles - 0) < 1e-6, 1);
el_gain_cut = pat.gain_dBi(:, az0_idx);
else
el_gain_cut = pat.gain_el_dBi;
end
plot(pat.el_angles, el_gain_cut, '-', 'Color', colors(i,:), 'LineWidth', 2.5, 'DisplayName', sprintf('%s %d', AntennaName, i));
end
title(sprintf('[%s] Elevation Radiation Pattern Cut (at Azimuth = 0^\\circ)', AntennaName), 'FontSize', 12);
xlabel('Elevation Angle (deg)', 'FontSize', 11);
ylabel('Antenna Gain (dBi)', 'FontSize', 11);
xlim([min(PatternArray(1).el_angles), max(PatternArray(1).el_angles)]);
ylim([y_min_total - 2, y_max_total + 2]);
legend('show', 'Location', 'south');
hold off;
end