SimTX API/Packets/IqBlock
Appearance
| Frame | ServerFrame, field 12
|
|---|---|
| Member | iq
|
| Direction | Server → client |
| Session | Receiver |
| Roles | ROLE_RECEIVER.
|
| Permission | None |
| Defined in | session.proto
|
IqBlock carries one block of received complex baseband samples. A receiver gets a continuous stream of them after the IqStreamDescriptor, at the rate of the simulation. With timestamped set in the ReceiverStart, every block also carries the UTC instant of its first sample.
Definition
message IqBlock {
float scale = 1;
bytes samples = 2;
int64 first_sample_epoch_seconds = 3; // timestamped streams only
int32 first_sample_nanos = 4;
fixed64 sequence = 5;
}
Fields
| # | Field | Type | Description |
|---|---|---|---|
| 1 | scale |
float |
Scale of this block: the peak component magnitude, at least 10−9. |
| 2 | samples |
bytes |
chunk_samples × (I, Q), interleaved, big-endian int16 (or int8). Length is exactly chunk_samples × 2 × 2 (or × 1) bytes.
|
| 3 | first_sample_epoch_seconds |
int64 |
Timestamped streams only: UTC instant of the first sample on the server's RF timeline, Unix seconds. |
| 4 | first_sample_nanos |
int32 |
Nanoseconds added to first_sample_epoch_seconds.
|
| 5 | sequence |
fixed64 |
Block number within the stream: 1 for the first block, +1 for each block after it. A step larger than 1 means blocks were dropped. 0 = the sender does not number blocks. |
Decoding
I = i_raw × scale / 32767 (INT16; use 127 for INT8)
Q = q_raw × scale / 32767
- The sample bytes are big-endian, unlike the rest of the frame, which follows protobuf encoding.
- Check that
samplesis exactlychunk_samples × 2 × bytesPerComponentbytes long and treat anything else as a protocol error. scaleis the block's peak component magnitude. The server quantises each component asround(x × 32767 / scale), so the integers always use the full range.- A magnitude of 1.0 is −12 dBm at the receiver input. Components are clipped at ±1.0 before quantisation, so strong signals overload the receiver.
Delivery
- Blocks are sent in real time. The server queues at most 8 blocks per connection and drops the oldest when the queue is full.
sequencecounts blocks from 1 and continues across retunes. A step larger than 1 means blocks were dropped. A sender that does not number blocks sends 0.sequenceis afixed64, so it occupies 9 bytes of the frame (tag and 8 bytes) even when small.- A client that does not read for 5 seconds is disconnected.
Examples
Complete frames, including the varint length prefix.
iq_block_int16 (server to client, 27 bytes):
1A frame length 26
62 18 iq (IqBlock), 24 bytes
0D 00 00 00 3F scale = 0.5
12 08 7F FF 80 01 40 00 C0 00 samples, 8 bytes
29 01 00 00 00 00 00 00 00 sequence = 1
iq_block_int16_timestamped (server to client, 38 bytes):
25 frame length 37
62 23 iq (IqBlock), 35 bytes
0D 00 00 00 3F scale = 0.5
12 08 7F FF 80 01 40 00 C0 00 samples, 8 bytes
18 C0 84 FC D6 06 first_sample_epoch_seconds = 1793000000
20 95 9A EF 3A first_sample_nanos = 123456789
29 02 00 00 00 00 00 00 00 sequence = 2