-
Notifications
You must be signed in to change notification settings - Fork 0
Add rev10: regression-safe max-azimuth refactor and validation harness #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| function [sub_array_agg_check_mc_dBm]=subchunk_agg_check_maxazi_rev10(app,cell_aas_dist_data,array_bs_azi_data,radar_beamwidth,min_azimuth,max_azimuth,base_protection_pts,point_idx,on_list_bs,cell_sim_chunk_idx,rand_seed1,agg_check_reliability,on_full_Pr_dBm,clutter_loss,custom_antenna_pattern,sub_point_idx) | ||
| %SUBCHUNK_AGG_CHECK_MAXAZI_REV10 Regression-safe speedup revision. | ||
| % rev10 intentionally preserves strict per-iteration RNG behavior from rev9. | ||
| % rev10 removes azimuth chunking (when memory is safe) and optimizes aggregation | ||
| % without changing random stream semantics. | ||
| % rev11 can target RNG/pre-generation/vectorization changes after rev10 validation. | ||
|
|
||
| DEBUG_CHECKS=false; | ||
|
|
||
| %%%%%%%%%Adding clutter distribution in monte carlo later | ||
| %%%%%%%%%%We just have to make a new bs_eirp_dist based on the azimuth | ||
| %%%%%%%%%%of the base station antenna offset to the federal point. | ||
| array_aas_dist_data=cell_aas_dist_data{2}; | ||
| aas_dist_azimuth=cell_aas_dist_data{1}; | ||
| mod_azi_diff_bs=array_bs_azi_data(:,4); | ||
|
|
||
| %%%%%%%%%Find the azimuth off-axis antenna loss | ||
| [nn_azi_idx]=nearestpoint_app(app,mod_azi_diff_bs,aas_dist_azimuth); %%%%%%%Nearest Azimuth Idx | ||
| super_array_bs_eirp_dist=array_aas_dist_data(nn_azi_idx, :); | ||
|
|
||
| %%%%%%%%%%%%%%%%Calculate the simualation azimuths | ||
| [array_sim_azimuth,num_sim_azi]=calc_sim_azimuths_rev3_360_azimuths_app(app,radar_beamwidth,min_azimuth,max_azimuth); | ||
|
|
||
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Calculate Each Base Station Azimuth | ||
| sim_pt=base_protection_pts(point_idx,:); | ||
| bs_azimuth=azimuth(sim_pt(1),sim_pt(2),on_list_bs(:,1),on_list_bs(:,2)); | ||
|
|
||
| %%%%%%%%%%%%%%Generate MC Iterations and Calculate Move List | ||
| sub_mc_idx=cell_sim_chunk_idx{sub_point_idx}; | ||
| num_mc_idx=length(sub_mc_idx); | ||
| num_bs=length(bs_azimuth); | ||
| sub_array_agg_check_mc_dBm=NaN(num_mc_idx,1); | ||
|
|
||
| % ------------------------------------------------------------------------- | ||
| % STEP 1: Deterministic MC random precompute (seed identity preserved). | ||
| % rand_*_all dimensions: [num_bs x num_mc_idx] | ||
| % ------------------------------------------------------------------------- | ||
| rel_min=min(agg_check_reliability); | ||
| rel_max=max(agg_check_reliability); | ||
|
|
||
| if rel_min==rel_max | ||
| rand_pr_all=repmat(rel_min,num_bs,num_mc_idx); | ||
| rand_eirp_all=rand_pr_all; | ||
| rand_clutter_all=rand_pr_all; | ||
| else | ||
| rand_pr_all=NaN(num_bs,num_mc_idx); | ||
| rand_eirp_all=NaN(num_bs,num_mc_idx); | ||
| rand_clutter_all=NaN(num_bs,num_mc_idx); | ||
|
|
||
| for loop_idx=1:1:num_mc_idx | ||
| mc_iter=sub_mc_idx(loop_idx); | ||
|
|
||
| rng(rand_seed1+mc_iter); % PR draw identity | ||
| rand_pr_all(:,loop_idx)=rand(num_bs,1)*(rel_max-rel_min)+rel_min; | ||
|
|
||
| rng(rand_seed1+mc_iter+1); % EIRP draw identity | ||
| rand_eirp_all(:,loop_idx)=rand(num_bs,1)*(rel_max-rel_min)+rel_min; | ||
|
|
||
| rng(rand_seed1+mc_iter+2); % Clutter draw identity | ||
| rand_clutter_all(:,loop_idx)=rand(num_bs,1)*(rel_max-rel_min)+rel_min; | ||
| end | ||
| end | ||
|
|
||
| % ------------------------------------------------------------------------- | ||
| % STEP 2: Precompute off-axis gain matrix once for all (bs,sim_azimuth). | ||
| % off_axis_gain_matrix dimensions: [num_bs x num_sim_azi] | ||
| % Nearest-neighbor behavior mirrors rev9 path. | ||
| % ------------------------------------------------------------------------- | ||
| pat_az=mod(custom_antenna_pattern(:,1),360); | ||
| pat_gain=custom_antenna_pattern(:,2); | ||
|
|
||
| [pat_az_unique,ia_unique]=unique(pat_az,'stable'); | ||
| pat_gain_unique=pat_gain(ia_unique); | ||
|
|
||
| off_axis_gain_matrix=NaN(num_bs,num_sim_azi); | ||
| for azimuth_idx=1:1:num_sim_azi | ||
| sim_azimuth=array_sim_azimuth(azimuth_idx); | ||
| rel_az=mod(bs_azimuth-sim_azimuth,360); | ||
| ant_deg_idx=nearestpoint_app(app,rel_az,pat_az_unique); | ||
| off_axis_gain_matrix(:,azimuth_idx)=pat_gain_unique(ant_deg_idx); | ||
| end | ||
|
|
||
| if DEBUG_CHECKS && any(isnan(off_axis_gain_matrix),'all') | ||
| error('Inside Agg Check Rev10: NaN Error: off_axis_gain_matrix'); | ||
| end | ||
|
|
||
| % ------------------------------------------------------------------------- | ||
| % STEP 3/4: Compute MC terms with RNG-free rev helpers. | ||
| % ------------------------------------------------------------------------- | ||
| sort_monte_carlo_pr_dBm_all=NaN(num_bs,num_mc_idx); | ||
| for loop_idx=1:1:num_mc_idx | ||
| pre_sort_monte_carlo_pr_dBm=monte_carlo_Pr_dBm_rev2_app(app,agg_check_reliability,on_full_Pr_dBm,rand_pr_all(:,loop_idx)); | ||
| rand_norm_eirp=monte_carlo_super_bs_eirp_dist_rev5(app,super_array_bs_eirp_dist,agg_check_reliability,rand_eirp_all(:,loop_idx)); | ||
| monte_carlo_clutter_loss=monte_carlo_clutter_rev3_app(app,agg_check_reliability,clutter_loss,rand_clutter_all(:,loop_idx)); | ||
|
|
||
| sort_monte_carlo_pr_dBm_all(:,loop_idx)=pre_sort_monte_carlo_pr_dBm+rand_norm_eirp-monte_carlo_clutter_loss; | ||
| end | ||
|
|
||
| % ------------------------------------------------------------------------- | ||
| % STEP 5: Aggregate across full azimuth set in one pass (no azi_chunk loop). | ||
| % Keep MC loop for deterministic RNG/regression safety. | ||
| % ------------------------------------------------------------------------- | ||
| for loop_idx=1:1:num_mc_idx | ||
| base_mc=sort_monte_carlo_pr_dBm_all(:,loop_idx); | ||
| sort_temp_mc_dBm=base_mc+off_axis_gain_matrix; | ||
|
|
||
| if DEBUG_CHECKS && any(isnan(sort_temp_mc_dBm),'all') | ||
| error('Inside Agg Check Rev10: NaN Error: sort_temp_mc_dBm'); | ||
| end | ||
|
|
||
| % Keep numeric path equivalent to rev9 while removing chunk overhead. | ||
| binary_sort_mc_watts=db2pow(sort_temp_mc_dBm)/1000; | ||
|
|
||
| if DEBUG_CHECKS && any(isnan(binary_sort_mc_watts),'all') | ||
| error('Inside Agg Check Rev10: NaN Error: binary_sort_mc_watts'); | ||
| end | ||
|
|
||
| agg_dBm=pow2db(sum(binary_sort_mc_watts,1,"omitnan")*1000); | ||
| sub_array_agg_check_mc_dBm(loop_idx,1)=max(agg_dBm); | ||
| end | ||
|
|
||
| %%%%%%%%%%We can max azimuths -->sub_array_agg_check_mc_dBm=NaN(num_mc_idx,num_sim_azi); | ||
|
|
||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| function results = validate_subchunk_agg_check_maxazi_rev10() | ||
| %VALIDATE_SUBCHUNK_AGG_CHECK_MAXAZI_REV10 Deterministic regression harness for rev9 vs rev10. | ||
| % This harness validates output equivalence, structural invariants, and runtime. | ||
| % NOTE: Intermediate checkpoint comparison inside target functions is not added here, | ||
| % because exposing internal arrays (e.g., off_axis_gain_matrix and MC terms) would | ||
| % require invasive API/debug-surface changes. This harness stays non-invasive. | ||
|
|
||
| rng(20260327,'twister'); % fixed harness seed | ||
|
|
||
| cases = { ... | ||
| make_case('small', 16, 9, 45, 1, 6), ... | ||
| make_case('medium', 64, 41, 10, 1, 9), ... | ||
| make_case('large', 96, 73, 5, 1, 12) ... | ||
| }; | ||
|
|
||
| tol = 1e-10; | ||
| results = struct('case_name',{},'size_match',{},'column_shape_match',{}, ... | ||
| 'nan_pattern_match',{},'inf_pattern_match',{},'max_abs_diff',{}, ... | ||
| 'max_rel_diff',{},'runtime_rev9_s',{},'runtime_rev10_s',{},'speedup',{}, ... | ||
| 'rev9_reproducible',{},'rev10_reproducible',{},'pass',{}); | ||
|
|
||
| for k = 1:numel(cases) | ||
| c = cases{k}; | ||
| args = c.args; | ||
|
|
||
| out_rev9_a = subchunk_agg_check_maxazi_rev9(args{:}); | ||
| out_rev10_a = subchunk_agg_check_maxazi_rev10(args{:}); | ||
|
|
||
| % deterministic reproducibility checks | ||
| out_rev9_b = subchunk_agg_check_maxazi_rev9(args{:}); | ||
| out_rev10_b = subchunk_agg_check_maxazi_rev10(args{:}); | ||
|
|
||
| size_match = isequal(size(out_rev9_a), size(out_rev10_a)); | ||
| expected_shape = [numel(c.sub_mc_idx), 1]; | ||
| column_shape_match = isequal(size(out_rev9_a), expected_shape) && isequal(size(out_rev10_a), expected_shape); | ||
| nan_pattern_match = isequal(isnan(out_rev9_a), isnan(out_rev10_a)); | ||
| inf_pattern_match = isequal(isinf(out_rev9_a), isinf(out_rev10_a)); | ||
|
|
||
| denom = max(abs(out_rev9_a), 1e-12); | ||
| abs_diff = abs(out_rev9_a - out_rev10_a); | ||
| rel_diff = abs_diff ./ denom; | ||
| max_abs_diff = max(abs_diff,[],'all'); | ||
| max_rel_diff = max(rel_diff,[],'all'); | ||
|
Comment on lines
+40
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The harness computes Useful? React with 👍 / 👎. |
||
|
|
||
| rev9_reproducible = isequaln(out_rev9_a, out_rev9_b); | ||
| rev10_reproducible = isequaln(out_rev10_a, out_rev10_b); | ||
|
|
||
| % runtime via timeit when available | ||
| runtime_rev9_s = NaN; | ||
| runtime_rev10_s = NaN; | ||
| speedup = NaN; | ||
| if exist('timeit','file') == 2 | ||
| runtime_rev9_s = timeit(@() subchunk_agg_check_maxazi_rev9(args{:})); | ||
| runtime_rev10_s = timeit(@() subchunk_agg_check_maxazi_rev10(args{:})); | ||
| speedup = runtime_rev9_s / runtime_rev10_s; | ||
| else | ||
| t = tic; subchunk_agg_check_maxazi_rev9(args{:}); runtime_rev9_s = toc(t); | ||
| t = tic; subchunk_agg_check_maxazi_rev10(args{:}); runtime_rev10_s = toc(t); | ||
| speedup = runtime_rev9_s / runtime_rev10_s; | ||
| end | ||
|
|
||
| pass = size_match && column_shape_match && nan_pattern_match && inf_pattern_match && ... | ||
| rev9_reproducible && rev10_reproducible && ... | ||
| (max_abs_diff <= tol) && (max_rel_diff <= tol); | ||
|
|
||
| fprintf('\n--- VALIDATION SUMMARY ---\n'); | ||
| fprintf('Case: %s\n', c.name); | ||
| fprintf('Output Size Match: %d\n', size_match); | ||
| fprintf('Column Shape Match: %d\n', column_shape_match); | ||
| fprintf('NaN Pattern Match: %d\n', nan_pattern_match); | ||
| fprintf('Inf Pattern Match: %d\n', inf_pattern_match); | ||
| fprintf('Rev9 Reproducible: %d\n', rev9_reproducible); | ||
| fprintf('Rev10 Reproducible: %d\n', rev10_reproducible); | ||
| fprintf('Max Abs Diff: %.12g\n', max_abs_diff); | ||
| fprintf('Max Rel Diff: %.12g\n', max_rel_diff); | ||
| fprintf('Tolerance: %.3e\n', tol); | ||
| fprintf('Runtime Rev9: %.6f s\n', runtime_rev9_s); | ||
| fprintf('Runtime Rev10: %.6f s\n', runtime_rev10_s); | ||
| fprintf('Speedup: %.4fx\n', speedup); | ||
| fprintf('Result: %s\n', ternary(pass,'PASS','FAIL')); | ||
|
|
||
| if ~pass | ||
| error('Validation failed: rev10 does not match rev9 within tolerance (case: %s).', c.name); | ||
| end | ||
|
|
||
| results(k).case_name = c.name; | ||
| results(k).size_match = size_match; | ||
| results(k).column_shape_match = column_shape_match; | ||
| results(k).nan_pattern_match = nan_pattern_match; | ||
| results(k).inf_pattern_match = inf_pattern_match; | ||
| results(k).max_abs_diff = max_abs_diff; | ||
| results(k).max_rel_diff = max_rel_diff; | ||
| results(k).runtime_rev9_s = runtime_rev9_s; | ||
| results(k).runtime_rev10_s = runtime_rev10_s; | ||
| results(k).speedup = speedup; | ||
| results(k).rev9_reproducible = rev9_reproducible; | ||
| results(k).rev10_reproducible = rev10_reproducible; | ||
| results(k).pass = pass; | ||
| end | ||
|
|
||
| end | ||
|
|
||
| function c = make_case(name, num_bs, num_mc, radar_beamwidth, point_idx, seed_offset) | ||
| % Build deterministic synthetic inputs representative of production dimensions. | ||
|
|
||
| rng(1000 + seed_offset,'twister'); | ||
|
|
||
| app = []; %#ok<NASGU> | ||
|
|
||
| % reliability grid and distributions (strictly monotonic reliability). | ||
| agg_check_reliability = [0.1 0.5 0.9 0.99]; | ||
| num_rel = numel(agg_check_reliability); | ||
|
|
||
| aas_dist_azimuth = (0:5:355).'; | ||
| array_aas_dist_data = -30 + 10*rand(numel(aas_dist_azimuth), num_rel); | ||
| cell_aas_dist_data = {aas_dist_azimuth, array_aas_dist_data}; | ||
|
|
||
| array_bs_azi_data = zeros(num_bs, 4); | ||
| array_bs_azi_data(:,4) = mod(360*rand(num_bs,1), 360); | ||
|
|
||
| min_azimuth = 0; | ||
| max_azimuth = 355; | ||
|
|
||
| base_protection_pts = [37.2 -76.5; 38.9 -77.0; 34.1 -118.2]; | ||
| on_list_bs = [ ... | ||
| 25 + 20*rand(num_bs,1), ... | ||
| -125 + 55*rand(num_bs,1) ... | ||
| ]; | ||
|
|
||
| cell_sim_chunk_idx = {1:num_mc}; | ||
| rand_seed1 = 12345 + seed_offset; | ||
|
|
||
| on_full_Pr_dBm = -140 + 60*rand(num_bs, num_rel); | ||
| clutter_loss = 5 + 25*rand(num_bs, num_rel); | ||
|
|
||
| pat_az = (0:359).'; | ||
| pat_gain = -min(abs(pat_az), abs(pat_az-360))/3; % smooth deterministic pattern | ||
| custom_antenna_pattern = [pat_az, pat_gain]; | ||
|
|
||
| sub_point_idx = 1; | ||
|
|
||
| args = {[],cell_aas_dist_data,array_bs_azi_data,radar_beamwidth,min_azimuth,max_azimuth, ... | ||
| base_protection_pts,point_idx,on_list_bs,cell_sim_chunk_idx,rand_seed1,agg_check_reliability, ... | ||
| on_full_Pr_dBm,clutter_loss,custom_antenna_pattern,sub_point_idx}; | ||
|
|
||
| c = struct(); | ||
| c.name = name; | ||
| c.args = args; | ||
| c.sub_mc_idx = cell_sim_chunk_idx{sub_point_idx}; | ||
| end | ||
|
|
||
| function out = ternary(cond, a, b) | ||
| if cond | ||
| out = a; | ||
| else | ||
| out = b; | ||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This revision computes
base_mc + off_axis_gain_matrixfor the full azimuth set on every Monte Carlo iteration, which raises peak temporary memory fromO(num_bs*azi_chunk)in rev9 toO(num_bs*num_sim_azi). For larger production shapes (many BS rows and fine beamwidths), this can trigger out-of-memory failures on workers even though rev9’s chunked loop completed, so the refactor is not regression-safe under high-load inputs.Useful? React with 👍 / 👎.