|
122 | 122 | end |
123 | 123 | end |
124 | 124 |
|
125 | | - |
126 | | -function needs_env = map_receivers_and_environments(receiver, options) |
127 | | - arguments |
128 | | - receiver { ... |
129 | | - nodes.mustBeReceiverOrTransmitter(receiver), ... |
130 | | - nodes.mustHaveDetector(receiver) } |
131 | | - options.Environment environment.Environment |
132 | | - end |
133 | | - |
134 | | - n_rx = numel(receiver); |
135 | | - n_env = 0; |
136 | | - have_environment = ismember(fieldnames(options), "Environment"); |
137 | | - if have_environment |
138 | | - n_env = numel(options.Environment); |
139 | | - end |
140 | | - |
141 | | - needs_env = arrayfun(@(maybe_has_env) isa(maybe_has_env, 'nodes.Ground_Station'), receiver); |
142 | | - |
143 | | - if n_rx >= n_env && n_env > 1 && have_environment |
144 | | - % convert logical values to indices |
145 | | - needs_env = needs_env .* cumsum(needs_env); |
146 | | - |
147 | | - % so we can catch them later set "0" values to -1 |
148 | | - needs_env(needs_env == 0) = -1; |
149 | | - |
150 | | - assert(max(needs_env) == numel(options.Environment), ... |
151 | | - [ ... |
152 | | - 'Number of receivers and environments do not match, either supply ', ... |
153 | | - 'a single environment for all receivers or an environment per receiver' ... |
154 | | - ]) |
155 | | - end |
156 | | -end |
157 | | - |
158 | | - |
159 | | -function [min_val, max_val] = extrema(array) |
160 | | - min_val = min(array); |
161 | | - max_val = max(array); |
162 | | -end |
163 | | - |
164 | | - |
165 | | -function loc_time = location_time(tx_idx, rx_idx, direction, heading, elevation, range, elev_limit, elev_mask, time) |
166 | | - arguments |
167 | | - tx_idx {mustBeNumeric} |
168 | | - rx_idx {mustBeNumeric} |
169 | | - direction nodes.LinkDirection |
170 | | - heading (1, :) {mustBeNumeric} |
171 | | - elevation (1, :) {mustBeNumeric} |
172 | | - range (1, :) {mustBeNumeric} |
173 | | - elev_limit {mustBeScalarOrEmpty, mustBeNumeric} |
174 | | - elev_mask (1, :) {mustBeNumericOrLogical} |
175 | | - time (1, :) {mustBeA(time, "datetime")} |
176 | | - end |
177 | | - |
178 | | - loc_time = struct( ... |
179 | | - "tx_idx", tx_idx, ... |
180 | | - "rx_idx", rx_idx, ... |
181 | | - "direction", direction, ... |
182 | | - "heading", heading, ... |
183 | | - "elevation", elevation, ... |
184 | | - "range", range, ... |
185 | | - "elevation_limit", elev_limit, ... |
186 | | - "elevation_mask", elev_mask, ... |
187 | | - "time", time); |
188 | | -end |
189 | | - |
190 | | - |
191 | | -function tt = timetable_for_elevation_window(rel_loc, elev_limit) |
192 | | - elev_mask = rel_loc.elevation > elev_limit; |
193 | | - if sum(elev_mask) < 1 |
194 | | - tt = []; |
195 | | - return |
196 | | - end |
197 | | - [t_min, t_max] = extrema(rel_loc.time(elev_mask)); |
198 | | - tt = timetable([t_min; t_max]); |
199 | | -end |
200 | | - |
201 | | - |
202 | | -function [single_link_idx, double_link_idx] = find_links(receivers, transmitters) |
203 | | - |
204 | | - arguments |
205 | | - receivers { ... |
206 | | - nodes.mustBeReceiverOrTransmitter(receivers), ... |
207 | | - nodes.mustHaveDetector(receivers) } |
208 | | - transmitters { ... |
209 | | - nodes.mustBeReceiverOrTransmitter(transmitters), ... |
210 | | - nodes.mustHaveSource(transmitters) } |
211 | | - end |
212 | | - |
213 | | - single_link_idx = {}; |
214 | | - double_link_idx = {}; |
215 | | - |
216 | | - n_receivers = numel(receivers); |
217 | | - |
218 | | - loc_time = struct( ... |
219 | | - "tx_idx", 0, ... |
220 | | - "rx_idx", 0, ... |
221 | | - "direction", nodes.LinkDirection.Downlink, ... |
222 | | - "heading", [], ... |
223 | | - "elevation", [], ... |
224 | | - "range", [], ... |
225 | | - "elevation_limit", 0, ... |
226 | | - "elevation_mask", [], ... |
227 | | - "time", []); |
228 | | - |
229 | | - % relative_locations = createArray(1, n_receivers, Like=loc_time(0, 0, [], [], [], [], [])); |
230 | | - % relative_locations = {}; |
231 | | - |
232 | | - for T = 1:numel(transmitters) |
233 | | - tx = transmitters(T); |
234 | | - i = 1; |
235 | | - valid_links = zeros(1, n_receivers); % for current transmitter |
236 | | - elevation_limits = zeros(1, n_receivers); |
237 | | - |
238 | | - % relative_locations = createArray(1, n_receivers, ... |
239 | | - % Like=loc_time(0, 0, 0, [], [], [], 0, [], [])); |
240 | | - |
241 | | - relative_locations = createArray(1, n_receivers, Like=loc_time); |
242 | | - for R = 1:numel(receivers) |
243 | | - rx = receivers(R); |
244 | | - direction = nodes.LinkDirection.DetermineLinkDirection(rx, tx); |
245 | | - |
246 | | - switch direction |
247 | | - case nodes.LinkDirection.Downlink |
248 | | - [h, e, r] = tx.RelativeHeadingAndElevation(rx); |
249 | | - limit = rx.Elevation_Limit; |
250 | | - elevation_limits(i) = limit; |
251 | | - elevation_limit_mask = e > elevation_limits(i); |
252 | | - rel_loc = location_time(T, R, direction, h, e, r, limit, elevation_limit_mask, tx.Times); |
253 | | - |
254 | | - case nodes.LinkDirection.Uplink |
255 | | - [h, e, r] = rx.RelativeHeadingAndElevation(tx); |
256 | | - limit = tx.Elevation_Limit; |
257 | | - elevation_limits(i) = limit; |
258 | | - elevation_limit_mask = e > elevation_limits(i); |
259 | | - rel_loc = location_time(T, R, direction, h, e, r, limit, elevation_limit_mask, rx.Times); |
260 | | - end |
261 | | - |
262 | | - % elevation_limit_mask = relative_locations(i).elevation > elevation_limits(i); |
263 | | - % if sum(elevation_limit_mask) > 0 |
264 | | - if sum(rel_loc.elevation_mask) > 0 |
265 | | - valid_links(i) = 1; |
266 | | - single_link_count = numel(single_link_idx) + 1; |
267 | | - single_link_idx{single_link_count} = rel_loc; |
268 | | - %relative_locations_count = numel(relative_locations) + 1; |
269 | | - % relative_locations{relative_locations_count} = rel_loc; |
270 | | - relative_locations(R) = rel_loc; |
271 | | - end |
272 | | - |
273 | | - i = i + 1; |
274 | | - end |
275 | | - |
276 | | - relative_locations = relative_locations(arrayfun(@(rl) ~isempty(rl.elevation), relative_locations)); |
277 | | - |
278 | | - %if sum(valid_links) < 2 |
279 | | - if numel(relative_locations) < 2 |
280 | | - % skip to next transmitter if there is one |
281 | | - continue |
282 | | - end |
283 | | - |
284 | | - %n = sum(valid_links); |
285 | | - n = numel(relative_locations); |
286 | | - for rx_pairs = nchoosek(linspace(1, n, n), 2)' |
287 | | - |
288 | | - rel_loc_i = relative_locations(rx_pairs(1)); |
289 | | - e_lim = elevation_limits(rx_pairs(1)); |
290 | | - tt_i = timetable_for_elevation_window(rel_loc_i, e_lim); |
291 | | - |
292 | | - rel_loc_j = relative_locations(rx_pairs(2)); |
293 | | - e_lim = elevation_limits(rx_pairs(2)); |
294 | | - tt_j = timetable_for_elevation_window(rel_loc_j, e_lim); |
295 | | - |
296 | | - if any([sum(size(tt_i)) < 1, sum(size(tt_j)) < 1]) |
297 | | - % one of the timetables is empty so it mustn't have seen the satellite |
298 | | - continue |
299 | | - end |
300 | | - |
301 | | - if ~overlapsrange(tt_i, tt_j) |
302 | | - %{ |
303 | | - skip to next pair |
304 | | - eventhough both rx, tx pairs could see each other they |
305 | | - couldn't see each other at the same time |
306 | | - %} |
307 | | - continue |
308 | | - end |
309 | | - |
310 | | - dl_idx = numel(double_link_idx) + 1; |
311 | | - % double_link_idx{dl_idx} = {T, rx_pairs(1), rx_pairs(2)}; % {transmitter, receiver_i, receivers_j} |
312 | | - double_link_idx{dl_idx} = {[rel_loc_i, rel_loc_j]}; |
313 | | - end |
314 | | - |
315 | | - end |
316 | | -end |
317 | | - |
318 | | - |
319 | 125 | function [loss_results, noise] = loss_and_noise_for_channel(transmitter, receiver, qkd_protocol) |
320 | 126 | arguments |
321 | 127 | transmitter (1,1) { ... |
|
0 commit comments