Wideband autonomous SDR analysis engine forked from sdr-visual-suite
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

175 wiersze
4.4KB

  1. package main
  2. import (
  3. "sort"
  4. "sdr-wideband-suite/internal/pipeline"
  5. )
  6. type SurveillanceLevelSummary struct {
  7. Name string `json:"name"`
  8. Role string `json:"role,omitempty"`
  9. Truth string `json:"truth,omitempty"`
  10. SampleRate int `json:"sample_rate,omitempty"`
  11. FFTSize int `json:"fft_size,omitempty"`
  12. BinHz float64 `json:"bin_hz,omitempty"`
  13. Decimation int `json:"decimation,omitempty"`
  14. SpanHz float64 `json:"span_hz,omitempty"`
  15. CenterHz float64 `json:"center_hz,omitempty"`
  16. Source string `json:"source,omitempty"`
  17. SpectrumBins int `json:"spectrum_bins,omitempty"`
  18. }
  19. type CandidateEvidenceSummary struct {
  20. Level string `json:"level"`
  21. Provenance string `json:"provenance,omitempty"`
  22. Count int `json:"count"`
  23. }
  24. type CandidateEvidenceStateSummary struct {
  25. Total int `json:"total"`
  26. WithEvidence int `json:"with_evidence"`
  27. Fused int `json:"fused"`
  28. MultiLevelConfirmed int `json:"multi_level_confirmed"`
  29. DerivedOnly int `json:"derived_only"`
  30. PrimaryOnly int `json:"primary_only"`
  31. }
  32. func buildSurveillanceLevelSummaries(set pipeline.SurveillanceLevelSet, spectra []pipeline.SurveillanceLevelSpectrum) map[string]SurveillanceLevelSummary {
  33. if set.Primary.Name == "" && len(set.Derived) == 0 && set.Presentation.Name == "" && len(set.All) == 0 {
  34. return nil
  35. }
  36. bins := map[string]int{}
  37. for _, spec := range spectra {
  38. if spec.Level.Name == "" || len(spec.Spectrum) == 0 {
  39. continue
  40. }
  41. bins[spec.Level.Name] = len(spec.Spectrum)
  42. }
  43. levels := set.All
  44. if len(levels) == 0 {
  45. if set.Primary.Name != "" {
  46. levels = append(levels, set.Primary)
  47. }
  48. if len(set.Derived) > 0 {
  49. levels = append(levels, set.Derived...)
  50. }
  51. if set.Presentation.Name != "" {
  52. levels = append(levels, set.Presentation)
  53. }
  54. }
  55. out := make(map[string]SurveillanceLevelSummary, len(levels))
  56. for _, level := range levels {
  57. name := level.Name
  58. if name == "" {
  59. continue
  60. }
  61. binHz := level.BinHz
  62. if binHz == 0 && level.SampleRate > 0 && level.FFTSize > 0 {
  63. binHz = float64(level.SampleRate) / float64(level.FFTSize)
  64. }
  65. out[name] = SurveillanceLevelSummary{
  66. Name: name,
  67. Role: level.Role,
  68. Truth: level.Truth,
  69. SampleRate: level.SampleRate,
  70. FFTSize: level.FFTSize,
  71. BinHz: binHz,
  72. Decimation: level.Decimation,
  73. SpanHz: level.SpanHz,
  74. CenterHz: level.CenterHz,
  75. Source: level.Source,
  76. SpectrumBins: bins[name],
  77. }
  78. }
  79. if len(out) == 0 {
  80. return nil
  81. }
  82. return out
  83. }
  84. func buildCandidateSourceSummary(candidates []pipeline.Candidate) map[string]int {
  85. if len(candidates) == 0 {
  86. return nil
  87. }
  88. out := map[string]int{}
  89. for _, cand := range candidates {
  90. if cand.Source == "" {
  91. continue
  92. }
  93. out[cand.Source]++
  94. }
  95. if len(out) == 0 {
  96. return nil
  97. }
  98. return out
  99. }
  100. func buildCandidateEvidenceSummary(candidates []pipeline.Candidate) []CandidateEvidenceSummary {
  101. if len(candidates) == 0 {
  102. return nil
  103. }
  104. type key struct {
  105. level string
  106. provenance string
  107. }
  108. counts := map[key]int{}
  109. for _, cand := range candidates {
  110. for _, ev := range cand.Evidence {
  111. name := ev.Level.Name
  112. if name == "" {
  113. name = "unknown"
  114. }
  115. k := key{level: name, provenance: ev.Provenance}
  116. counts[k]++
  117. }
  118. }
  119. if len(counts) == 0 {
  120. return nil
  121. }
  122. out := make([]CandidateEvidenceSummary, 0, len(counts))
  123. for k, v := range counts {
  124. out = append(out, CandidateEvidenceSummary{Level: k.level, Provenance: k.provenance, Count: v})
  125. }
  126. sort.Slice(out, func(i, j int) bool {
  127. if out[i].Count == out[j].Count {
  128. if out[i].Level == out[j].Level {
  129. return out[i].Provenance < out[j].Provenance
  130. }
  131. return out[i].Level < out[j].Level
  132. }
  133. return out[i].Count > out[j].Count
  134. })
  135. return out
  136. }
  137. func buildCandidateEvidenceStateSummary(candidates []pipeline.Candidate) *CandidateEvidenceStateSummary {
  138. if len(candidates) == 0 {
  139. return nil
  140. }
  141. summary := CandidateEvidenceStateSummary{Total: len(candidates)}
  142. for _, cand := range candidates {
  143. state := pipeline.CandidateEvidenceStateFor(cand)
  144. if state.TotalLevelEntries == 0 {
  145. continue
  146. }
  147. summary.WithEvidence++
  148. if state.Fused {
  149. summary.Fused++
  150. }
  151. if state.MultiLevelConfirmed {
  152. summary.MultiLevelConfirmed++
  153. }
  154. if state.DerivedOnly {
  155. summary.DerivedOnly++
  156. }
  157. if state.PrimaryLevelCount > 0 && state.DerivedLevelCount == 0 {
  158. summary.PrimaryOnly++
  159. }
  160. }
  161. if summary.WithEvidence == 0 {
  162. return nil
  163. }
  164. return &summary
  165. }