digiproc 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +8 -0
  7. data/Gemfile.lock +48 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +78 -0
  10. data/Rakefile +37 -0
  11. data/TODO.md +50 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/config/environment.rb +118 -0
  15. data/console_tests.rb +44 -0
  16. data/digiproc.gemspec +49 -0
  17. data/examples/analog_signals/analog_to_digital.rb +31 -0
  18. data/examples/analog_signals/companded-signals.png +0 -0
  19. data/examples/analog_signals/companding.rb +68 -0
  20. data/examples/analog_signals/fft-plot.png +0 -0
  21. data/examples/analog_signals/plot_Digiproc::FFT.png +0 -0
  22. data/examples/analog_signals/plot_Dsp::FFT.png +0 -0
  23. data/examples/analog_signals/quantization-outputs.png +0 -0
  24. data/examples/analog_signals/quantize_compand.rb +69 -0
  25. data/examples/binomial_distribution/bit_error.rb +14 -0
  26. data/examples/binomial_distribution/dice.rb +35 -0
  27. data/examples/digital_signals/_coded_frequency_signal,_ts_=_1_s.png +0 -0
  28. data/examples/digital_signals/_coded_frequency_signal,_ts_=_2_s.png +0 -0
  29. data/examples/digital_signals/coded_power_spectral_density,__ts_=_1_s.png +0 -0
  30. data/examples/digital_signals/coded_power_spectral_density,__ts_=_2_s.png +0 -0
  31. data/examples/digital_signals/coded_time_signal,_ts_=_1_s.png +0 -0
  32. data/examples/digital_signals/coded_time_signal,_ts_=_2_s.png +0 -0
  33. data/examples/digital_signals/freq_sig_from_eqn,_ts_=_1_s.png +0 -0
  34. data/examples/digital_signals/freq_sig_from_eqn,_ts_=_2_s.png +0 -0
  35. data/examples/digital_signals/frequency_signal,_ts_=_1_s.png +0 -0
  36. data/examples/digital_signals/frequency_signal,_ts_=_2_s.png +0 -0
  37. data/examples/digital_signals/modulate_square_pulses.rb +9 -0
  38. data/examples/digital_signals/modulated_sq._pulses.png +0 -0
  39. data/examples/digital_signals/modulated_sq._pulses_alt.png +0 -0
  40. data/examples/digital_signals/power_spectral_density,__ts_=_1_s.png +0 -0
  41. data/examples/digital_signals/power_spectral_density,__ts_=_2_s.png +0 -0
  42. data/examples/digital_signals/square_signals.rb +90 -0
  43. data/examples/digital_signals/time_signal,_ts_=_1_s.png +0 -0
  44. data/examples/digital_signals/time_signal,_ts_=_2_s.png +0 -0
  45. data/examples/encoding/gray_code.rb +22 -0
  46. data/examples/encoding/psk.rb +91 -0
  47. data/examples/encoding/system_2_phase.png +0 -0
  48. data/examples/encoding/system_2_xmit_signal.png +0 -0
  49. data/examples/encoding/system_3_phase.png +0 -0
  50. data/examples/encoding/system_3_xmit_signal.png +0 -0
  51. data/examples/encoding/system_4_xmit_signal.png +0 -0
  52. data/examples/encoding/xor-dpsk-phase-signal-(sys1).png +0 -0
  53. data/examples/encoding/xor-dpsk-xmit-signal-(sys-1).png +0 -0
  54. data/examples/factories/Quickplot Graph.png +0 -0
  55. data/examples/factories/bandpass.rb +6 -0
  56. data/examples/fft/plot_Dsp::FFT.png +0 -0
  57. data/examples/fft/recieved_data_(time_domain).png +0 -0
  58. data/examples/fft/simple_fft_example.rb +47 -0
  59. data/examples/fft/unprocessed_fft.png +0 -0
  60. data/examples/filters/bandpass_filter.png +0 -0
  61. data/examples/filters/filter_a_signal.rb +38 -0
  62. data/examples/filters/white_noise_db_out_of_bp_filter.png +0 -0
  63. data/examples/filters/white_noise_mag_out_of_bp_filter.png +0 -0
  64. data/examples/filters/white_noise_spectra.png +0 -0
  65. data/examples/functions/compute_probability.rb +29 -0
  66. data/examples/functions/gram_schmidt.rb +10 -0
  67. data/examples/functions/minimize_energy.rb +29 -0
  68. data/examples/functions/orthoganalize.rb +18 -0
  69. data/examples/functions/simple_functions.rb +81 -0
  70. data/examples/linear_algebra/diverging_sys.rb +13 -0
  71. data/examples/linear_algebra/iterative_sys_of_eqns_methods.rb +27 -0
  72. data/examples/modulation_schemes/dpsk_2.png +0 -0
  73. data/examples/modulation_schemes/dpsk_256.png +0 -0
  74. data/examples/modulation_schemes/dpsk_freq_domain.rb +119 -0
  75. data/examples/modulation_schemes/psk.rb +36 -0
  76. data/examples/modulation_schemes/psk_2.png +0 -0
  77. data/examples/modulation_schemes/psk_256.png +0 -0
  78. data/examples/modulation_schemes/psksystem_1_xmit_signal.png +0 -0
  79. data/examples/modulation_schemes/psksystem_2_xmit_signal.png +0 -0
  80. data/examples/modulation_schemes/psksystem_3_xmit_signal.png +0 -0
  81. data/examples/modulation_schemes/system_1_xmit_signal.png +0 -0
  82. data/examples/modulation_schemes/system_2_xmit_signal.png +0 -0
  83. data/examples/modulation_schemes/system_3_xmit_signal.png +0 -0
  84. data/examples/quickplot/PlottableClass_plot.png +0 -0
  85. data/examples/quickplot/decorators.rb +13 -0
  86. data/examples/quickplot/direct_gruff.png +0 -0
  87. data/examples/quickplot/plot_PlottableClass.png +0 -0
  88. data/examples/quickplot/quickplot_vs_others.rb +85 -0
  89. data/examples/quickplot/random_data_quickplot,_dark.png +0 -0
  90. data/examples/quickplot/random_data_quickplot.png +0 -0
  91. data/examples/realized_gaussian/norm_dist_plot.png +0 -0
  92. data/examples/realized_gaussian/norm_dist_spectrum.png +0 -0
  93. data/examples/realized_gaussian/realized_gaussian_example.rb +23 -0
  94. data/lib/concerns/convolvable.rb +144 -0
  95. data/lib/concerns/data_properties.rb +223 -0
  96. data/lib/concerns/fourier_transformable.rb +178 -0
  97. data/lib/concerns/initializable.rb +43 -0
  98. data/lib/concerns/multipliable.rb +22 -0
  99. data/lib/concerns/os.rb +36 -0
  100. data/lib/concerns/plottable.rb +248 -0
  101. data/lib/concerns/requires_data.rb +8 -0
  102. data/lib/digiproc/version.rb +8 -0
  103. data/lib/digiproc.rb +2 -0
  104. data/lib/extensions/array_extension.rb +23 -0
  105. data/lib/extensions/core_extensions.rb +117 -0
  106. data/lib/factories/factories.rb +3 -0
  107. data/lib/factories/filter_factory.rb +83 -0
  108. data/lib/factories/window_factory.rb +22 -0
  109. data/lib/fft.rb +255 -0
  110. data/lib/filters/bandpass_filter.rb +43 -0
  111. data/lib/filters/bandstop_filter.rb +44 -0
  112. data/lib/filters/digital_filter.rb +59 -0
  113. data/lib/filters/highpass_filter.rb +27 -0
  114. data/lib/filters/lowpass_filter.rb +27 -0
  115. data/lib/functions.rb +221 -0
  116. data/lib/probability/binomial_distribution.rb +84 -0
  117. data/lib/probability/bit_generator.rb +94 -0
  118. data/lib/probability/gaussian_distribution.rb +29 -0
  119. data/lib/probability/probability.rb +234 -0
  120. data/lib/probability/theoretical_gaussian_distribution.rb +59 -0
  121. data/lib/quick_plot.rb +96 -0
  122. data/lib/rbplot.rb +219 -0
  123. data/lib/signals/analog_signal.rb +143 -0
  124. data/lib/signals/digital_signal.rb +181 -0
  125. data/lib/strategies/code/differential_encoding_strategy.rb +69 -0
  126. data/lib/strategies/code/gray_code.rb +75 -0
  127. data/lib/strategies/code/xor_differential_encoding_strategy.rb +100 -0
  128. data/lib/strategies/code/xor_differential_encoding_zero_angle_strategy.rb +103 -0
  129. data/lib/strategies/companding/custom_companding_strategy.rb +29 -0
  130. data/lib/strategies/convolution/bf_conv.rb +57 -0
  131. data/lib/strategies/fft/brute_force_dft_strategy.rb +31 -0
  132. data/lib/strategies/fft/inverse_fft_conjugate_strategy.rb +44 -0
  133. data/lib/strategies/fft/radix2_strategy.rb +84 -0
  134. data/lib/strategies/gaussian/gaussian_generator.rb +49 -0
  135. data/lib/strategies/linear_algebra/gauss_seidel_strategy.rb +90 -0
  136. data/lib/strategies/linear_algebra/jacobi_strategy.rb +81 -0
  137. data/lib/strategies/linear_algebra/sor2_strategy.rb +98 -0
  138. data/lib/strategies/linear_algebra/sor_strategy.rb +108 -0
  139. data/lib/strategies/modulation/phase_shift_keying_strategy.rb +96 -0
  140. data/lib/strategies/orthogonalize/gram_schmidt.rb +50 -0
  141. data/lib/strategies/strategies.rb +3 -0
  142. data/lib/strategies/window/blackman_window.rb +32 -0
  143. data/lib/strategies/window/hamming_window.rb +31 -0
  144. data/lib/strategies/window/hanning_window.rb +31 -0
  145. data/lib/strategies/window/kaiser_window.rb +27 -0
  146. data/lib/strategies/window/rectangular_window.rb +22 -0
  147. data/lib/strategies/window/window.rb +42 -0
  148. data/lib/systems/custom_system.rb +13 -0
  149. data/lib/systems/hilbert_transform.rb +6 -0
  150. data/lib/systems/matched_filter.rb +21 -0
  151. data/lib/systems/raised_cosine_filter.rb +11 -0
  152. data/lib/systems/system.rb +19 -0
  153. data/lib/systems/systems.rb +3 -0
  154. data/playground.rb +323 -0
  155. data/plots/_coded_frequency_signal,_ts_=_1_s.png +0 -0
  156. data/plots/_coded_frequency_signal,_ts_=_2_s.png +0 -0
  157. data/plots/coded_freq_sig_from_eqn,_ts_=_1_s.png +0 -0
  158. data/plots/coded_freq_sig_from_eqn,_ts_=_2_s.png +0 -0
  159. data/plots/coded_power_spectral_density,__ts_=_1_s.png +0 -0
  160. data/plots/coded_power_spectral_density,__ts_=_2_s.png +0 -0
  161. data/plots/coded_time_signal,_ts_=_1_s.png +0 -0
  162. data/plots/coded_time_signal,_ts_=_2_s.png +0 -0
  163. data/plots/dpsk_2.png +0 -0
  164. data/plots/freq_sig_from_eqn,_ts_=_1_s.png +0 -0
  165. data/plots/freq_sig_from_eqn,_ts_=_2_s.png +0 -0
  166. data/plots/frequency_signal,_ts_=_1_s.png +0 -0
  167. data/plots/frequency_signal,_ts_=_2_s.png +0 -0
  168. data/plots/power_spectral_density,__ts_=_1_s.png +0 -0
  169. data/plots/power_spectral_density,__ts_=_2_s.png +0 -0
  170. data/plots/psk_2.png +0 -0
  171. data/plots/time_signal,_ts_=_1_s.png +0 -0
  172. data/plots/time_signal,_ts_=_2_s.png +0 -0
  173. data/test-title-dark.png +0 -0
  174. data/test-title.png +0 -0
  175. metadata +322 -0
