Synchronization between simulated devices is modeled by Trigger Models. Simulated device instances sharing the same Trigger Model instance are considered time-synchronized with each other, but not with other simulated devices that do not share the same Trigger Model.

%%{init: {"flowchart":{"useMaxWidth": false}}}%% flowchart LR subgraph Synchronization direction TB trigger[TriggerModel] --> trigger_realization[TriggerRealization] end device_a[Simulated Device] device_b[         ⋮         ]:::invis device_c[Simulated Device] trigger_realization --> device_a trigger_realization --> device_b trigger_realization --> device_c classDef invis fill-opacity:0,stroke-opacity:0,font-weight:bold; click trigger href "simulation.synchronization.TriggerModel.html" click trigger_realization href "simulation.synchronization.TriggerRealization.html" click device_a href "simulation.simulated_device.html" click device_b href "simulation.simulated_device.html" click device_c href "simulation.simulated_device.html"

During the generation of each simulation drop, the Trigger Model instance is realized once for all simulated devices sharing the same instance, resulting in a single Trigger Realization.

Note that, as the name suggests, HermesPy’s synchronization model is considered to be at the trigger level of transmitting and receiving devices, meaning propagation delays due to channel models linking synchronized devices must still be compensated by appropriate equalization routines. The currently available Trigger Model implementations are:

Trigger Model


Random Trigger

Random triggering within a given time interval.

Sample Offset Trigger

Static triggering at a given sample offset.

Time Offset Trigger

Static triggering at a given time offset.

Static Trigger

Static triggering with no offset. This is the default.

Consider a scenario featuring four wireless devices, with two devices respectively linked, interfering with each other on partially overlapping frequency bands.

 1# Create a new simulation featuring two sets of two linked, synchronized devices
 2simulation = Simulation()
 4# Create devices
 5device_A_Tx = simulation.new_device(carrier_frequency=3.7e9)
 6device_A_Rx = simulation.new_device(carrier_frequency=3.7e9)
 7device_B_Tx = simulation.new_device(carrier_frequency=3.9e9)
 8device_B_Rx = simulation.new_device(carrier_frequency=3.9e9)
10# Specify a root-raised cosine single carrier waveform
11waveform = RootRaisedCosineWaveform(
12    symbol_rate=400e6,
13    oversampling_factor=4,
14    roll_off=.9,
15    num_preamble_symbols=0,
16    num_data_symbols=1024,
17    pilot_rate=7,
19waveform.channel_estimation = SingleCarrierLeastSquaresChannelEstimation()
20waveform.channel_equalization = SingleCarrierMinimumMeanSquareChannelEqualization()
22# Link devices
23link_A = SimplexLink(device_A_Tx, device_A_Rx, waveform=deepcopy(waveform))
24link_B = SimplexLink(device_B_Tx, device_B_Rx, waveform=deepcopy(waveform))

The exchanged waveforms are identical, however, devices are considered to be only synchronized to their linked partners.

1# Specify trigger models
2trigger_model_A = TriggerModel()
3device_A_Tx.trigger_model = trigger_model_A
4device_A_Rx.trigger_model = trigger_model_A
6trigger_model_B = TriggerModel()
7device_B_Tx.trigger_model = trigger_model_B
8device_B_Rx.trigger_model = trigger_model_B

Of course, the abstract TriggerModel in the above snippet must be replaced by the desired implementation from the list above. By generating a single drop of the simulation and plotting the bit error rates of the two devices, we may visualize the impact of partially overlapping commuication frames in time-domain due to the interference in between the two links.

 1# Configure BER evaluators for each link
 2ber_A = BitErrorEvaluator(link_A, link_A)
 3ber_B = BitErrorEvaluator(link_B, link_B)
 5# Generate drop
 6_ = simulation.scenario.drop()
 8# Visualize BERs that should spike at the frame overlaps
 9ber_A.evaluate().visualize(title='Link A Bit Error Rate')
10ber_B.evaluate().visualize(title='Link B Bit Error Rate')