308 lines
16 KiB
Matlab
308 lines
16 KiB
Matlab
% =========================================================================
|
|
% Tx_Main.m
|
|
% Pure MATLAB FMCW TX Simulator (Multi-Chirp Frame Generation)
|
|
% =========================================================================
|
|
|
|
clear; clc; close all;
|
|
|
|
% =============== 경로 추가 및 환경설정 ===============
|
|
currentFilePath = mfilename('fullpath');
|
|
currentFolder = fileparts(currentFilePath);
|
|
addpath(genpath(currentFolder));
|
|
|
|
%% =================== 시각화 토글 ===================
|
|
% 각 figure를 개별적으로 on/off 할 수 있습니다.
|
|
PlotToggle.range_profile = false; % Step 8 Range Profile
|
|
PlotToggle.tx_single = false; % Figure 1 Single chirp waveform
|
|
PlotToggle.tx_multi = false; % Figure 2 Multi chirp waveform
|
|
PlotToggle.tx_antenna = false; % Figure 3 TX antenna pattern
|
|
PlotToggle.rx_antenna = false; % Figure 4 RX antenna pattern
|
|
PlotToggle.rd_map = false; % Figure 5 Range-Doppler map
|
|
PlotToggle.cfar = false; % Figure 6 CFAR detections
|
|
PlotToggle.coverage = true; % Figure 7 Coverage analysis
|
|
|
|
%% =================== 파라미터 입력 ===================
|
|
|
|
% 1) 기본 물리 파라미터
|
|
RadarParams.Basic.c = 3e8; % 빛의 속도 (m/s)
|
|
RadarParams.Basic.kb = physconst('Boltzmann'); % 볼츠만 상수
|
|
RadarParams.Basic.T0 = 290; % 표준 온도 (K)
|
|
|
|
% 2) 파형생성 관련 파라미터
|
|
RadarParams.Waveform.fc = 77e9; % 중심 주파수 (Hz)
|
|
RadarParams.Waveform.lambda_c = RadarParams.Basic.c / RadarParams.Waveform.fc; % 중심 파장 (m)
|
|
RadarParams.Waveform.NumChirps = 128; % 프레임당 처프 수
|
|
RadarParams.Waveform.B_valid = 1e9; % 유효 대역폭 (Hz)
|
|
RadarParams.Waveform.fs_adc = 10e6; % ADC 샘플링 주파수 (Hz)
|
|
RadarParams.Waveform.fs_waveform = 1e6; % 파형 시각화용 샘플링 주파수 (Hz)
|
|
|
|
% 2-1) 처프 타이밍 파라미터
|
|
RadarParams.Waveform.Timing.IdleTime = 7e-6; % 처프 아이들 구간 (s)
|
|
RadarParams.Waveform.Timing.TxStartTime = 1e-6; % Tx on (s)
|
|
RadarParams.Waveform.Timing.AdcStartTime = 6e-6; % ADC on (s)
|
|
RadarParams.Waveform.Timing.AdcSampTime = 50e-6; % ADC 샘플링 구간 (s)
|
|
RadarParams.Waveform.Timing.ExcessTime = 1e-6; % 램프 끝나고 다음 처프 시작까지의 여유 시간 (s)
|
|
RadarParams.Waveform.Timing.RampEndTime = RadarParams.Waveform.Timing.IdleTime + RadarParams.Waveform.Timing.TxStartTime + RadarParams.Waveform.Timing.AdcSampTime + RadarParams.Waveform.Timing.ExcessTime; % 램프 종료 시점 (s)
|
|
RadarParams.Waveform.PRI = RadarParams.Waveform.Timing.IdleTime + RadarParams.Waveform.Timing.RampEndTime; % Pulse Repetition Interval (s)
|
|
RadarParams.Waveform.PRF = 1 / RadarParams.Waveform.PRI; % Pulse Repetition Frequency (Hz)
|
|
RadarParams.Waveform.Slope = RadarParams.Waveform.B_valid / RadarParams.Waveform.Timing.AdcSampTime; % 처프의 주파수 상승률 (Hz/s)
|
|
RadarParams.Waveform.f_start = RadarParams.Waveform.fc - RadarParams.Waveform.B_valid/2; % 처프 시작 주파수 (Hz)
|
|
|
|
% 2-2) Phase noise & nonlinearity parameters
|
|
RadarParams.Waveform.nonideal.pn_level = 0.05; % 위상노이즈 레벨
|
|
RadarParams.Waveform.nonideal.f_ripple = 300e3; % 위상 리플 주파수
|
|
RadarParams.Waveform.nonideal.peak_phase_error = 0.1; % 최대 위상오차
|
|
RadarParams.Waveform.nonideal.power_drop_edge = 0.8; % 엣지 파워 드롭
|
|
RadarParams.Waveform.nonideal.enable_phase_noise = true; % phase noise on/off
|
|
RadarParams.Waveform.nonideal.enable_nonlinearity = false; % nonlinearity on/off
|
|
% Datasheet 기반 phase noise 설정 (예: -89 dBc/Hz @ 1 MHz)
|
|
RadarParams.Waveform.nonideal.phaseNoise.offset_Hz = [1e6];
|
|
RadarParams.Waveform.nonideal.phaseNoise.level_dBc_Hz = [-89];
|
|
|
|
% 2-3) MIMO 모드 설정
|
|
RadarParams.Waveform.mimoMode = 'TDM'; % 'TDM' 또는 'DDMA'
|
|
|
|
% 3) RF 출력 파라미터 - 주파수별 출력 파워 [dBm]
|
|
RadarParams.RFOutput.PA_Profile.freqs = [76e9, 76.5e9, 77e9, 77.5e9, 78e9, 79e9];
|
|
RadarParams.RFOutput.PA_Profile.power_dBm = [10.5, 11.5, 12.0, 11.5, 10.5, 8.0];
|
|
|
|
% 4) 안테나 파라미터
|
|
% 4-1) 안테나 개수 및 위치 (3xN 행렬, 단위: m)
|
|
RadarParams.Antenna.NumTx = 2;
|
|
RadarParams.Antenna.NumRx = 4;
|
|
RadarParams.Antenna.lambda = RadarParams.Waveform.lambda_c;
|
|
RadarParams.Antenna.TxPos = [ (0:RadarParams.Antenna.NumTx-1)*2*RadarParams.Antenna.lambda; zeros(1,RadarParams.Antenna.NumTx); zeros(1,RadarParams.Antenna.NumTx) ]; % 3xNumTx
|
|
RadarParams.Antenna.RxPos = [ (0:RadarParams.Antenna.NumRx-1)*0.5*RadarParams.Antenna.lambda; zeros(1,RadarParams.Antenna.NumRx); zeros(1,RadarParams.Antenna.NumRx) ]; % 3xNumRx
|
|
|
|
% 4-2) 안테나 패턴 (각각 NumTx, NumRx 길이의 구조체 배열)
|
|
RadarParams.Antenna.tx_files = {}; % 필요시 파일명 지정 (로드 기능)
|
|
RadarParams.Antenna.rx_files = {};
|
|
RadarParams.Antenna.TxPattern = build_antenna_patterns(RadarParams.Antenna.NumTx, '1D', 12, 5, 30, 10, RadarParams.Antenna.tx_files);
|
|
RadarParams.Antenna.RxPattern = build_antenna_patterns(RadarParams.Antenna.NumRx, '2D', 14, 2, 40, 15, RadarParams.Antenna.rx_files);
|
|
|
|
% 5) 타겟 모델링
|
|
RadarParams.Target.R = [12]; % 타겟 거리 (m)
|
|
RadarParams.Target.v = [7]; % 타겟 속도 (m/s)
|
|
RadarParams.Target.rcs = [-10000]; % 타겟 RCS (dBsm)
|
|
RadarParams.Target.az = [10]; % 방위각 (deg)
|
|
RadarParams.Target.el = [0]; % 고각 (deg)
|
|
RadarParams.Target.NumTargets = length(RadarParams.Target.R);
|
|
|
|
% 6) 수신단 파라미터
|
|
RadarParams.Rxpath.fc_hpf = 1400; % HPF 컷오프 (Hz)
|
|
RadarParams.Rxpath.fc_lpf = 0.8*RadarParams.Waveform.fs_adc/2; % LPF 컷오프 주파수 (Hz)
|
|
RadarParams.Rxpath.adc_bits = 12; % ADC 비트수
|
|
RadarParams.Rxpath.adc_v_full_scale = 2.0; % full-scale 전압 (Vp-p)
|
|
RadarParams.Rxpath.receiver_mode = 'Real'; % 'IQ' 또는 'Real'
|
|
RadarParams.Rxpath.load_impedance_ohm = 50; % 임피던스 (Ohm)
|
|
RadarParams.Rxpath.rxPathGain_dB = 50; % RX 경로 이득 (dB)
|
|
RadarParams.Rxpath.system_NF_dB = 15; % 시스템 잡음지수 (dB)
|
|
|
|
% 6-5) Spur parameters (하드웨어 스퍼 모델링)
|
|
% Spur의 원인은 다양하지만, 대표적으로 LO leakage, 믹서 비선형성, ADC 샘플링 톤, 스위칭 잡음 등이 있다.
|
|
% SpurParams 구조체는 각 스퍼 유형별로 존재 여부와 특성을 정의한다.
|
|
% 실제에서는 spur의 발생 위치는 다양하지만, 시뮬레이션에서는 수신단에서 spur 신호를 모사하기 때문에 apply_lna_and_mixer 함수 내에서 SpurParams를 참조하여 spur 신호를 생성하고 adc_combined에 추가하는 방식으로 구현.
|
|
RadarParams.SpurParams = struct();
|
|
RadarParams.SpurParams.lo = struct('amp',0.01,'freq',1e6); % 위상 성분
|
|
RadarParams.SpurParams.mixer= struct('alpha2',1e-4,'alpha3',1e-6); % 2/3차 비선형
|
|
RadarParams.SpurParams.adc = struct('amp',1e-3,'freq',2e6); % ADC 이후 톤
|
|
RadarParams.SpurParams.switch = struct('amp',5e-4,'freq',500e3); % 스위칭 잡음
|
|
RadarParams.SpurParams.pulse = struct('amp',0.0,'freq',200e3,'duty',0.1,'phase',0);% 펄스열 락킹
|
|
RadarParams.SpurParams.lo_leak = struct('amp',0.05); % DC/LO leakage
|
|
RadarParams.SpurParams.clip = struct('amp',0.03,'range',20); % Clipping spur
|
|
RadarParams.SpurParams.enabled = false; % spur on/off
|
|
|
|
% 7) 신호처리 파라미터
|
|
RadarParams.SP.RDM.window_type_range = 'hann'; % Range FFT용 윈도우
|
|
RadarParams.SP.RDM.window_type_doppler = 'chebwin'; % Doppler FFT용 윈도우
|
|
|
|
num_samples_range = round(RadarParams.Waveform.fs_adc * RadarParams.Waveform.Timing.AdcSampTime);
|
|
num_chirps_doppler = RadarParams.Waveform.NumChirps;
|
|
|
|
% Range 윈도우 생성 및 성능 지표 계산
|
|
[RadarParams.SP.RDM.window_range, RadarParams.SP.RDM.window_metrics_range] = ...
|
|
create_window_with_metrics(RadarParams.SP.RDM.window_type_range, num_samples_range, 60);
|
|
|
|
% Doppler 윈도우 생성 및 성능 지표 계산
|
|
[RadarParams.SP.RDM.window_doppler, RadarParams.SP.RDM.window_metrics_doppler] = ...
|
|
create_window_with_metrics(RadarParams.SP.RDM.window_type_doppler, num_chirps_doppler, 60);
|
|
|
|
RadarParams.SP.CFAR.method = 'OS'; % 'CA' 또는 'OS'
|
|
RadarParams.SP.CFAR.dimension = '2D'; % '1D' 또는 '2D'
|
|
RadarParams.SP.CFAR.axis = 'doppler'; % 1D일 때만 사용: 'range' 또는 'doppler'
|
|
RadarParams.SP.CFAR.pfa = 1e-6; % false alarm 확률
|
|
RadarParams.SP.CFAR.train = [8, 8]; % [doppler, range] training cell 수 (1D면 첫 값 사용)
|
|
RadarParams.SP.CFAR.guard = [2, 2]; % [doppler, range] guard cell 수 (1D면 첫 값 사용)
|
|
RadarParams.SP.CFAR.rank = 0.75; % OS-CFAR rank 비율(0~1)
|
|
RadarParams.SP.CFAR.os_scale = 15.0; % OS-CFAR 임계 스케일
|
|
|
|
% 8) Secondary surface loss (안테나 반사 손실)
|
|
RadarParams.Antenna.SecondarySurfaceLoss_dB = 3;
|
|
|
|
% 9) 커버리지 분석 파라미터
|
|
RadarParams.Coverage.R_max = 10; % 최대 탐지 거리 (m)
|
|
RadarParams.Coverage.RCS_dBsm = 0; % 표적 RCS (dBsm)
|
|
|
|
|
|
%% 2. 모듈별 함수 호출 (TX 파이프라인)
|
|
% step 0. 파형 시각화를 위한 시간 벡터 및 TX 마스크 생성
|
|
Target = RadarParams.Target;
|
|
TxPattern = RadarParams.Antenna.TxPattern;
|
|
RxPattern = RadarParams.Antenna.RxPattern;
|
|
NumTx = RadarParams.Antenna.NumTx;
|
|
NumChirps = RadarParams.Waveform.NumChirps;
|
|
T_chirp = RadarParams.Waveform.Timing.IdleTime + RadarParams.Waveform.Timing.RampEndTime;
|
|
T_frame = T_chirp * NumChirps;
|
|
[t, tx_mask] = generate_waveform_timing(RadarParams);
|
|
|
|
% ================= ADC Raw Data 생성 파트 (step 1 ~ 6) =================
|
|
|
|
% step 1. 송신 안테나 이득 산출 (Ptx 반영 안함)
|
|
TxOut = radiate_antenna(Target, TxPattern);
|
|
|
|
% step 2. 채널 전파 (TTD 및 공간 감쇠 산출)
|
|
ChannelOut = apply_channel_effects(RadarParams);
|
|
|
|
% step 3. 수신 안테나 이득 결합
|
|
RxOut = receive_antenna(ChannelOut, Target, RxPattern);
|
|
|
|
% step 4-1. 물리적 이득 통합 (TX_Gain * Space_Loss * RX_Gain)
|
|
% 아직 RF 파워(V_tx)가 곱해지지 않은 상태의 "시스템 전달 함수" 진폭입니다.
|
|
SystemAmp = zeros(size(RxOut.space_loss_amp));
|
|
for k = 1:Target.NumTargets
|
|
for tx = 1:NumTx
|
|
SystemAmp(k, :, tx, :, :) = RxOut.space_loss_amp(k, :, tx, :, :) * TxOut.G_tx_amp(k, tx);
|
|
end
|
|
end
|
|
|
|
% step 4-2. 수신 RF/IF 체인 모델링 및 ADC 입력 신호 생성
|
|
% - 기능: 경로 감쇠/위상, PA 출력, 수신 이득, 잡음, MIMO 모드, non-ideal, spur를 반영해
|
|
% RX 채널별 디지털화 직전 신호를 생성합니다.
|
|
% - 출력 1) adc_raw_data : [NumRx x NumTx x NumChirps x N_adc_samples]
|
|
% TX별로 분리된 분석용 원시 신호(각 TX 성분이 분리되어 저장됨)
|
|
% - 출력 2) adc_combined : [NumRx x NumChirps x N_adc_samples]
|
|
% 실제 ADC 입력을 모사한 합산 신호(각 RX에서 모든 TX 성분이 합쳐진 신호)
|
|
[adc_raw_data, adc_combined] = apply_lna_and_mixer(RxOut, TxOut, RadarParams);
|
|
|
|
% step 5. ADC Combined 신호 (실제 ADC 입력) 생성 및 HPF 적용
|
|
adc_combined_hpf = apply_analog_hpf(adc_combined, RadarParams.Waveform.fs_adc, RadarParams.Rxpath.fc_hpf);
|
|
|
|
% step 6. ADC 모델링 (Quantization & Clipping)
|
|
% 하드웨어 사양 파라미터는 서두에서 정의됨
|
|
v_peak = max(abs(adc_combined_hpf(:)));
|
|
lsb_val = RadarParams.Rxpath.adc_v_full_scale / (2^RadarParams.Rxpath.adc_bits);
|
|
|
|
% ADC 양자화
|
|
adc_digital = apply_adc_quantization(adc_combined_hpf, RadarParams.Rxpath.adc_bits, RadarParams.Rxpath.adc_v_full_scale, RadarParams.Rxpath.receiver_mode);
|
|
|
|
% ================= 신호처리 파트 (step 7 ~ ) =================
|
|
|
|
% step 7. Range-FFT 및 Ideal LPF 적용
|
|
% LPF 차단 주파수와 윈도우 타입은 앞쪽에서 정의됨
|
|
% (RadarParams.Rxpath.fc_lpf, RadarParams.SP.RDM.*)
|
|
|
|
% adc_digital을 [NumRx, 1, NumChirps, N_samples] 형태로 변환 (process_range_fft_lpf 호환성)
|
|
adc_digital_expanded = reshape(adc_digital, [size(adc_digital,1), 1, size(adc_digital,2), size(adc_digital,3)]);
|
|
|
|
[range_data, r_axis] = process_range_fft_lpf(adc_digital_expanded, RadarParams);
|
|
|
|
% step 8. Range Profile 시각화 (1번 채널, 1번 처프)
|
|
if PlotToggle.range_profile
|
|
figure('Name', 'Range Profile with Ideal LPF');
|
|
plot(r_axis, 20*log10(abs(squeeze(range_data(1,1,1,:)))));
|
|
grid on; hold on;
|
|
xlabel('Range (m)');
|
|
ylabel('Magnitude (dB)');
|
|
title(['Range Profile (LPF Cut-off: ', num2str(RadarParams.Rxpath.fc_lpf/1e6), ' MHz)']);
|
|
|
|
% LPF 컷오프 지점 표시
|
|
xline((RadarParams.Rxpath.fc_lpf * RadarParams.Basic.c)/(2*RadarParams.Waveform.Slope), '--r', 'LPF Cut-off');
|
|
end
|
|
|
|
% step 9. Doppler-FFT 수행
|
|
[rd_cube, v_axis] = process_doppler_fft(range_data, RadarParams);
|
|
|
|
% step 10. NumRx 비코히어런트 적분(Noncoherent Integration) RDM 생성
|
|
target_rd_map = integrate_nci_rdm(rd_cube, RadarParams); % [Doppler x Range]
|
|
|
|
% step 11. CFAR 기반 표적 탐지 (OS/CA, 1D/2D, range/doppler 선택 가능)
|
|
[cfar_mask, cfar_threshold, cfar_detections] = detect_targets_cfar(target_rd_map, RadarParams);
|
|
|
|
%% 3. 결과 시각화 (Single Chirp & Multi-Chirp)
|
|
% [Figure 1] 단일 처프 정밀 타이밍 분석
|
|
T_chirp = RadarParams.Waveform.Timing.IdleTime + RadarParams.Waveform.Timing.RampEndTime;
|
|
idx_single = (t <= T_chirp);
|
|
|
|
t_single = t(idx_single);
|
|
tx_mask_single = tx_mask(idx_single);
|
|
|
|
fig_single = [];
|
|
if PlotToggle.tx_single
|
|
fig_single = visualize_tx_waveform(t_single, RadarParams.Waveform.Timing, RadarParams.Waveform.fc, RadarParams.Waveform.f_start, RadarParams.Waveform.Slope, tx_mask_single, RadarParams.Waveform.nonideal.peak_phase_error, RadarParams.Waveform.nonideal.f_ripple);
|
|
end
|
|
|
|
% [Figure 2] 다중 처프 프레임 시퀀스 및 MIMO 변조 확인
|
|
% (수정됨: mimoMode와 NumTx 변수를 추가로 전달)
|
|
fig_multi = [];
|
|
if PlotToggle.tx_multi
|
|
fig_multi = visualize_multi_tx_waveform(t, RadarParams.Waveform.Timing, RadarParams.Waveform.fc, RadarParams.Waveform.f_start, RadarParams.Waveform.Slope, tx_mask, NumChirps, RadarParams.Waveform.mimoMode, NumTx);
|
|
end
|
|
|
|
% --- [ Figure 3, 4: 안테나 방사 패턴 단면 도시 ] ---
|
|
% 'TX'와 'RX'라는 이름을 넘겨주어 그래프 타이틀과 범례를 구분합니다.
|
|
fig_tx_ant = [];
|
|
if PlotToggle.tx_antenna
|
|
fig_tx_ant = visualize_antenna_pattern(TxPattern, 'TX');
|
|
end
|
|
|
|
fig_rx_ant = [];
|
|
if PlotToggle.rx_antenna
|
|
fig_rx_ant = visualize_antenna_pattern(RxPattern, 'RX');
|
|
end
|
|
|
|
% [Figure 5] Range-Doppler Map 시각화 (NumRx NCI RDM)
|
|
fig_rd_map = [];
|
|
if PlotToggle.rd_map
|
|
fig_rd_map = visualize_rd_map_with_spurs(target_rd_map, r_axis, v_axis, Target, RadarParams.SpurParams, RadarParams, RadarParams.Waveform.Slope);
|
|
end
|
|
|
|
% [Figure 6] CFAR 탐지 결과 시각화 (2D MAP 위 원 마커)
|
|
fig_cfar = [];
|
|
if PlotToggle.cfar
|
|
fig_cfar = figure('Name', 'CFAR Detections on NCI RDM');
|
|
imagesc(r_axis, v_axis, 20*log10(abs(target_rd_map)));
|
|
axis xy;
|
|
colormap(jet);
|
|
colorbar;
|
|
xlabel('Range (m)');
|
|
ylabel('Velocity (m/s)');
|
|
title('CFAR Detections (Circle Markers)');
|
|
hold on;
|
|
|
|
if ~isempty(cfar_detections)
|
|
det_d_idx = cfar_detections(:,1); % Doppler bin index
|
|
det_r_idx = cfar_detections(:,2); % Range bin index
|
|
det_r = r_axis(det_r_idx);
|
|
det_v = v_axis(det_d_idx);
|
|
plot(det_r, det_v, 'wo', 'MarkerSize', 7, 'LineWidth', 1.5);
|
|
end
|
|
|
|
hold off;
|
|
end
|
|
|
|
% ================= Coverage Analysis (Performance Analysis) =================
|
|
% [Figure 7] Angular Coverage 분석: 2D 안테나 패턴 기반 효율적 SNR 계산
|
|
% 거리 100m, RCS 0 dBsm 표적의 각도별 SNR 분석
|
|
snr_coverage_2d = [];
|
|
azimuth_deg = [];
|
|
elevation_deg = [];
|
|
coverage_info = [];
|
|
fig_coverage = [];
|
|
if PlotToggle.coverage
|
|
[snr_coverage_2d, azimuth_deg, elevation_deg, coverage_info, fig_coverage] = analyze_coverage(RadarParams, RadarParams.Coverage.R_max, RadarParams.Coverage.RCS_dBsm);
|
|
end
|
|
|
|
|
|
|
|
|