@@ -0,0 +1,248 @@
1
+ require 'gruff'
2
+
3
+ ##
4
+ # Defines plotting helpers using the `gruff` library.
5
+ # See `examples/quickplot/quickplot_vs_others.rb for good examples of this module and Quickplot (which extends Digiproc::Plottable::InstanceMethods)
6
+
7
+ module Digiproc::Plottable
8
+
9
+ ##
10
+ # Defines custom plot styles to be used
11
+ module Styles
12
+ MIDNIGHT = {
13
+ :colors => [
14
+ '#00dae5', #teal
15
+ '#FF1A1A', # red
16
+ '#3FFC07', # green
17
+ '#FDD84E', # yellow
18
+ '#6886B4', # blue
19
+ '#8A6EAF', # purple
20
+ '#EFAA43', # orange
21
+ 'white'
22
+ ],
23
+ :marker_color => '#7e7c7f',
24
+ :font_color => '#cccccc',
25
+ :background_colors => %w(black #2a2a2a)
26
+ }
27
+
28
+ SUBMARINE = {
29
+ :colors => [
30
+ '#FF1A1A', # red
31
+ '#3FFC07', # green
32
+ '#FDD84E', # yellow
33
+ '#6886B4', # blue
34
+ '#8A6EAF', # purple
35
+ '#EFAA43', # orange
36
+ 'white'
37
+ ],
38
+ :marker_color => '#3d007a',
39
+ :font_color => '#cccccc',
40
+ :background_colors => %w(black #2a2a2a)
41
+ }
42
+
43
+ BLUESCALE = {
44
+ :colors => [
45
+ '#0b0b70', #
46
+ '#383838', #
47
+ '#686868', #
48
+ '#989898', #
49
+ '#c8c8c8', #
50
+ '#e8e8e8', #
51
+ ],
52
+ :marker_color => '#aea9a9', # Grey
53
+ :font_color => 'black',
54
+ :background_colors => 'white'
55
+ }
56
+ end
57
+
58
+ ##
59
+ # Contains generic plotting helpers which can be extended to make more specific plotting helpers, or can be used
60
+ # in another class to extend their functionality. Digiproc::Plottable does extend self::ClassMethods, so they can be used
61
+ # as standalone plotting functions using Digiproc::Plottable.iplot() { |g| ... } or Digiproc::Plottable.qplot(...)
62
+
63
+ module ClassMethods
64
+
65
+
66
+ # TODO: Below method will be plotted inside a block instead
67
+ # of passing params to the method. Also, the logic below the
68
+ # yield will fix the problem of x float values not being able to
69
+ # have corresponding labels. Lastly, it will return an instance
70
+ # of the plot without writing it, so it can be decorated with
71
+ # vertical lines, or any other future decorator.
72
+
73
+ ##
74
+ # Will yield g and allow the caller to define the plot as they wish. It does very little beforehand to setup the plot
75
+
76
+ def iplot(xsteps: 4)
77
+ g = Gruff::Line.new('1000x1000')
78
+ g.theme = Digiproc::Plottable::Styles::BLUESCALE
79
+ g.line_width = 2
80
+ g.dot_radius = 0.1
81
+ yield g
82
+ #must insert data :name, data_arr
83
+ #or dataxy :name, x_arr, y_arr
84
+
85
+ # Go through each dataset,
86
+ #If there are x values, get max and min
87
+ #If there are not, get the length of the data
88
+ #If labels are not inserted by user, do:
89
+ # get range of largest dataset
90
+ # label at 0, 0.25*len, 0.5*len, 0.75*len, len
91
+ return g
92
+ end
93
+
94
+
95
+
96
+
97
+ ##
98
+ # Used by Digiproc::QuickPlot.
99
+ ## qplot(x: Array[Numeric], y: Array[Numeric], data: Array[Numeric], data_name: String, xyname: String, filename: String, path: String, xsteps: Integer, label_map: ->(Float) returns Float) #=> returns a plot at the entered directory or './plots' by default (ensure directory exists)
100
+ # x and y OR data must exist to make a plot.
101
+ # `label_map` is used to map the index of the data (or the x value at that point if using xy) to an appropriate label. For example if the x values are between 1 and 10 but data.length is 10000, your label_map could be:
102
+ ## label_map = ->(index_val){ return index_val / 1000.0 }
103
+ # The frequency of labels will be determined by `xsteps`
104
+ def qplot(x: nil ,y: nil , data: nil, data_name: "data", xyname: "data",filename: "#{self}_plot", path: "./plots/", xsteps: 4, label_map: nil)
105
+ raise ArgumentError.new("Either x and y or data must exist") if data.nil? and (x.nil? or y.nil?)
106
+ data = data
107
+ raise TypeError.new("Data must be an array, not a #{data.class}") if data and not data.is_a? Array
108
+ raise TypeError.new("X and Y must be arrays, not #{x.class}, #{y.class}") if (!!x and !!y) and not (x.is_a?(Array) and y.is_a?(Array))
109
+ raise ArgumentError.new("X and Y must be the same size") if (!!x and !!y) and (x.length != y.length)
110
+ g = Gruff::Line.new('1000x1000')
111
+ g.theme = Styles::BLUESCALE
112
+ g.line_width = 2.5
113
+ g.dot_radius = 0.1
114
+ # g.minimum_x_value = 0
115
+ g.data data_name, data if !!data
116
+ g.dataxy xyname, x, y if !!x and !!y
117
+ xmax = !!data ? data.length : x.max
118
+ xmin = !!data ? 0 : x.min
119
+ increment_label = (xmax - xmin) / xsteps.to_f
120
+ datalength = !!data ? data.length : x.length
121
+ increment_datapoints = (datalength.to_f / xsteps).round
122
+ labels = {}
123
+ for i in 0..xsteps do
124
+ datapoint_location = i * increment_datapoints
125
+ datapoint_location -= 1 if datapoint_location > (datalength - 1)
126
+ label_val = label_map.nil? ? (i * increment_label).round(2) : label_map.call((i * increment_label)).round(2)
127
+ labels[datapoint_location] = label_val
128
+ end
129
+ g.labels = labels
130
+ g.show_vertical_markers = false
131
+ yield g
132
+ g.write(path + filename + '.png')
133
+ end
134
+
135
+
136
+ #TODO: Figure out a way to display a vertical line using a decorator.
137
+ #The class below displays a line from the upper left to lower right hand corner of the plot
138
+
139
+ # class VerticalLine
140
+
141
+ # attr_reader :plot, :x_value, :label, :color
142
+
143
+ # def initialize(plot, x_value, label = "vline", color = "white")
144
+ # @plot, @x_value, @label, @color = plot, x_value, label, color
145
+ # end
146
+
147
+ # def write(location)
148
+ # add_vertical_line
149
+ # puts plot.instance_variable_get(:@data).to_s
150
+ # plot.write(location)
151
+ # end
152
+
153
+ # private
154
+
155
+ # def add_vertical_line
156
+ # data = plot.instance_variable_get(:@data)
157
+ # data_cpy = data.dup
158
+ # data_num = data.length
159
+ # max_y_val = data.map{ |dataset| get_max_y(dataset) }.max
160
+ # min_y_val = data.map{ |dataset| get_min_y(dataset) }.min
161
+ # plot.dataxy label, [x_value, x_value+1], [max_y_val, min_y_val]
162
+ # plot.colors[data_num] = color
163
+ # end
164
+
165
+ # def get_max_y(arr)
166
+ # arr[1].max
167
+ # end
168
+
169
+ # def get_min_y(arr)
170
+ # arr[1].min
171
+ # end
172
+
173
+ # def has_x_values?(data)
174
+ # data.length == 4
175
+ # end
176
+ # end
177
+
178
+
179
+ end
180
+
181
+ extend self::ClassMethods
182
+
183
+ ##
184
+ # Can be included in classes in which you may want a specific plot for a method output (ie the Discrete Fourier Transform magnitude plot)
185
+ module InstanceMethods
186
+
187
+ ##
188
+ ## plot(method: Symbol, filename: String [default = "plot_#{self.class}"], path: String [default = "./"], xmax: Integer [default = 1], xmin: Integer [default = 0], xsteps: Integer [default = 4])
189
+ # Can be used to plot the output of a specific method. By specifying the name of the method when you call plot, if the output of that method is a Numeric Array, then a plot will be made.
190
+ # An example can be seen in Digiproc::FFT #plot_db
191
+ def plot(method:, filename: "plot_#{self.class}", path: "./", xmax: 1, xmin: 0, xsteps: 4)
192
+ data = self.send(method)
193
+ raise TypeError.new('Data must be an array, not a #{data.class}') if not data.is_a? Array
194
+ g = Gruff::Line.new('1000x1000')
195
+ g.theme = Digiproc::Plottable::Styles::MIDNIGHT
196
+ g.line_width = 1
197
+ g.dot_radius = 1
198
+ g.minimum_x_value = 0
199
+ g.data method, data
200
+ increment_label = (xmax - xmin) / xsteps.to_f
201
+ increment_datapoints = (data.length.to_f / xsteps).round
202
+ labels = {}
203
+ for i in 0..xsteps do
204
+ datapoint_location = i * increment_datapoints
205
+ datapoint_location -= 1 if datapoint_location > (data.length - 1)
206
+ labels[datapoint_location] = (i * increment_label).round(2)
207
+ end
208
+ g.labels = labels
209
+ g.show_vertical_markers = true
210
+ yield g
211
+ g.write(path + filename + '.png')
212
+ end
213
+
214
+ ##
215
+ # Same as qplot in Digiproc::Plottable::InstanceMethods
216
+
217
+ def qplot(x: nil ,y: nil , data: nil, data_name: "data", xyname: "data",filename: "#{self}_plot", path: "./plots/", xsteps: 4, label_map: nil)
218
+ raise ArgumentError.new("Either x and y or data must exist") if data.nil? and (x.nil? or y.nil?)
219
+ data = data
220
+ raise TypeError.new("Data must be an array, not a #{data.class}") if data and not data.is_a? Array
221
+ raise TypeError.new("X and Y must be arrays, not #{x.class}, #{y.class}") if (!!x and !!y) and not (x.is_a?(Array) and y.is_a?(Array))
222
+ raise ArgumentError.new("X and Y must be the same size") if (!!x and !!y) and (x.length != y.length)
223
+ g = Gruff::Line.new('1000x1000')
224
+ g.theme = Styles::BLUESCALE
225
+ g.line_width = 2.5
226
+ g.dot_radius = 0.1
227
+ # g.minimum_x_value = 0
228
+ g.data data_name, data if !!data
229
+ g.dataxy xyname, x, y if !!x and !!y
230
+ xmax = !!data ? data.length : x.max
231
+ xmin = !!data ? 0 : x.min
232
+ increment_label = (xmax - xmin) / xsteps.to_f
233
+ datalength = !!data ? data.length : x.length
234
+ increment_datapoints = (datalength.to_f / xsteps).round
235
+ labels = {}
236
+ for i in 0..xsteps do
237
+ datapoint_location = i * increment_datapoints
238
+ datapoint_location -= 1 if datapoint_location > (datalength - 1)
239
+ label_val = label_map.nil? ? (i * increment_label).round(2) : label_map.call((i * increment_label)).round(2)
240
+ labels[datapoint_location] = label_val
241
+ end
242
+ g.labels = labels
243
+ g.show_vertical_markers = false
244
+ yield g
245
+ g.write(path + filename + '.png')
246
+ end
247
+ end
248
+ end
@@ -0,0 +1,8 @@
1
+ ##
2
+ # Many modules in this gem require that the class which includes them has a property called `data`. This module can be used by modules which require the use
3
+ # of the `data` property to ensure that they are being used correctly. If `data` is not a property, a `TypeError` will be thrown upon inclusion into the class.
4
+ module Digiproc::RequiresData
5
+ def self.included(base)
6
+ raise TypeError.new("To implement #{self}, #{base} must have an instance varaible @data, and getters/setters") if not base.method_defined?(:data)
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+
2
+ module Digiproc
3
+ VERSION = "0.1.0"
4
+ end
5
+
6
+
7
+
8
+
data/lib/digiproc.rb ADDED
@@ -0,0 +1,2 @@
1
+ require_relative "./digiproc/version"
2
+ require_relative "../config/environment"
@@ -0,0 +1,23 @@
1
+ class Array
2
+
3
+ # def *(arr)
4
+ # raise ArgumentError.new("Array sizes must be equal") if self.size != arr.size
5
+ # output = []
6
+ # self.each_with_index do |o,i|
7
+ # output << o * arr[i]
8
+ # end
9
+ # output
10
+ # end
11
+
12
+
13
+ # def plus(arr)
14
+ # raise ArgumentError.new("sizes must be equal") if self.size != arr.size
15
+ # output = []
16
+ # self.each_with_index do |o,i|
17
+ # output << o + arr[i]
18
+ # end
19
+ # output
20
+ # end
21
+
22
+
23
+ end
@@ -0,0 +1,117 @@
1
+ ##
2
+ # Add extensions to certain Ruby Classes for easy use of the library without using too many custom classes
3
+ module Digiproc::CoreExtensions
4
+ module ArrayExtension
5
+ module DotProduct
6
+ ##
7
+ # Take the dot product of self another Array (allow complex numbers). They must be the same size. Returns a scalar
8
+ ## myArray.dot(anotherArray) # => Float
9
+ def dot(arr)
10
+ raise ArgumentError.new("Array sizes must be equal") if self.size != arr.size
11
+ output = []
12
+ self.each_with_index do |o,i|
13
+ output << o * arr[i].conjugate
14
+ end
15
+ output.sum
16
+ end
17
+ end
18
+ module Sum
19
+ ##
20
+ # Add two arrays element by element. They must be the same size
21
+ ## myArray.plus(anotherArr) # => Array (same size as the input)
22
+ def plus(arr)
23
+ raise ArgumentError.new("sizes must be equal") if self.size != arr.size
24
+ output = []
25
+ self.each_with_index do |o,i|
26
+ output << o + arr[i]
27
+ end
28
+ output
29
+ end
30
+ end
31
+
32
+ ##
33
+ # Multiply two arrays element by element. They must be the same size
34
+ ## myArray.times(anotherArr) => Array (same size as the input)
35
+ module Multiply
36
+ def times(arr)
37
+ raise ArgumentError.new("Array sizes must be equal") if self.size != arr.size
38
+ output = []
39
+ self.each_with_index do |o,i|
40
+ output << o * arr[i]
41
+ end
42
+ output
43
+ end
44
+ end
45
+ end
46
+
47
+ # Extend functionaly of Ruby's Math module
48
+ module MathExtension
49
+ ##
50
+ # Add methods which are useful when using decible values
51
+ module Decible
52
+ ##
53
+ ## db(numeric_input [Numeric]) # => returns 20 * Math.log(numeric_input, 10)
54
+ def db(value)
55
+ 20 * Math.log(value, 10)
56
+ end
57
+
58
+ ##
59
+ ## db_power(numeric_input [Numeric]) # => returns 10 * Math.log(numeric_input, 10)
60
+ def db_power(value)
61
+ 10 * Math.log(value, 10)
62
+ end
63
+
64
+ ##
65
+ # input a decible, recieve a magnitude
66
+ def mag_from_db(decible)
67
+ 10 ** (decible / 20.0)
68
+ end
69
+
70
+ ##
71
+ # Input a decible, recieve a magnitude (power)
72
+ def power_from_db(decible)
73
+ 10 ** (decible / 10.0)
74
+ end
75
+ end
76
+ end
77
+
78
+ module VectorExtension
79
+ ##
80
+ # Extend functionality to Vector
81
+ module Projection
82
+ module ClassMethods
83
+ ##
84
+ # .projcect(vector1, vector2) returns a projection of vector 1 onto vector 2
85
+ def project(vec1, vec2)
86
+ vec1 = vec1.is_a?(Vector)? vec1 : Vector.elements(vec1)
87
+ vec2 = vec2.is_a?(Vector) ? vec2 : Vector.elements(vec2)
88
+ vec2.project_onto vec1
89
+ end
90
+ end
91
+ module InstanceMethods
92
+ ##
93
+ # .project_onto(vector) projects self onto the input vector
94
+ def project_onto(vec)
95
+ raise ArgumentError.new("Argument must be a Vector") if not vec.is_a? Vector
96
+ (self.dot(vec) / (vec.r ** 2)) * vec
97
+ end
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ module FloatExtension
104
+
105
+ module OddPatch
106
+
107
+ def odd?
108
+ true
109
+ end
110
+
111
+ end
112
+
113
+ end
114
+
115
+
116
+
117
+ end
@@ -0,0 +1,3 @@
1
+ module Digiproc::Factories
2
+
3
+ end
@@ -0,0 +1,83 @@
1
+ ##
2
+ # Factory for different filters.
3
+ # Filters are created using the Windowing method
4
+ # The window for the filter outputted will depend on the required stopband attenuation
5
+
6
+
7
+ class Digiproc::Factories::FilterFactory
8
+
9
+ ##
10
+ # == Give requirements of the filter:
11
+ # type:: [String] Accepts: 'highpass', 'lowpass', 'bandpass', 'bandstop'
12
+ # wc:: [Float] cutoff frequency in radians
13
+ # wo:: [Float] center frequency in radians
14
+ # bw:: [Float] bandwidth in radians
15
+ # transition_width:: [Float] in NORMALIZED FREQUENCY, ie 0 to 1 scale, where 1 = Sampling Frequency (should be changed to rad for consistency)
16
+ # stopband_attenuation:: [Numeric] level of stopband in decibles
17
+ #
18
+ # == Also Note:
19
+ # Digiproc::LowpassFilter:: requires wc, not wo or bw
20
+ # Digiproc::HighpassFilter:: requires wc, not wo or bw
21
+ # Digiproc::BandpassFilter:: requires wo and bw, not wc
22
+ # Digiproc::BandstopFilter:: requires wo and bw, not wc
23
+ # NOTE: This factory makes all sizes odd in ensure all types of filters will work (ie an even number of values will not allow a highpass filter, an anti-symmetric odd will not allow a lowpass, etc.)
24
+ # Available windows: Digiproc::RectangularWindow, Digiproc::HanningWindow, Digiproc::HammingWindow, Digiproc::BlackmanWindow
25
+ def self.filter_for(type: , wc: nil, wo: nil, bw: nil, transition_width: nil, stopband_attenuation: )
26
+ window = nil
27
+ size = 0
28
+ if stopband_attenuation < 21
29
+ window = Digiproc::RectangularWindow
30
+ size = make_odd(0.9 / transition_width)
31
+ elsif stopband_attenuation < 40
32
+ window = Digiproc::HanningWindow
33
+ size = make_odd(3.1 / transition_width)
34
+ elsif stopband_attenuation < 50
35
+ window = Digiproc::HammingWindow
36
+ size = make_odd(3.3 / transition_width)
37
+ else
38
+ window = Digiproc::BlackmanWindow
39
+ size = make_odd(5.5 / transition_width)
40
+ end
41
+
42
+ case type.to_s.downcase
43
+ when 'lowpass'
44
+ return Filters::lowpass.new(wc: wc, size: size, window: window)
45
+ when 'highpass'
46
+ return Filters::highpass.new(wc: wc, size: size, window: window)
47
+ when 'bandpass'
48
+ return Filters::bandpass.new(wo: wo, bw: bw, size: size, window: window)
49
+ when 'bandstop'
50
+ return Filters::bandstop.new(wo: wo, bw: bw, size: size, window: window)
51
+ else
52
+ raise ArgumentError.new('Filter types include: lowpass, highpass, bandpass, bandstop')
53
+ end
54
+ end
55
+
56
+ ##
57
+ # Input Numeric, output closest round integer >= to input
58
+ def self.make_odd(num)
59
+ n = num.round
60
+ n += 1 if n.even?
61
+ n
62
+ end
63
+
64
+ # An unnecessary inner class that Digiproc::Factories::FilterFactory uses. Only a wrapper to Digiproc::XXXXXFilter
65
+ class Filters
66
+ def self.lowpass
67
+ Digiproc::LowpassFilter
68
+ end
69
+
70
+ def self.highpass
71
+ Digiproc::HighpassFilter
72
+ end
73
+
74
+ def self.bandpass
75
+ Digiproc::BandpassFilter
76
+ end
77
+
78
+ def self.bandstop
79
+ Digiproc::BandstopFilter
80
+ end
81
+ end
82
+
83
+ end
@@ -0,0 +1,22 @@
1
+ ##
2
+ # Factory class for Windows. Can output Digiproc::HanningWindow, Digiproc::HammingWindow, and Digiproc::BlackmanWindow
3
+
4
+ class Digiproc::Factories::WindowFactory
5
+
6
+ ##
7
+ # Decision made based off ofstopband_attenuation
8
+ # @example
9
+ # Digiproc::Factories::WindowFactory.window_for(normalized_transition_width: 0.05, stopband_attenuation: 60) # => outputs Digiproc::BlackmanWindow instance
10
+ def self.window_for(normalized_transition_width: , stopband_attenuation: )
11
+
12
+ if stopband_attenuation < 40
13
+ return Digiproc::HanningWindow.new(norm_trans_freq: normalized_transition_width)
14
+ elsif stopband_attenuation < 50
15
+ return Digiproc::HammingWindow.new(norm_trans_freq: normalized_transition_width)
16
+ else
17
+ return Digiproc::BlackmanWindow.new(norm_trans_freq: normalized_transition_width)
18
+ end
19
+ end
20
+
21
+
22
+ end