nexrad_decode/messages/volume_coverage_pattern/
elevation_data_block.rs1use serde::Deserialize;
2use std::fmt::Debug;
3
4use crate::messages::primitive_aliases::{Code1, Code2, Integer1, Integer2, ScaledSInteger2};
5use crate::messages::volume_coverage_pattern::definitions::{ChannelConfiguration, WaveformType};
6
7#[cfg(feature = "uom")]
8use uom::si::{
9 angle::degree,
10 angular_velocity::degree_per_second,
11 f64::{Angle, AngularVelocity},
12};
13
14#[derive(Clone, PartialEq, Deserialize)]
16pub struct ElevationDataBlock {
17 pub elevation_angle: Code2,
19
20 pub channel_configuration: Code1,
25
26 pub waveform_type: Code1,
33
34 pub super_resolution_control: Code1,
40
41 pub surveillance_prf_number: Integer1,
43
44 pub surveillance_prf_pulse_count_radial: Integer2,
46
47 pub azimuth_rate: Code2,
49
50 pub reflectivity_threshold: ScaledSInteger2,
52
53 pub velocity_threshold: ScaledSInteger2,
55
56 pub spectrum_width_threshold: ScaledSInteger2,
58
59 pub differential_reflectivity_threshold: ScaledSInteger2,
61
62 pub differential_phase_threshold: ScaledSInteger2,
64
65 pub correlation_coefficient_threshold: ScaledSInteger2,
67
68 pub sector_1_edge_angle: Code2,
70
71 pub sector_1_doppler_prf_number: Integer2,
73
74 pub sector_1_doppler_prf_pulse_count_radial: Integer2,
76
77 pub supplemental_data: Code2,
86
87 pub sector_2_edge_angle: Code2,
89
90 pub sector_2_doppler_prf_number: Integer2,
92
93 pub sector_2_doppler_prf_pulse_count_radial: Integer2,
95
96 pub ebc_angle: Code2,
98
99 pub sector_3_edge_angle: Code2,
101
102 pub sector_3_doppler_prf_number: Integer2,
104
105 pub sector_3_doppler_prf_pulse_count_radial: Integer2,
107
108 pub reserved: Integer2,
110}
111
112fn decode_angle(raw: Code2) -> f64 {
114 let mut angle: f64 = 0.0;
115 for i in 3..16 {
116 if ((raw >> i) & 1) == 1 {
117 angle += 180.0 * f64::powf(2.0, (i - 15) as f64);
118 }
119 }
120
121 return angle;
122}
123
124fn decode_angular_velocity(raw: Code2) -> f64 {
126 let mut angular_velocity: f64 = 0.0;
127
128 for i in 3..15 {
129 if ((raw >> i) & 1) == 1 {
130 angular_velocity += 22.5 * f64::powf(2.0, (i - 14) as f64);
131 }
132 }
133
134 if ((raw >> 15) & 1) == 1 {
135 angular_velocity = -angular_velocity
136 }
137
138 return angular_velocity;
139}
140
141impl ElevationDataBlock {
142 #[cfg(feature = "uom")]
144 pub fn elevation_angle(&self) -> Angle {
145 Angle::new::<degree>(decode_angle(self.elevation_angle))
146 }
147
148 pub fn elevation_angle_degrees(&self) -> f64 {
150 decode_angle(self.elevation_angle)
151 }
152
153 pub fn channel_configuration(&self) -> ChannelConfiguration {
155 match self.channel_configuration {
156 0 => ChannelConfiguration::ConstantPhase,
157 1 => ChannelConfiguration::RandomPhase,
158 2 => ChannelConfiguration::SZ2Phase,
159 _ => ChannelConfiguration::UnknownPhase,
160 }
161 }
162
163 pub fn waveform_type(&self) -> WaveformType {
165 match self.waveform_type {
166 1 => WaveformType::CS,
167 2 => WaveformType::CDW,
168 3 => WaveformType::CDWO,
169 4 => WaveformType::B,
170 5 => WaveformType::SPP,
171 _ => WaveformType::Unknown,
172 }
173 }
174
175 pub fn super_resolution_control_half_degree_azimuth(&self) -> bool {
177 (self.super_resolution_control & 0x1) == 1
178 }
179
180 pub fn super_resolution_control_quarter_km_reflectivity(&self) -> bool {
182 ((self.super_resolution_control >> 1) & 0x1) == 1
183 }
184
185 pub fn super_resolution_control_doppler_to_300km(&self) -> bool {
187 ((self.super_resolution_control >> 2) & 0x1) == 1
188 }
189
190 pub fn super_resolution_control_dual_polarization_to_300km(&self) -> bool {
192 ((self.super_resolution_control >> 3) & 0x1) == 1
193 }
194
195 #[cfg(feature = "uom")]
197 pub fn azimuth_rate(&self) -> AngularVelocity {
198 AngularVelocity::new::<degree_per_second>(decode_angular_velocity(self.azimuth_rate))
199 }
200
201 pub fn azimuth_rate_degrees_per_second(&self) -> f64 {
203 decode_angular_velocity(self.azimuth_rate)
204 }
205
206 pub fn reflectivity_threshold(&self) -> f64 {
208 self.reflectivity_threshold as f64 * 0.125
209 }
210
211 pub fn velocity_threshold(&self) -> f64 {
213 self.velocity_threshold as f64 * 0.125
214 }
215
216 pub fn spectrum_width_threshold(&self) -> f64 {
218 self.spectrum_width_threshold as f64 * 0.125
219 }
220
221 pub fn differential_reflectivity_threshold(&self) -> f64 {
223 self.differential_reflectivity_threshold as f64 * 0.125
224 }
225
226 pub fn differential_phase_threshold(&self) -> f64 {
228 self.differential_phase_threshold as f64 * 0.125
229 }
230
231 pub fn correlation_coefficient_threshold(&self) -> f64 {
233 self.correlation_coefficient_threshold as f64 * 0.125
234 }
235
236 #[cfg(feature = "uom")]
238 pub fn sector_1_edge_angle(&self) -> Angle {
239 Angle::new::<degree>(decode_angle(self.sector_1_edge_angle))
240 }
241
242 pub fn sector_1_edge_angle_degrees(&self) -> f64 {
244 decode_angle(self.sector_1_edge_angle)
245 }
246
247 #[cfg(feature = "uom")]
249 pub fn sector_2_edge_angle(&self) -> Angle {
250 Angle::new::<degree>(decode_angle(self.sector_2_edge_angle))
251 }
252
253 pub fn sector_2_edge_angle_degrees(&self) -> f64 {
255 decode_angle(self.sector_2_edge_angle)
256 }
257
258 #[cfg(feature = "uom")]
260 pub fn sector_3_edge_angle(&self) -> Angle {
261 Angle::new::<degree>(decode_angle(self.sector_3_edge_angle))
262 }
263
264 pub fn sector_3_edge_angle_degrees(&self) -> f64 {
266 decode_angle(self.sector_3_edge_angle)
267 }
268
269 #[cfg(feature = "uom")]
271 pub fn ebc_angle(&self) -> Angle {
272 Angle::new::<degree>(decode_angle(self.ebc_angle))
273 }
274
275 pub fn ebc_angle_degrees(&self) -> f64 {
277 decode_angle(self.ebc_angle)
278 }
279
280 pub fn supplemental_data_sails_cut(&self) -> bool {
282 (self.supplemental_data & 0x0001) == 1
283 }
284
285 pub fn supplemental_data_sails_sequence_number(&self) -> u8 {
287 ((self.supplemental_data & 0x000E) >> 1) as u8
288 }
289
290 pub fn supplemental_data_mrle_cut(&self) -> bool {
292 ((self.supplemental_data & 0x0010) >> 4) == 1
293 }
294
295 pub fn supplemental_data_mrle_sequence_number(&self) -> u8 {
297 ((self.supplemental_data & 0x00E0) >> 5) as u8
298 }
299
300 pub fn supplemental_data_mpda_cut(&self) -> bool {
302 ((self.supplemental_data & 0x0200) >> 9) == 1
303 }
304
305 pub fn supplemental_data_base_tilt_cut(&self) -> bool {
307 ((self.supplemental_data & 0x0400) >> 10) == 1
308 }
309}
310
311impl Debug for ElevationDataBlock {
312 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
313 let mut debug = f.debug_struct("ElevationDataBlock");
314
315 #[cfg(feature = "uom")]
316 debug.field("elevation_angle", &self.elevation_angle());
317 #[cfg(not(feature = "uom"))]
318 debug.field("elevation_angle", &self.elevation_angle_degrees());
319
320 debug.field("channel_configuration", &self.channel_configuration());
321 debug.field("waveform_type", &self.waveform_type());
322
323 debug.field(
324 "super_resolution_control_raw",
325 &self.super_resolution_control,
326 );
327 debug.field(
328 "super_resolution_control_half_degree_azimuth",
329 &self.super_resolution_control_half_degree_azimuth(),
330 );
331 debug.field(
332 "super_resolution_control_quarter_km_reflectivity",
333 &self.super_resolution_control_quarter_km_reflectivity(),
334 );
335 debug.field(
336 "super_resolution_control_doppler_to_300km",
337 &self.super_resolution_control_doppler_to_300km(),
338 );
339 debug.field(
340 "super_resolution_control_dual_polarization_to_300km",
341 &self.super_resolution_control_dual_polarization_to_300km(),
342 );
343
344 debug.field("surveillance_prf_number", &self.surveillance_prf_number);
345 debug.field(
346 "surveillance_prf_pulse_count_radial",
347 &self.surveillance_prf_pulse_count_radial,
348 );
349
350 #[cfg(feature = "uom")]
351 debug.field("azimuth_rate", &self.azimuth_rate());
352 #[cfg(not(feature = "uom"))]
353 debug.field("azimuth_rate", &self.azimuth_rate_degrees_per_second());
354
355 debug.field("reflectivity_threshold", &self.reflectivity_threshold());
356 debug.field("velocity_threshold", &self.velocity_threshold());
357 debug.field("spectrum_width_threshold", &self.spectrum_width_threshold());
358 debug.field(
359 "differential_reflectivity_threshold",
360 &self.differential_reflectivity_threshold(),
361 );
362 debug.field(
363 "differential_phase_threshold",
364 &self.differential_phase_threshold(),
365 );
366 debug.field(
367 "correlation_coefficient_threshold",
368 &self.correlation_coefficient_threshold(),
369 );
370
371 #[cfg(feature = "uom")]
372 debug.field("sector_1_edge_angle", &self.sector_1_edge_angle());
373 #[cfg(not(feature = "uom"))]
374 debug.field("sector_1_edge_angle", &self.sector_1_edge_angle_degrees());
375
376 debug.field(
377 "sector_1_doppler_prf_number",
378 &self.sector_1_doppler_prf_number,
379 );
380 debug.field(
381 "sector_1_doppler_prf_pulse_count_radial",
382 &self.sector_1_doppler_prf_pulse_count_radial,
383 );
384
385 #[cfg(feature = "uom")]
386 debug.field("sector_2_edge_angle", &self.sector_2_edge_angle());
387 #[cfg(not(feature = "uom"))]
388 debug.field("sector_2_edge_angle", &self.sector_2_edge_angle_degrees());
389
390 debug.field(
391 "sector_2_doppler_prf_number",
392 &self.sector_2_doppler_prf_number,
393 );
394 debug.field(
395 "sector_2_doppler_prf_pulse_count_radial",
396 &self.sector_2_doppler_prf_pulse_count_radial,
397 );
398
399 #[cfg(feature = "uom")]
400 debug.field("sector_3_edge_angle", &self.sector_3_edge_angle());
401 #[cfg(not(feature = "uom"))]
402 debug.field("sector_3_edge_angle", &self.sector_3_edge_angle_degrees());
403
404 debug.field(
405 "sector_3_doppler_prf_number",
406 &self.sector_3_doppler_prf_number,
407 );
408 debug.field(
409 "sector_3_doppler_prf_pulse_count_radial",
410 &self.sector_3_doppler_prf_pulse_count_radial,
411 );
412
413 #[cfg(feature = "uom")]
414 debug.field("ebc_angle", &self.ebc_angle());
415 #[cfg(not(feature = "uom"))]
416 debug.field("ebc_angle", &self.ebc_angle_degrees());
417
418 debug.field("supplemental_data", &self.supplemental_data);
419 debug.field(
420 "supplemental_data_sails_cut",
421 &self.supplemental_data_sails_cut(),
422 );
423 debug.field(
424 "supplemental_data_sails_sequence_number",
425 &self.supplemental_data_sails_sequence_number(),
426 );
427 debug.field(
428 "supplemental_data_mrle_cut",
429 &self.supplemental_data_mrle_cut(),
430 );
431 debug.field(
432 "supplemental_data_mrle_sequence_number",
433 &self.supplemental_data_mrle_sequence_number(),
434 );
435 debug.field(
436 "supplemental_data_mpda_cut",
437 &self.supplemental_data_mpda_cut(),
438 );
439 debug.field(
440 "supplemental_data_base_tilt_cut",
441 &self.supplemental_data_base_tilt_cut(),
442 );
443
444 debug.field("reserved", &self.reserved);
445
446 debug.finish()
447 }
448}