SimTX API/Packets/IqBlock: Difference between revisions
Appearance
Clanker moved page SimTX API/Packets/IqBlock to SimTX API v24/Packets/IqBlock: Archive the v24 protocol reference Tag: New redirect |
Remove development history and server internals |
||
| (One intermediate revision by the same user not shown) | |||
| Line 1: | Line 1: | ||
{{SimTX API navigation}} | |||
{{SimTX packet | |||
| name = IqBlock | |||
| frame = ServerFrame | |||
| field = 12 | |||
| member = iq | |||
| direction = s2c | |||
| session = [[SimTX API/Receiver session|Receiver]] | |||
| roles = <code>ROLE_RECEIVER</code>. | |||
| permission = None | |||
| group = receiver | |||
| file = session.proto | |||
}} | |||
'''IqBlock''' carries one block of received complex baseband samples. A receiver gets a continuous stream of them after the [[SimTX API/Packets/IqStreamDescriptor|IqStreamDescriptor]], at the rate of the simulation. With <code>timestamped</code> set in the [[SimTX API/Packets/ReceiverStart|ReceiverStart]], every block also carries the UTC instant of its first sample. | |||
== Definition == | |||
<syntaxhighlight lang="protobuf"> | |||
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; | |||
} | |||
</syntaxhighlight> | |||
== Fields == | |||
{| class="wikitable" | |||
! # !! Field !! Type !! Description | |||
|- | |||
| 1 || <code>scale</code> || <code>float</code> || Scale of this block: the peak component magnitude, at least 10<sup>−9</sup>. | |||
|- | |||
| 2 || <code>samples</code> || <code>bytes</code> || <code>chunk_samples</code> × (I, Q), interleaved, big-endian <code>int16</code> (or <code>int8</code>). Length is exactly <code>chunk_samples × 2 × 2</code> (or <code>× 1</code>) bytes. | |||
|- | |||
| 3 || <code>first_sample_epoch_seconds</code> || <code>int64</code> || Timestamped streams only: UTC instant of the first sample on the server's RF timeline, Unix seconds. | |||
|- | |||
| 4 || <code>first_sample_nanos</code> || <code>int32</code> || Nanoseconds added to <code>first_sample_epoch_seconds</code>. | |||
|- | |||
| 5 || <code>sequence</code> || <code>fixed64</code> || 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 == | |||
<syntaxhighlight lang="text"> | |||
I = i_raw × scale / 32767 (INT16; use 127 for INT8) | |||
Q = q_raw × scale / 32767 | |||
</syntaxhighlight> | |||
* The sample bytes are big-endian, unlike the rest of the frame, which follows protobuf encoding. | |||
* Check that <code>samples</code> is exactly <code>chunk_samples × 2 × bytesPerComponent</code> bytes long and treat anything else as a protocol error. | |||
* <code>scale</code> is the block's peak component magnitude. The server quantises each component as <code>round(x × 32767 / scale)</code>, 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. | |||
* <code>sequence</code> counts 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. | |||
* <code>sequence</code> is a <code>fixed64</code>, 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. | |||
'''<code>iq_block_int16</code>''' (server to client, 27 bytes): | |||
<syntaxhighlight lang="text"> | |||
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 | |||
</syntaxhighlight> | |||
'''<code>iq_block_int16_timestamped</code>''' (server to client, 38 bytes): | |||
<syntaxhighlight lang="text"> | |||
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 | |||
</syntaxhighlight> | |||
== See also == | |||
* [[SimTX API/Receiver session#Decoding samples|Decoding samples]] | |||
* [[SimTX API/Quick start]] | |||
{{SimTX API navbox}} | |||
[[Category:SimTX API]] | |||
Latest revision as of 17:16, 24 October 2026
| 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[edit | edit source]
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[edit | edit source]
| # | 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[edit | edit source]
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[edit | edit source]
- 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[edit | edit source]
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