@@ -339,10 +339,16 @@ public enum DataFilter {
339339 }
340340
341341 public static func get_csp( data: [ [ [ Double ] ] ] , labels: [ Double ] ) throws -> CSPResult {
342- guard let firstEpoch = data. first, let firstChannel = firstEpoch. first else { throw invalidArguments ( " Invalid CSP data " ) }
342+ guard let firstEpoch = data. first, let firstChannel = firstEpoch. first, !firstChannel . isEmpty else { throw invalidArguments ( " Invalid CSP data " ) }
343343 let nEpochs = data. count
344344 let nChannels = firstEpoch. count
345345 let nTimes = firstChannel. count
346+ guard labels. count == nEpochs else { throw invalidArguments ( " labels count must match epoch count " ) }
347+ guard data. allSatisfy ( { epoch in
348+ epoch. count == nChannels && epoch. allSatisfy { $0. count == nTimes }
349+ } ) else {
350+ throw invalidArguments ( " CSP data must be rectangular " )
351+ }
346352 var flattened = [ Double] ( )
347353 flattened. reserveCapacity ( nEpochs * nChannels * nTimes)
348354 for epoch in data {
@@ -368,6 +374,7 @@ public enum DataFilter {
368374 }
369375
370376 public static func get_window( window_function: Int , window_len: Int ) throws -> [ Double ] {
377+ guard window_len > 0 else { throw invalidArguments ( " window_len must be positive " ) }
371378 var output = [ Double] ( repeating: 0.0 , count: window_len)
372379 try output. withUnsafeMutableBufferPointer { pointer in
373380 try DataFilterNative . withData { native in
@@ -413,6 +420,7 @@ public enum DataFilter {
413420 }
414421
415422 public static func perform_ifft( data: [ Complex ] ) throws -> [ Double ] {
423+ guard data. count >= 2 else { throw invalidArguments ( " FFT data must contain at least two bins " ) }
416424 var real = data. map ( \. real)
417425 var imag = data. map ( \. imag)
418426 let restoredLength = ( data. count - 1 ) * 2
@@ -461,7 +469,10 @@ public enum DataFilter {
461469 }
462470
463471 public static func get_psd_welch( data: [ Double ] , nfft: Int , overlap: Int , sampling_rate: Int , window: Int ) throws -> PSD {
464- guard nfft % 2 == 0 else { throw invalidArguments ( " nfft must be even " ) }
472+ guard nfft > 0 , nfft & ( nfft - 1 ) == 0 else { throw invalidArguments ( " nfft must be a positive power of two " ) }
473+ guard data. count >= nfft else { throw invalidArguments ( " nfft must be less than or equal to data count " ) }
474+ guard overlap >= 0 , overlap < nfft else { throw invalidArguments ( " overlap must be non-negative and less than nfft " ) }
475+ guard sampling_rate > 0 else { throw invalidArguments ( " sampling_rate must be positive " ) }
465476 var input = data
466477 var ampl = [ Double] ( repeating: 0.0 , count: nfft / 2 + 1 )
467478 var freq = [ Double] ( repeating: 0.0 , count: nfft / 2 + 1 )
@@ -482,6 +493,8 @@ public enum DataFilter {
482493 }
483494
484495 public static func get_band_power( psd: PSD , freq_start: Double , freq_end: Double ) throws -> Double {
496+ guard !psd. ampl. isEmpty, psd. ampl. count == psd. freq. count else { throw invalidArguments ( " PSD arrays must be non-empty and have equal lengths " ) }
497+ guard freq_start < freq_end else { throw invalidArguments ( " freq_start must be less than freq_end " ) }
485498 var ampl = psd. ampl
486499 var freq = psd. freq
487500 var output = 0.0
@@ -513,8 +526,11 @@ public enum DataFilter {
513526 sampling_rate: Int ,
514527 apply_filter: Bool
515528 ) throws -> BandPowerResult {
529+ let ( rows, cols) = try BrainFlowArray . validateRectangular ( data)
516530 guard !channels. isEmpty, !bands. isEmpty else { throw invalidArguments ( " Channels and bands must be non-empty " ) }
517- let cols = data [ channels [ 0 ] ] . count
531+ guard channels. allSatisfy ( { $0 >= 0 && $0 < rows } ) else { throw invalidArguments ( " Channel index is out of range " ) }
532+ guard bands. allSatisfy ( { $0. start < $0. stop } ) else { throw invalidArguments ( " Band start frequency must be less than stop frequency " ) }
533+ guard sampling_rate > 0 else { throw invalidArguments ( " sampling_rate must be positive " ) }
518534 var selected = [ Double] ( )
519535 selected. reserveCapacity ( channels. count * cols)
520536 for channel in channels {
@@ -543,7 +559,11 @@ public enum DataFilter {
543559 public static func perform_ica( data: [ [ Double ] ] , num_components: Int , channels: [ Int ] ? = nil ) throws -> ICAResult {
544560 let ( rows, cols) = try BrainFlowArray . validateRectangular ( data)
545561 let selectedChannels = channels ?? Array ( 0 ..< rows)
546- guard num_components >= 1 else { throw invalidArguments ( " num_components must be positive " ) }
562+ guard !selectedChannels. isEmpty else { throw invalidArguments ( " channels must be non-empty " ) }
563+ guard selectedChannels. allSatisfy ( { $0 >= 0 && $0 < rows } ) else { throw invalidArguments ( " Channel index is out of range " ) }
564+ guard cols >= 2 else { throw invalidArguments ( " ICA data must contain at least two samples " ) }
565+ guard selectedChannels. count >= 2 else { throw invalidArguments ( " ICA requires at least two channels " ) }
566+ guard num_components >= 2 , num_components <= selectedChannels. count else { throw invalidArguments ( " num_components must be between 2 and the selected channel count " ) }
547567 var selected = [ Double] ( )
548568 selected. reserveCapacity ( selectedChannels. count * cols)
549569 for channel in selectedChannels {
@@ -578,6 +598,7 @@ public enum DataFilter {
578598 var input = data
579599 let start = start_pos ?? 0
580600 let end = end_pos ?? data. count
601+ guard start >= 0 , end <= data. count, start < end else { throw invalidArguments ( " Invalid position arguments " ) }
581602 var output = 0.0
582603 try input. withUnsafeMutableBufferPointer { pointer in
583604 try DataFilterNative . withData { native in
@@ -588,6 +609,7 @@ public enum DataFilter {
588609 }
589610
590611 public static func get_railed_percentage( data: [ Double ] , gain: Int ) throws -> Double {
612+ guard !data. isEmpty else { throw invalidArguments ( " data must be non-empty " ) }
591613 var input = data
592614 var output = 0.0
593615 try input. withUnsafeMutableBufferPointer { pointer in
@@ -599,6 +621,8 @@ public enum DataFilter {
599621 }
600622
601623 public static func get_oxygen_level( ppg_ir: [ Double ] , ppg_red: [ Double ] , sampling_rate: Int , coef1: Double = 1.5958422 , coef2: Double = - 34.6596622 , coef3: Double = 112.6898759 ) throws -> Double {
624+ guard !ppg_ir. isEmpty, ppg_ir. count == ppg_red. count else { throw invalidArguments ( " PPG arrays must be non-empty and have equal lengths " ) }
625+ guard sampling_rate > 0 else { throw invalidArguments ( " sampling_rate must be positive " ) }
602626 var ir = ppg_ir
603627 var red = ppg_red
604628 var output = 0.0
@@ -613,6 +637,9 @@ public enum DataFilter {
613637 }
614638
615639 public static func get_heart_rate( ppg_ir: [ Double ] , ppg_red: [ Double ] , sampling_rate: Int , fft_size: Int ) throws -> Double {
640+ guard !ppg_ir. isEmpty, ppg_ir. count == ppg_red. count else { throw invalidArguments ( " PPG arrays must be non-empty and have equal lengths " ) }
641+ guard sampling_rate > 0 else { throw invalidArguments ( " sampling_rate must be positive " ) }
642+ guard fft_size >= 1024 , fft_size % 2 == 0 else { throw invalidArguments ( " fft_size must be even and at least 1024 " ) }
616643 var ir = ppg_ir
617644 var red = ppg_red
618645 var output = 0.0
@@ -655,6 +682,7 @@ public enum DataFilter {
655682 try checkBrainFlowExitCode ( native. get_num_elements_in_file ( fileNamePtr, & elements) , " Failed to determine number of file elements " )
656683 }
657684 }
685+ guard elements >= 0 else { throw invalidArguments ( " File element count must be non-negative " ) }
658686 var data = [ Double] ( repeating: 0.0 , count: Int ( elements) )
659687 var rows : CInt = 0
660688 var cols : CInt = 0
0 commit comments