FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
simulationProgressStore.ts
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2025-present FERS Contributors (see AUTHORS.md).
3
4import { create } from 'zustand';
5
6export type SimulationProgressState = {
7 message: string;
8 current: number;
9 total: number;
10 details?: SimulationProgressDetail[];
11};
12
13export type SimulationProgressDetail = {
14 id: string;
15 message: string;
16 current: number;
17 total: number;
18};
19
20export type SimulationRunStatus = 'idle' | 'running' | 'completed' | 'failed';
21
22export type SimulationOutputMode = 'pulsed' | 'cw' | 'fmcw';
23
24export type SimulationOutputChunkMetadata = {
25 chunk_index: number;
26 i_dataset: string;
27 q_dataset: string;
28 start_time: number;
29 sample_count: number;
30 sample_start: number;
31 sample_end_exclusive: number;
32};
33
34export type SimulationOutputStreamingSegmentMetadata = {
35 start_time: number;
36 end_time: number;
37 sample_count: number;
38 sample_start: number;
39 sample_end_exclusive: number;
40 first_chirp_start_time?: number;
41 emitted_chirp_count?: number;
42 first_triangle_start_time?: number;
43 emitted_triangle_count?: number;
44};
45
46export type SimulationOutputFmcwMetadata = {
47 waveform_shape?: 'linear' | 'triangle';
48 chirp_bandwidth: number;
49 chirp_duration: number;
50 chirp_rate: number;
51 start_frequency_offset: number;
52 chirp_period?: number;
53 chirp_rate_signed?: number;
54 chirp_direction?: 'up' | 'down';
55 chirp_count?: number;
56 triangle_period?: number;
57 triangle_count?: number;
58};
59
60export type SimulationOutputFmcwSourceSegmentMetadata = {
61 start_time: number;
62 end_time: number;
63 first_chirp_start_time?: number;
64 emitted_chirp_count?: number;
65 first_triangle_start_time?: number;
66 emitted_triangle_count?: number;
67};
68
69export type SimulationOutputFmcwSourceMetadata =
70 SimulationOutputFmcwMetadata & {
71 transmitter_id: number;
72 transmitter_name: string;
73 waveform_id: number;
74 waveform_name: string;
75 carrier_frequency: number;
76 segments: SimulationOutputFmcwSourceSegmentMetadata[];
77 };
78
79export type SimulationOutputVita49Timestamp = {
80 integer_seconds: number;
81 fractional_picoseconds: number;
82};
83
84export type SimulationOutputVita49StreamMetadata = {
85 receiver_id: number;
86 receiver_name: string;
87 stream_id: number;
88 mode?: string;
89 sample_rate: number;
90 reference_frequency: number;
91 packets_emitted: number;
92 samples_emitted: number;
93 packets_dropped: number;
94 samples_dropped: number;
95 over_range_count: number;
96 late_packet_count: number;
97 context_packet_count: number;
98 first_sample_time: number | null;
99 end_sample_time: number | null;
100 first_timestamp: SimulationOutputVita49Timestamp | null;
101 end_timestamp: SimulationOutputVita49Timestamp | null;
102};
103
104export type SimulationOutputVita49Metadata = {
105 endpoint: string;
106 endpoint_host: string;
107 endpoint_port: number;
108 epoch_unix_nanoseconds: string | null;
109 class_id: string;
110 adc_fullscale: number;
111 max_udp_payload: number;
112 queue_depth: number;
113 streams: SimulationOutputVita49StreamMetadata[];
114};
115
116export type SimulationOutputFileMetadata = {
117 receiver_id: number;
118 receiver_name: string;
119 mode: SimulationOutputMode;
120 path: string;
121 sampling_rate: number;
122 total_samples: number;
123 sample_start: number;
124 sample_end_exclusive: number;
125 pulse_count: number;
126 min_pulse_length_samples: number;
127 max_pulse_length_samples: number;
128 uniform_pulse_length: boolean;
129 chunks: SimulationOutputChunkMetadata[];
130 streaming_segments: SimulationOutputStreamingSegmentMetadata[];
131 fmcw?: SimulationOutputFmcwMetadata;
132 fmcw_sources: SimulationOutputFmcwSourceMetadata[];
133 fmcw_dechirp_mode?: 'none' | 'physical' | 'ideal';
134 fmcw_dechirp_reference_source?:
135 | 'none'
136 | 'attached'
137 | 'transmitter'
138 | 'custom';
139 fmcw_dechirp_reference_transmitter_id?: number;
140 fmcw_dechirp_reference_transmitter_name?: string;
141 fmcw_dechirp_reference_waveform_id?: number;
142 fmcw_dechirp_reference_waveform_name?: string;
143 fmcw_dechirp_reference_waveform?: SimulationOutputFmcwMetadata;
144};
145
146export type SimulationOutputMetadata = {
147 schema_version: number;
148 simulation_name: string;
149 output_directory: string;
150 start_time: number;
151 end_time: number;
152 sampling_rate: number | null;
153 sampling_rates?: number[];
154 oversample_ratio: number;
155 files: SimulationOutputFileMetadata[];
156 vita49?: SimulationOutputVita49Metadata;
157};
158
159export type RawSimulationOutputFileMetadata = Omit<
160 SimulationOutputFileMetadata,
161 'sampling_rate' | 'streaming_segments' | 'fmcw_sources'
162> & {
163 sampling_rate?: number;
164 streaming_segments?: SimulationOutputStreamingSegmentMetadata[];
165 cw_segments?: SimulationOutputStreamingSegmentMetadata[];
166 fmcw_sources?: SimulationOutputFmcwSourceMetadata[];
167};
168
169export type RawSimulationOutputMetadata = Omit<
170 SimulationOutputMetadata,
171 'files'
172> & {
173 files: RawSimulationOutputFileMetadata[];
174};
175
176export const normalizeSimulationOutputMetadata = (
177 metadata: RawSimulationOutputMetadata
178): SimulationOutputMetadata => ({
179 ...metadata,
180 files: metadata.files.map((file) => {
181 const {
182 cw_segments,
183 streaming_segments,
184 fmcw_sources,
185 sampling_rate,
186 ...normalizedFile
187 } = file;
188 return {
189 ...normalizedFile,
190 sampling_rate:
191 sampling_rate ??
192 metadata.sampling_rate ??
193 metadata.sampling_rates?.[0] ??
194 0,
195 streaming_segments: streaming_segments ?? cw_segments ?? [],
196 fmcw_sources: fmcw_sources ?? [],
197 };
198 }),
199});
200
201type SimulationProgressStore = {
202 isSimulating: boolean;
203 isGeneratingKml: boolean;
204 simulationProgress: Record<string, SimulationProgressState>;
205 simulationRunStatus: SimulationRunStatus;
206 simulationRunError: string | null;
207 simulationOutputMetadata: SimulationOutputMetadata | null;
208
209 setIsSimulating: (isSimulating: boolean) => void;
210 setIsGeneratingKml: (isGeneratingKml: boolean) => void;
211 startSimulationRun: () => void;
212 setSimulationProgressSnapshot: (
213 progress: Record<string, SimulationProgressState>
214 ) => void;
215 setSimulationOutputMetadata: (
216 metadata: SimulationOutputMetadata | null
217 ) => void;
218 completeSimulationRun: () => void;
219 failSimulationRun: (errorMessage: string) => void;
220 clearSimulationProgress: () => void;
221};
222
223export const useSimulationProgressStore = create<SimulationProgressStore>()(
224 (set) => ({
225 isSimulating: false,
226 isGeneratingKml: false,
227 simulationProgress: {},
228 simulationRunStatus: 'idle',
229 simulationRunError: null,
230 simulationOutputMetadata: null,
231
232 setIsSimulating: (isSimulating) => set({ isSimulating }),
233 setIsGeneratingKml: (isGeneratingKml) => set({ isGeneratingKml }),
234 startSimulationRun: () =>
235 set({
236 isSimulating: true,
237 simulationProgress: {},
238 simulationRunStatus: 'running',
239 simulationRunError: null,
240 simulationOutputMetadata: null,
241 }),
242 setSimulationProgressSnapshot: (progress) =>
243 set({ simulationProgress: progress }),
244 setSimulationOutputMetadata: (metadata) =>
245 set({ simulationOutputMetadata: metadata }),
246 completeSimulationRun: () =>
247 set({
248 isSimulating: false,
249 simulationRunStatus: 'completed',
250 simulationRunError: null,
251 }),
252 failSimulationRun: (errorMessage) =>
253 set({
254 isSimulating: false,
255 simulationRunStatus: 'failed',
256 simulationRunError: errorMessage,
257 }),
258 clearSimulationProgress: () =>
259 set({
260 simulationProgress: {},
261 simulationRunStatus: 'idle',
262 simulationRunError: null,
263 simulationOutputMetadata: null,
264 }),
265 })
266);