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 |
Protocol v25 reference: IqBlock Tag: Removed redirect |
||
| 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; v24's separate TimedIqBlock is gone. | |||
== 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 as they would a real one. | |||
== 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 and moves between server nodes. 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, from the protocol's golden test vectors (<code>protocol/simtx/v25/testdata/frames.json</code>). | |||
'''<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]] | |||
Revision as of 16:58, 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; v24's separate TimedIqBlock is gone.
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 as they would a real one.
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 and moves between server nodes. 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, from the protocol's golden test vectors (protocol/simtx/v25/testdata/frames.json).
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