1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2025-present FERS Contributors (see AUTHORS.md).
4import { create } from 'zustand';
6export type SimulationProgressState = {
10 details?: SimulationProgressDetail[];
13export type SimulationProgressDetail = {
20export type SimulationRunStatus = 'idle' | 'running' | 'completed' | 'failed';
22export type SimulationOutputMode = 'pulsed' | 'cw' | 'fmcw' | 'sfcw';
24export type SimulationOutputChunkMetadata = {
31 sample_end_exclusive: number;
34export type SimulationOutputStreamingSegmentMetadata = {
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 first_sfcw_step_start_time?: number;
45 emitted_sfcw_step_count?: number;
48export type SimulationOutputFmcwMetadata = {
49 waveform_shape?: 'linear' | 'triangle' | 'file';
50 chirp_bandwidth: number;
51 chirp_duration: number;
53 start_frequency_offset: number;
54 chirp_period?: number;
55 chirp_rate_signed?: number;
56 chirp_direction?: 'up' | 'down';
58 triangle_period?: number;
59 triangle_count?: number;
60 sampled_duration?: number;
61 sampled_count?: number;
64export type SimulationOutputFmcwSourceSegmentMetadata = {
67 first_chirp_start_time?: number;
68 emitted_chirp_count?: number;
69 first_triangle_start_time?: number;
70 emitted_triangle_count?: number;
73export type SimulationOutputFmcwSourceMetadata =
74 SimulationOutputFmcwMetadata & {
75 transmitter_id: number;
76 transmitter_name: string;
78 waveform_name: string;
79 carrier_frequency: number;
80 segments: SimulationOutputFmcwSourceSegmentMetadata[];
83export type SimulationOutputSfcwMetadata = {
84 carrier_frequency: number;
85 start_frequency_offset: number;
91 first_frequency: number;
92 last_frequency: number;
93 frequency_span: number;
94 effective_bandwidth: number;
95 range_resolution: number;
96 unambiguous_range: number;
99export type SimulationOutputSfcwSourceSegmentMetadata = {
102 first_step_start_time?: number;
103 emitted_step_count?: number;
106export type SimulationOutputSfcwSourceMetadata =
107 SimulationOutputSfcwMetadata & {
108 transmitter_id: number;
109 transmitter_name: string;
111 waveform_name: string;
112 segments: SimulationOutputSfcwSourceSegmentMetadata[];
115export type SimulationOutputVita49Timestamp = {
116 integer_seconds: number;
117 fractional_picoseconds: number;
120export type SimulationOutputVita49StreamMetadata = {
122 receiver_name: string;
126 reference_frequency: number;
127 packets_emitted: number;
128 samples_emitted: number;
129 packets_dropped: number;
130 samples_dropped: number;
131 over_range_count: number;
132 late_data_packet_count: number;
133 late_context_packet_count: number;
134 context_packet_count: number;
135 first_sample_time: number | null;
136 end_sample_time: number | null;
137 first_timestamp: SimulationOutputVita49Timestamp | null;
138 end_timestamp: SimulationOutputVita49Timestamp | null;
141export type SimulationOutputVita49Metadata = {
143 endpoint_host: string;
144 endpoint_port: number;
145 epoch_unix_nanoseconds: string | null;
147 adc_fullscale: number;
148 max_udp_payload: number;
150 streams: SimulationOutputVita49StreamMetadata[];
153export type SimulationOutputFileMetadata = {
155 receiver_name: string;
156 mode: SimulationOutputMode;
158 sampling_rate: number;
159 total_samples: number;
160 sample_start: number;
161 sample_end_exclusive: number;
163 min_pulse_length_samples: number;
164 max_pulse_length_samples: number;
165 uniform_pulse_length: boolean;
166 chunks: SimulationOutputChunkMetadata[];
167 streaming_segments: SimulationOutputStreamingSegmentMetadata[];
168 fmcw?: SimulationOutputFmcwMetadata;
169 fmcw_sources: SimulationOutputFmcwSourceMetadata[];
170 sfcw?: SimulationOutputSfcwMetadata;
171 sfcw_sources: SimulationOutputSfcwSourceMetadata[];
172 fmcw_dechirp_mode?: 'none' | 'physical' | 'ideal';
173 fmcw_dechirp_reference_source?:
178 fmcw_dechirp_reference_transmitter_id?: number;
179 fmcw_dechirp_reference_transmitter_name?: string;
180 fmcw_dechirp_reference_waveform_id?: number;
181 fmcw_dechirp_reference_waveform_name?: string;
182 fmcw_dechirp_reference_waveform?: SimulationOutputFmcwMetadata;
185export type SimulationOutputMetadata = {
186 schema_version: number;
187 simulation_name: string;
188 output_directory: string;
191 sampling_rate: number | null;
192 sampling_rates?: number[];
193 oversample_ratio: number;
194 files: SimulationOutputFileMetadata[];
195 vita49?: SimulationOutputVita49Metadata;
198export type RawSimulationOutputFileMetadata = Omit<
199 SimulationOutputFileMetadata,
200 'sampling_rate' | 'streaming_segments' | 'fmcw_sources' | 'sfcw_sources'
202 sampling_rate?: number;
203 streaming_segments?: SimulationOutputStreamingSegmentMetadata[];
204 cw_segments?: SimulationOutputStreamingSegmentMetadata[];
205 fmcw_sources?: SimulationOutputFmcwSourceMetadata[];
206 sfcw_sources?: SimulationOutputSfcwSourceMetadata[];
209export type RawSimulationOutputMetadata = Omit<
210 SimulationOutputMetadata,
213 files: RawSimulationOutputFileMetadata[];
216export const normalizeSimulationOutputMetadata = (
217 metadata: RawSimulationOutputMetadata
218): SimulationOutputMetadata => ({
220 files: metadata.files.map((file) => {
233 metadata.sampling_rate ??
234 metadata.sampling_rates?.[0] ??
236 streaming_segments: streaming_segments ?? cw_segments ?? [],
237 fmcw_sources: fmcw_sources ?? [],
238 sfcw_sources: sfcw_sources ?? [],
243type SimulationProgressStore = {
244 isSimulating: boolean;
245 isGeneratingKml: boolean;
246 simulationProgress: Record<string, SimulationProgressState>;
247 simulationRunStatus: SimulationRunStatus;
248 simulationRunError: string | null;
249 simulationOutputMetadata: SimulationOutputMetadata | null;
251 setIsSimulating: (isSimulating: boolean) => void;
252 setIsGeneratingKml: (isGeneratingKml: boolean) => void;
253 startSimulationRun: () => void;
254 setSimulationProgressSnapshot: (
255 progress: Record<string, SimulationProgressState>
257 setSimulationOutputMetadata: (
258 metadata: SimulationOutputMetadata | null
260 completeSimulationRun: () => void;
261 failSimulationRun: (errorMessage: string) => void;
262 clearSimulationProgress: () => void;
265export const useSimulationProgressStore = create<SimulationProgressStore>()(
268 isGeneratingKml: false,
269 simulationProgress: {},
270 simulationRunStatus: 'idle',
271 simulationRunError: null,
272 simulationOutputMetadata: null,
274 setIsSimulating: (isSimulating) => set({ isSimulating }),
275 setIsGeneratingKml: (isGeneratingKml) => set({ isGeneratingKml }),
276 startSimulationRun: () =>
279 simulationProgress: {},
280 simulationRunStatus: 'running',
281 simulationRunError: null,
282 simulationOutputMetadata: null,
284 setSimulationProgressSnapshot: (progress) =>
285 set({ simulationProgress: progress }),
286 setSimulationOutputMetadata: (metadata) =>
287 set({ simulationOutputMetadata: metadata }),
288 completeSimulationRun: () =>
291 simulationRunStatus: 'completed',
292 simulationRunError: null,
294 failSimulationRun: (errorMessage) =>
297 simulationRunStatus: 'failed',
298 simulationRunError: errorMessage,
300 clearSimulationProgress: () =>
302 simulationProgress: {},
303 simulationRunStatus: 'idle',
304 simulationRunError: null,
305 simulationOutputMetadata: null,