Files
ARSS/01. Tx Path/visualize_multi_tx_waveform.m
T

145 lines
6.7 KiB
Matlab

function fig = visualize_multi_tx_waveform(t, Timing, fc, f_start, Slope, tx_mask, TotalNumChirps, mimoMode, NumTx)
fig = figure('Name', 'Multi-Chirp & MIMO Modulation', 'Position', [150, 150, 1100, 750]);
T_chirp = Timing.IdleTime + Timing.RampEndTime;
NumChirpsToPlot = min(TotalNumChirps, 4);
plot_idx = (t <= NumChirpsToPlot * T_chirp);
t_plot = t(plot_idx);
tx_mask_plot = tx_mask(plot_idx);
t_mod = mod(t_plot, T_chirp);
t_ramp = t_mod - Timing.IdleTime;
inst_freq_theoretical = f_start + Slope * t_ramp;
inst_freq_masked = inst_freq_theoretical;
inst_freq_masked(tx_mask_plot == 0) = NaN;
% =========================================================
% [Subplot 1] 상단: 시간에 따른 주파수 파형
% =========================================================
subplot(2, 1, 1);
y_min = (f_start / 1e9) - 0.25;
y_max = (f_start / 1e9) + (Slope * Timing.RampEndTime / 1e9) + 0.1;
plot(t_plot * 1e6, inst_freq_masked / 1e9, 'b', 'LineWidth', 2);
grid on; hold on;
title(sprintf('Continuous Multi-Chirp Sequence (Showing %d of %d Chirps)', NumChirpsToPlot, TotalNumChirps), 'FontSize', 12);
ylabel('Absolute Frequency (GHz)', 'FontSize', 11);
ylim([y_min, y_max]);
if ~isempty(t_plot)
xlim([0, max(t_plot)*1e6]);
else
xlim([0, 1]); % fallback range when no data
end
f_valid_start = f_start + (Slope * Timing.AdcStartTime);
f_valid_end = f_start + (Slope * (Timing.AdcStartTime + Timing.AdcSampTime));
valid_bandwidth = f_valid_end - f_valid_start;
info_str = {
sprintf('▶ Valid Start Freq : %.4f GHz', f_valid_start / 1e9), ...
sprintf('▶ Center Freq : %.4f GHz', fc / 1e9), ...
sprintf('▶ Valid End Freq : %.4f GHz', f_valid_end / 1e9), ...
sprintf('▶ Transmit Bandwidth : %.4f GHz', valid_bandwidth / 1e9), ...
sprintf('▶ Total Gen Chirps : %d', TotalNumChirps)
};
text(0.02, 0.96, info_str, 'Units', 'normalized', 'FontSize', 10, 'FontWeight', 'bold', 'BackgroundColor', [1 1 1 0.85], 'EdgeColor', 'k', 'VerticalAlignment', 'top', 'Margin', 5);
guide_line_args = {'Color', [0 0 0.5], 'LineStyle', '--', 'LineWidth', 1};
for i = 0:NumChirpsToPlot
plot([i * T_chirp * 1e6, i * T_chirp * 1e6], [y_min, y_max], guide_line_args{:});
end
draw_dim_arrow = @(x1, x2, y, label_str) ...
[plot([x1, x2], [y, y], 'k-', 'LineWidth', 1.2), ...
fill([x1, x1 + min(0.6, (x2-x1)*0.35), x1 + min(0.6, (x2-x1)*0.35)], [y, y + 0.015, y - 0.015], 'k', 'EdgeColor', 'none'), ...
fill([x2, x2 - min(0.6, (x2-x1)*0.35), x2 - min(0.6, (x2-x1)*0.35)], [y, y + 0.015, y - 0.015], 'k', 'EdgeColor', 'none'), ...
text((x1+x2)/2, y + 0.03, label_str, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'bottom', 'FontSize', 9, 'FontWeight', 'bold', 'BackgroundColor', 'w', 'EdgeColor', 'k')];
y_pri = y_min + 0.08;
pri_us = T_chirp * 1e6;
prf_khz = (1 / T_chirp) / 1e3;
pri_prf_label = sprintf('PRI: %.1f \\mus\nPRF: %.1f kHz', pri_us, prf_khz);
draw_dim_arrow(0, pri_us, y_pri, pri_prf_label);
hold off;
% =========================================================
% [Subplot 2] 하단: MIMO 방식 통합형 Active TX & Phase 맵
% =========================================================
subplot(2, 1, 2);
hold on; grid on;
% --- [핵심 추가]: TX 개수에 맞춘 고유 색상 팔레트 생성 ---
% lines() 함수는 구분이 명확하고 세련된 색상 배열을 반환합니다.
tx_colors = lines(NumTx);
for tx = 1:NumTx
plot([0, NumChirpsToPlot * T_chirp * 1e6], [tx, tx], ':', 'Color', [0.8 0.8 0.8], 'HandleVisibility', 'off');
end
for i = 0 : NumChirpsToPlot - 1
t_center_us = (i + 0.5) * T_chirp * 1e6;
if strcmpi(mimoMode, 'TDM')
active_tx_list = mod(i, NumTx) + 1;
elseif strcmpi(mimoMode, 'DDMA')
active_tx_list = 1:NumTx;
else
active_tx_list = 1;
end
for tx = 1:NumTx
% 현재 처리 중인 TX 안테나의 고유 색상 추출
current_color = tx_colors(tx, :);
if ismember(tx, active_tx_list)
if strcmpi(mimoMode, 'DDMA')
phase_rad = 2 * pi * (tx - 1) * i / NumTx;
phase_deg = mod(rad2deg(phase_rad), 360);
else
phase_deg = 0;
end
% 활성화: 해당 안테나의 색상으로 꽉 채워진 원
plot(t_center_us, tx, 'o', 'MarkerSize', 12, 'MarkerFaceColor', current_color, 'MarkerEdgeColor', current_color, 'HandleVisibility', 'off');
text_offset_us = T_chirp * 1e6 * 0.08;
text(t_center_us + text_offset_us, tx, sprintf('%d^\\circ', round(phase_deg)), ...
'VerticalAlignment', 'middle', 'HorizontalAlignment', 'left', ...
'FontSize', 9, 'FontWeight', 'bold', 'Color', current_color);
else
% 비활성화: 해당 안테나의 색상 테두리를 가진 비워진 원
plot(t_center_us, tx, 'o', 'MarkerSize', 12, 'MarkerFaceColor', 'w', 'MarkerEdgeColor', current_color, 'HandleVisibility', 'off');
end
end
end
title(sprintf('%s Active TX Antenna & Phase Map', upper(mimoMode)), 'FontSize', 12);
ylabel('TX Antenna', 'FontSize', 11);
yticks(1:NumTx);
% Y축 라벨에도 텍스트 색상을 입혀 직관성 극대화 (선택 사항)
% yticklabels(arrayfun(@(x) sprintf('\\color[rgb]{%f,%f,%f}TX %d', tx_colors(x,1), tx_colors(x,2), tx_colors(x,3), x), 1:NumTx, 'UniformOutput', false));
yticklabels(arrayfun(@(x) sprintf('TX %d', x), 1:NumTx, 'UniformOutput', false));
ylim([0.5, NumTx + 0.5]);
% --- [범례 수정]: 중립적인 색상(다크 그레이)으로 상태의 개념만 표시 ---
neutral_color = [0.3 0.3 0.3];
h_on = plot(NaN, NaN, 'o', 'MarkerSize', 10, 'MarkerFaceColor', neutral_color, 'MarkerEdgeColor', neutral_color, 'DisplayName', 'Active');
h_off = plot(NaN, NaN, 'o', 'MarkerSize', 10, 'MarkerFaceColor', 'w', 'MarkerEdgeColor', neutral_color, 'DisplayName', 'Inactive');
legend([h_on, h_off], 'Location', 'best', 'FontSize', 10, 'Box', 'on');
xlabel('Time (\mus)', 'FontSize', 11);
xlim([0, max(t_plot)*1e6]);
y_lims_bottom = ylim;
for i = 0:NumChirpsToPlot
plot([i * T_chirp * 1e6, i * T_chirp * 1e6], y_lims_bottom, guide_line_args{:}, 'HandleVisibility', 'off');
end
hold off;
end