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,29 @@
1
+ points1 = [[2,1,3],[1,2,4],[-3,-2,-4],[1,-2,4]]
2
+ points2 = [[0,1,0],[1,3,3],[-2,-5,-4],[-1,-2,-4]]
3
+
4
+ # => #translate_center_to_origin can take arguments of individual arrays (of the same length), an array of the points, or an array of a hash with
5
+ # the points as the keys and the probability of the points as the value. If no probabilities are given, each point is assumed to be
6
+ # equiprobable. The points are then centered around the origin as to reduce the total energy of the points.
7
+
8
+ min_energy_1 = Digiproc::Functions.translate_center_to_origin(points1)
9
+ min_energy_2 = Digiproc::Functions.translate_center_to_origin(points2)
10
+
11
+ puts "Translated version of #{points1}: \n\t\n#{min_energy_1}"
12
+ puts "\n\n"
13
+ puts "Translated version of #{points2}: \n\t\n#{min_energy_2}"
14
+ puts "\n\n"
15
+ probabilities = [1.0/3, 1.0 / 6, 1.0/6, 1.0/3]
16
+ points_probs_1 = {}
17
+ points_probs_2 = {}
18
+
19
+ for i in 0...points1.length do
20
+ points_probs_1[points1[i]] = probabilities[i]
21
+ points_probs_2[points2[i]] = probabilities[i]
22
+ end
23
+
24
+ min_energy_3 = Digiproc::Functions.translate_center_to_origin(points_probs_1)
25
+ min_energy_4 = Digiproc::Functions.translate_center_to_origin(points_probs_2)
26
+
27
+ puts "Translated version of #{points_probs_1}: \n\t\n#{min_energy_3}"
28
+ puts "\n\n"
29
+ puts "Translated version of #{points_probs_2}: \n\t\n#{min_energy_4}"
@@ -0,0 +1,18 @@
1
+
2
+ gs = Digiproc::Strategies::GramSchmidtOrthonormalize
3
+ eqn1 = ->(t){Math::E ** (-t)}
4
+ eqn2 = ->(t){Math::E ** (-2*t)}
5
+ eqn3 = ->(t){Math::E ** (-3*t)}
6
+
7
+ set1 = Digiproc::AnalogSignal.new(eqn: eqn1, size: 10000, sample_rate:0.1).digitize
8
+ set2 = Digiproc::AnalogSignal.new(eqn: eqn2, size: 10000, sample_rate:0.1).digitize
9
+ set3 = Digiproc::AnalogSignal.new(eqn: eqn3, size: 10000, sample_rate:0.1).digitize
10
+
11
+ out1, out2, out3 = gs.new([set1,set2,set3]).output
12
+
13
+ puts "out1 dot out2 = #{out1.dot out2}"
14
+ puts "out1 dot out3 = #{out1.dot out3}"
15
+ puts "out2 dot out3 = #{out2.dot out3}"
16
+
17
+ puts "All three are orthogonal becacuse their dot products are 0"
18
+
@@ -0,0 +1,81 @@
1
+ # ***** Simple functions examples from Digiproc::Functions and Digiproc::Probability *****
2
+
3
+
4
+ #Gaussian random number generator
5
+ pfuncs = Digiproc::Probability
6
+ nums = []
7
+ 10.times do
8
+ nums << pfuncs.nrand
9
+ end
10
+
11
+ puts "Numbers from gaussian distribution:"
12
+ puts nums.to_s
13
+ puts
14
+
15
+ # Pearson's Correlation Coefficient from Digiproc::Probability
16
+ dist1 = Digiproc::Probability::RealizedGaussianDistribution.new(mean: 0, stddev: 10, size: 100).data
17
+ dist2 = Digiproc::Probability::RealizedGaussianDistribution.new(mean: 0, stddev: 10, size: 100).data
18
+ corr_coeff = pfuncs.correlation_coefficient(dist1, dist2)
19
+ corr_coeff_2 = pfuncs.correlation_coefficient(dist1, Digiproc::Functions.process(dist1, ->(x){x * -2 + 3} ))
20
+
21
+ puts "Correlation coefficient, different random distributions: #{corr_coeff}"
22
+ puts "Correlation coefficient, gain and shifted from same distribution #{corr_coeff_2}"
23
+ puts
24
+
25
+ # stddev, mean, variance, covariance, cdf, q, pdf
26
+
27
+ distribution = Digiproc::Probability::RealizedGaussianDistribution.new(mean: 0, stddev: 10, size: 100).data
28
+
29
+ mean = pfuncs.mean(distribution)
30
+ stddev = pfuncs.stddev(distribution)
31
+ variance = pfuncs.variance(distribution)
32
+ cov = pfuncs.covariance(distribution, distribution)
33
+ pdf = pfuncs.pdf(distribution)
34
+ cdf = pfuncs.normal_cdf(5, mean, stddev)
35
+ q = pfuncs.normal_q(5, mean, stddev)
36
+
37
+
38
+ puts "Mean: #{mean}"
39
+ puts "Std. Deviation: #{stddev}"
40
+ puts "Variance: #{variance}"
41
+ puts "Covaraince: #{cov}"
42
+ # puts "PDF: #{pdf}" => Long print - a big hash of value => occurances count
43
+ puts "CDF of 5, at mean: #{mean}, stddev: #{stddev}: #{cdf}"
44
+ puts "Q of 5, at mean: #{mean}, stddev: #{stddev}: #{q}"
45
+ puts
46
+ puts
47
+
48
+ # linspace(start, stop, num_points)
49
+
50
+ t = Digiproc::Functions.linspace(0, 5, 10)
51
+ puts "Linspace from 0 to 5, 10 numbers"
52
+ puts t.to_s
53
+ puts
54
+
55
+ # factorial (includes memoization, you can build memory to allow fact of larger numbers by incrementing fact size)
56
+
57
+ fns = Digiproc::Functions
58
+ puts "Factorial of 23: #{fns.fact(23)}"
59
+ puts
60
+
61
+ # process(vals, eqn) processes values with an equation
62
+
63
+ eqn = ->(x){ x ** 2 }
64
+ vals = [1,2,3,4,5,6]
65
+ out = fns.process(vals, eqn)
66
+ puts "Output of process: #{out}"
67
+ puts
68
+ puts
69
+
70
+ # maxima, local maxima (relative maxima in order (forward and reverse) -> useful when trying to find local maxima in a fft plot
71
+ # where signals of interest are local maxima not absolute maxima)
72
+
73
+ vals = [1,2,3,4,5,6,5,4,5,4,3,2,5,2,3,4,3,2,3,4,9,6,7,8,7,1]
74
+
75
+ maxima = fns.maxima(vals)
76
+ top_three_maxima = fns.maxima(vals, 3)
77
+ local_maximas = fns.local_maxima(vals, 3)
78
+
79
+ puts "Maxima: #{maxima}"
80
+ puts "Top 3 maxima: #{top_three_maxima}"
81
+ puts "Local maxima (3): #{local_maximas}"
@@ -0,0 +1,13 @@
1
+ # Attempt to solve a system of linear equations using these strategies
2
+
3
+ a = [[2,-3,0],[1,3,-10],[3,0,1]]
4
+ b = [-7,9,13]
5
+
6
+ js = Digiproc::Strategies::JacobiStrategy.new(a,b)
7
+ gs = Digiproc::Strategies::GaussSeidelStrategy.new(a,b)
8
+ sor = Digiproc::Strategies::Sor2Strategy.new(a,b)
9
+
10
+ puts js.calculate
11
+ puts gs.calculate
12
+ puts sor.calculate(w: 0.1)
13
+ puts (Matrix.rows(a).inv * Matrix.column_vector(b)).map(&:to_f)
@@ -0,0 +1,27 @@
1
+ # Iteratively solve a system of linear equations using these strategies
2
+
3
+ a = [[10,4,0,0],[0,7,0,3],[9,0,8,1],[1,0,0,1]]
4
+ b = [52,24,61,5]
5
+
6
+ js = Digiproc::Strategies::JacobiStrategy.new(a,b)
7
+ gs = Digiproc::Strategies::GaussSeidelStrategy.new(a,b)
8
+ sor = Digiproc::Strategies::SorStrategy.new(a,b)
9
+
10
+ puts js.calculate
11
+ puts gs.calculate
12
+ puts sor.calculate(w: 0.5)
13
+ puts (Matrix.rows(a).inv * Matrix.column_vector(b)).map(&:to_f)
14
+
15
+ a = [
16
+ [1,-1,-1,-1,-1,-1],
17
+ [-1,2,0,0,0,0],
18
+ [-1,0,3,1,1,1],
19
+ [-1,0,1,4,2,2],
20
+ [-1,0,1,2,5,3],
21
+ [-1,0,1,2,3,6]
22
+ ]
23
+
24
+ b = [-4,1,5,8,10,11]
25
+
26
+ sor = Digiproc::Strategies::SorStrategy.new(a,b)
27
+ puts sor.calculate(w: 0.5, threshold: 0.000001)
@@ -0,0 +1,119 @@
1
+ # Show that PSK and DPSK modulated signals have the same bandwidth
2
+
3
+ # Define DPSK encoding/decoding strategy
4
+ dpsk_strategy = Digiproc::Strategies::XORDifferentialEncodingZeroAngleStrategy
5
+
6
+ # *********** NOTE: Digiproc::Strategies::DifferentialEncodingStrategy encodes for an M-ary PSK signal, requires decoding
7
+ # via reciever in figure 4-15 of INTRODUCITON TO DIGITAL COMMUNICATION, ZIEMER, PETERSON which has not been implemented.
8
+
9
+ # Not adding a coding strategy into PSK causes bit to phase mapping to not be differentially encoded
10
+
11
+ # Make a 100-bit stream, make one PSK (Phase Shift Keying) and one DPSK (Differential PSK) signal, plot the frequency domians
12
+
13
+ signal2 = Digiproc::Probability::RandomBitGenerator.new_bitstream.generate(600).split('')
14
+ psk2 = Digiproc::Strategies::PSK.new(modulating_signal: signal2, carrier_frequency: 10, pulse_length: 0.05)
15
+ dpsk2 = Digiproc::Strategies::PSK.new(modulating_signal: signal2, coding_strategy: dpsk_strategy, carrier_frequency: 10, pulse_length: 0.05)
16
+
17
+ puts "PSK Signal"
18
+ puts "Coded"
19
+ puts psk2.coded_signal.to_s
20
+ puts "Phase"
21
+ puts psk2.phase_signal.to_s
22
+
23
+
24
+ puts "DPSK Signal"
25
+ puts "Coded"
26
+ puts dpsk2.coded_signal.to_s
27
+ puts "Phase"
28
+ puts dpsk2.phase_signal.to_s
29
+
30
+ puts "Original signal:"
31
+ puts "#{signal2}"
32
+ puts "Decoded signal:"
33
+ # NOTE: decoded signals are not simulating a reciever, but just reversing the coding strategy
34
+ puts "DPSK"
35
+ puts "#{dpsk2.decode}"
36
+ puts "PSK"
37
+ puts "#{psk2.decode}"
38
+ puts "Match check"
39
+ puts "DPSK decode matches original:"
40
+ puts signal2 == dpsk2.decode
41
+ puts "PSK decode matches original:"
42
+ puts signal2 == psk2.decode.map{ |i| i.to_i.to_s }
43
+
44
+ # Below simulates a receiver per fig. 4-14 in INTRODUCTION TO DIGITAL COMMUNICATIONS, ZIEMER, PETERSON
45
+ # Reciever is of the form: phase signal -> Bandwidth Filter 0.57 / Tb -> Delay -> multiply -> Lowpass Filter -> Sample at t = Tb -> Output
46
+ #|-bypass-->{up_arrow}
47
+
48
+ #Example below fails, if you have time and want to help troubleshoot, please contribute! First
49
+ # 200 samples are showing up, and the rest seem to be wrapped in the front of the ifft. See
50
+ # Digiproc::Strategies::PSK#reciever_out for troubleshooting
51
+
52
+ puts "Simulated DPSK reciever output:"
53
+ receiver_out = dpsk2.reciever_decode
54
+ puts receiver_out.to_s
55
+ puts receiver_out.map{ |i| i.to_f <=> 0 }.map{ |i| i == -1 ? 0 : 1 }.to_s
56
+ puts "Test equality of signal"
57
+ test_sig = receiver_out.map{ |i| (i.to_f <=> 0).to_s }.map{ |i| i == "-1" ? "0" : "1" }
58
+
59
+ # Note - this reciever only works for small signals at this time.
60
+ # The FFT funciton needs to be optimized to automatically set the appropriate size
61
+ # based off of the input function
62
+
63
+
64
+
65
+ puts test_sig.size
66
+ puts signal2.size
67
+ puts test_sig == signal2
68
+ puts test_sig == signal2.take(test_sig.length)
69
+
70
+ test_sig.each_with_index do |sym, i|
71
+ if test_sig[i] != signal2[i]
72
+ puts "Signal fails at index #{i}"
73
+ puts signal2[i - 10, 50].to_s
74
+ puts test_sig[i - 10, 50].to_s
75
+ break
76
+ end
77
+ end
78
+
79
+ path = "./examples/modulation_schemes/"
80
+
81
+ Digiproc::QuickPlot.plot(data: psk2.output.to_ds.fft.magnitude, title: "PSK 2", path: path)
82
+ Digiproc::QuickPlot.plot(data: dpsk2.output.to_ds.fft.magnitude, title: "DPSK 2", path: path)
83
+
84
+ # Make 75 8-bit symbols, make one PSK and one DPSK signal, plot the frequency domians
85
+ signal256 = Digiproc::Probability::RandomBitGenerator.new_symbol_stream(bits_per_symbol: Math.log(256,2).to_i).generate 75
86
+ psk256 = Digiproc::Strategies::PSK.new(modulating_signal: signal256, carrier_frequency: 10, pulse_length: 0.4)
87
+ dpsk256 = Digiproc::Strategies::PSK.new(modulating_signal: signal256, coding_strategy: dpsk_strategy ,carrier_frequency: 10, pulse_length: 0.4)
88
+ s = signal256.map{|a| a.to_i(2)}
89
+
90
+ puts "Original signal"
91
+ puts s.to_s
92
+ puts
93
+ puts "DPSK Signal"
94
+ puts "Coded"
95
+ puts dpsk256.coded_signal.to_s
96
+ puts "Phase"
97
+ puts dpsk256.phase_signal.to_s
98
+ puts
99
+ puts "PSK Signal"
100
+ puts "Coded"
101
+ puts psk256.coded_signal.to_s
102
+ puts "Phase"
103
+ puts psk256.phase_signal.to_s
104
+
105
+ Digiproc::QuickPlot.plot(data: psk256.output.to_ds.fft.magnitude, title: "PSK 256", path: path)
106
+ Digiproc::QuickPlot.plot(data: dpsk256.output.to_ds.fft.magnitude, title: "DPSK 256", path: path)
107
+
108
+ puts "Original Signal"
109
+ puts "#{signal256}"
110
+
111
+ puts "Decoded signal"
112
+ puts "Decoded DPSK"
113
+ puts "#{dpsk256.decode}"
114
+ puts "Decoded PSK"
115
+ puts "#{psk256.decode}"
116
+
117
+ puts "Match check:"
118
+ puts "#{signal256 == dpsk256.decode}"
119
+ puts "#{signal256 == psk256.decode.map{ |i| i.to_i.to_s }}"
@@ -0,0 +1,36 @@
1
+ plt = Digiproc::QuickPlot
2
+
3
+ sig_str = "110100010110"
4
+ sig = sig_str.split('')
5
+ diff_sig = Digiproc::Strategies::XORDifferentialEncodingStrategy.encode(sig, 2, "0")
6
+
7
+ bpsk = Digiproc::Strategies::PSK.new(modulating_signal: diff_sig, coding_strategy: nil)
8
+ bdpsk = Digiproc::Strategies::PSK.new(modulating_signal: sig)
9
+ dpsk = Digiproc::Strategies::PSK.new(modulating_signal: sig, coding_strategy: Digiproc::Strategies::DifferentialEncodingStrategy)
10
+
11
+ puts "System 1 Differential Signal: #{bpsk.coded_signal}"
12
+ puts "System 1 Phase: #{bpsk.phase_signal.map{ |ps| ps / Math::PI }} * pi"
13
+ puts "System 1 Decoded: #{bpsk.decode}"
14
+ plt.plot(data: bpsk.phase_signal.map{ |p| p / Math::PI}, y_label: "Phase", title: "System 1 Phase")
15
+ puts "\n\n"
16
+ puts "System 2 Differential Signal: #{bdpsk.coded_signal}"
17
+ puts "System 2 Coded Phase: #{bdpsk.phase_signal.map{ |ps| ps / Math::PI}} * pi"
18
+ puts "System 2 Decoded: #{bdpsk.decode}"
19
+ plt.plot(data: bdpsk.phase_signal.map{ |p| p / Math::PI},y_label: "Phase", title: "System 2 Phase")
20
+ puts "\n\n"
21
+
22
+ puts "System 3 Signal: #{dpsk.coded_signal}"
23
+ puts "System 3 Coded Phase: #{dpsk.phase_signal.map{ |p| p / Math::PI}} * pi"
24
+ puts "System 3 Decoded: #{dpsk.decode}"
25
+ plt.plot(data: dpsk.phase_signal.map{ |p| p / Math::PI},y_label: "Phase", title: "System 3 Phase")
26
+ puts "\n\n"
27
+
28
+ # dpsk_output = dpsk.output
29
+ # time_range = Digiproc::Functions.linspace(0, dpsk_output.sample_rate * dpsk_output.size, dpsk_output.size)
30
+ path = "./examples/modulation_schemes/"
31
+ plt.plot(data: bpsk.output.digitize, title: "System 1 Xmit Signal", y_label: "Magnitude", dark: true, path: path)
32
+ plt.plot(data: bdpsk.output.digitize, title: "System 2 Xmit Signal", y_label: "Magnitude", dark: true, path: path)
33
+ plt.plot(data: dpsk.output.digitize, title: "System 3 Xmit Signal", y_label: "Magnitude", dark: true, path: path)
34
+ puts "System 1 Output From Reciever: \n#{bpsk.reciever_decode}\n\n"
35
+ puts "System 2 Output From Reciever: \n#{bdpsk.reciever_decode}\n\n"
36
+ puts "System 3 Output From Reciever: \n#{dpsk.reciever_decode}\n\n"
@@ -0,0 +1,13 @@
1
+ # DISREGARD THIS EXAMPLE
2
+
3
+ #Using Gruff Line
4
+
5
+ #Below does not work, needs to be re-worked
6
+
7
+
8
+ g = Gruff::Line.new('1000x1000')
9
+ distr = Digiproc::Probability::RealizedGaussianDistribution.new(mean: 0, stddev: 3, size: 100)
10
+ g.data :random, distr.data
11
+ gnew = Digiproc::Plottable::ClassMethods::VerticalLine.new(g, 30)
12
+ gnew.write('./examples/quickplot/test.png')
13
+
Binary file
@@ -0,0 +1,85 @@
1
+ # Use gruff directly
2
+ g = Gruff::Line.new('1000x1000')
3
+ distr = Digiproc::Probability::GaussianDistribution.new(mean: 0, stddev: 3, size: 100)
4
+ g.data("Random data", distr.data)
5
+ g.write('./examples/quickplot/direct_gruff.png')
6
+
7
+ path = "./examples/quickplot/"
8
+
9
+
10
+ # Using QuickPlot
11
+
12
+ plt = Digiproc::QuickPlot
13
+ plt.plot(title: "Random data QuickPlot", data: distr.data, path: path, data_name: "Random distr.")
14
+ plt.plot(title: "Random data QuickPlot, dark", data: distr.data, path: path, x_label: "x axis", y_label: "y axis",dark: true)
15
+
16
+
17
+
18
+
19
+
20
+ # Using Plottable Module inside a class
21
+
22
+ # Big advantage of not using QuickPlot is the ability to use xsteps as a parameter which specifies the label
23
+ # interval on the x axis of the plot
24
+ class PlottableClass
25
+
26
+ extend Digiproc::Plottable::ClassMethods
27
+ include Digiproc::Plottable::InstanceMethods
28
+
29
+ def initialize(distr)
30
+ @distr = distr
31
+ end
32
+
33
+ def data
34
+ return @distr.data
35
+ end
36
+
37
+ end
38
+
39
+ plot = PlottableClass
40
+
41
+ plot.qplot(data: distr.data, data_name: "Random distribution",xsteps: 10, path: path) do |g|
42
+ g.title = "Random Data Plottable qPlot"
43
+ g.x_axis_label = "x axis"
44
+ g.y_axis_label = "y axis"
45
+ end
46
+
47
+ plot_instance = PlottableClass.new(distr)
48
+
49
+ # Instnace Methods includes qplot which is the same as above
50
+ # plot used below should be renamed to fftPlot() - it was created to plot
51
+ # a Discrete Fourier Transform - the x axis goes from 0 to 1 regardless of
52
+ # points in the dataset to correspond to normalized frequency in a DFT plot.
53
+
54
+ plot_instance.plot(method: :data, xsteps: 10, path: path) do |g|
55
+ g.title = "Random Data from Instance Method"
56
+ g.x_axis_label = "x axis"
57
+ g.y_axis_label = 'y axis'
58
+ end
59
+
60
+
61
+ ## You can use Digiproc::Plottable class methods as well: (TODO)
62
+
63
+
64
+
65
+ ## Using Rbplot
66
+
67
+ x = Digiproc::Functions.linspace(1,100,100)
68
+ y1 = Digiproc::Probability.nrand(100)
69
+ y2 = Digiproc::Probability.nrand(100)
70
+
71
+ plt = Digiproc::Rbplot.line(x,y1)
72
+ plt.size(2000,2000)
73
+ plt.title('Test title')
74
+ plt.xlabel('x axis')
75
+ plt.ylabel('y axis')
76
+ plt.xsteps(10)
77
+ plt.add_line(x, y2)
78
+ plt.add_line(x,x.map{ |a| a / 100})
79
+ plt.theme(:light)
80
+ plt.legend('set1', 'set2', 'set3')
81
+ plt.show
82
+ plt.title('Test title dark')
83
+ plt.theme(:dark)
84
+ plt.show
85
+
@@ -0,0 +1,23 @@
1
+ plt = Dsp::QuickPlot
2
+ gauss = Dsp::Probability::RealizedGaussianDistribution
3
+ fns = Dsp::Functions
4
+
5
+ distribution = gauss.new(mean: 0, stddev: 10, size: 100)
6
+ data = distribution.data
7
+
8
+ #qplot function in quickplot gives a different plot API
9
+ plt.qplot(data: data, path: './examples/realized_gaussian/', filename: 'norm_dist_plot', xsteps: 10, data_name: "normal random numbers") do |g|
10
+ g.title = "Gaussian Random Numbers"
11
+ g.theme = Dsp::Plottable::Styles::MIDNIGHT
12
+ g.show_vertical_markers = false
13
+ end
14
+
15
+ spectra = fns.fft(data).map(&:abs)
16
+ x_vals = fns.linspace(0,128,128)
17
+
18
+ plt.qplot(data: spectra, path: './examples/realized_gaussian/', filename: 'norm_dist_spectrum', xsteps: 4, xyname: "spectra mag. of norm. random nums") do |g|
19
+ g.title = "Gaussian Nums: Frequency Domain"
20
+ g.labels = {0 => 0, 32 => 0.25, 64 => 0.5, 98 => 0.75, 127 => 1}
21
+ g.show_vertical_markers = false
22
+ end
23
+
@@ -0,0 +1,144 @@
1
+
2
+ module Digiproc::Convolvable
3
+
4
+
5
+ ##
6
+ # This module contains class methods for performing convolution based off a strategy. Digiproc::Convolvable
7
+ # extends ClassMethods, and therefore all methods can be called on the Convolable module.
8
+ # Note that arrays in this module must be of Numeric types
9
+
10
+ module ClassMethods
11
+ ##
12
+ ## convolve(data1 [Array], data2 [Array], strategy [ConvolutionStrategy]) => returns Array[Numeric]
13
+ # This method performs convolution.
14
+ # `strategy` can be custom-written as long as it matches the ConvolutionStrategy interface:
15
+ # have a class method called `conv` which takes 2 arrays and convolves them. ie:
16
+ ## Digiproc::Convolvable.conv([1,2,3],[1,2,3]) #=> [1, 4, 10, 12, 9]
17
+
18
+ def convolve(data1, data2, strategy = Digiproc::Strategies::BFConvolutionStrategy)
19
+ strategy.conv(data1, data2, strategy)
20
+ end
21
+
22
+ ##
23
+ # Alias to #convolve
24
+ def conv(data1, data2, strategy = Digiproc::Strategies::BFConvolutionStrategy)
25
+ strategy.conv(data1,data2)
26
+ end
27
+
28
+ ##
29
+ ## cross_correlation(data1 [Array], data2 [Array]) => returns Array[Numeric]
30
+ # Uses the #conv method to perform cross_correlation by reversing the second data set order
31
+ # Does not accept a strategy as a third parameter
32
+ ## Digiproc::Convolvable.cross_correlation(arr1, arr2)
33
+ def cross_correlation(data1, data2)
34
+ conv(data1, data2.reverse)
35
+ end
36
+
37
+ ##
38
+ # Alias to #cross_correlation
39
+ def xcorr(data1, data2)
40
+ cross_correlation(data1, data2)
41
+ end
42
+
43
+ ##
44
+ ## auto_correlation(data [Array]) => returns Array[Numeric]
45
+ # Uses the cross_correlation method to perform cross correlation of data on itself.
46
+ ## Digiproc::Convolvable.auto_correlation([1,2,3]) # => [3, 8, 14, 8, 3]
47
+ def auto_correlation(data)
48
+ cross_correlation(data, data)
49
+ end
50
+
51
+
52
+ ##
53
+ # Alias to #auto_correlation
54
+ # ie:
55
+ ## Digiproc::Convolvable.acorr([1,2,3]) # => [3, 8, 14, 8, 3]
56
+ def acorr(data)
57
+ cross_correlation(data, data)
58
+ end
59
+
60
+ end
61
+
62
+ ##
63
+ # This module contains instance methods for classes which have properties of `data` which
64
+ # are arrays and can undergo convolution, correlation, cross-correlation, and autocorrelation (arrays must then be of Numerics). As such, if
65
+ # a class `includes` Convolvable::InstanceMethods, it is also including `Digiproc::RequiresData` which ensures that the
66
+ # class has a `data` property
67
+
68
+ module InstanceMethods
69
+
70
+ ##
71
+ # When included in a class, it automatically has that class include Digiproc::RequiresData, because methods in this module require that there be a property called `data` which is an Array
72
+ def self.included(base)
73
+ base.class_eval do
74
+ include Digiproc::RequiresData
75
+ end
76
+ end
77
+
78
+ ##
79
+ # Optionally initializable with a `ConvolutionStrategy` (see `Digiproc::Initializable`)
80
+ # This snows up as new, but when using this code, :initialize will be called. This pattern is utilized in the Digiproc::DigitalSignal class, and can be seen in its initializer.
81
+ def initialize(strategy: Digiproc::Strategies::BFConvolutionStrategy)
82
+ @convolution_strategy = strategy
83
+ end
84
+
85
+ ##
86
+ ## convolve(incoming_data [Array [OR a class including Digiproc::RequiresData]]) => returns Array[Numeric]
87
+ # uses the `strategy` class to convolve the included class' data property with the array provided as an argument
88
+ # ie if class DataHolder includes Convolavable::InstanceMethods, and you have two instances, d1 and d2, you can say:
89
+ ## d1.convolve(d2)
90
+ # Or, if you have a 1D array of numerics in variable `my_data_arr` capable of convolving with d1.data, you can say:
91
+ ## d1.convolve(my_data_arr) # returns array of data
92
+ def convolve(incoming_data)
93
+ incoming_data = incoming_data.is_a?(Array) ? incoming_data : incoming_data.data
94
+ self.convolution_strategy.conv(self.data, incoming_data)
95
+ end
96
+
97
+ ##
98
+ # Alias to convolve
99
+ def conv(incoming_data)
100
+ self.convolve(incoming_data)
101
+ end
102
+
103
+ ##
104
+ # Used internally to ensure that if the class which includes this module is not `Initializable`, then a Convolution strategy will still be set
105
+ # In this case, use Digiproc::BFConvolutionStrategy
106
+ def convolution_strategy
107
+ @convolution_strategy.nil? ? Digiproc::Strategies::BFConvolutionStrategy : @convolution_strategy
108
+ end
109
+
110
+ ##
111
+ ## cross_correlation(incoming_data [Array [OR a class extending Digiproc::RequiresData]]) => returns Array[Numeric]
112
+ # see #convolve for example of using an array or a Digiproc::RequiresData. ie:
113
+ ## includingInstance.cross_correlation(array_data) # returns array of data
114
+ def cross_correlation(incoming_data)
115
+ incoming_data = incoming_data.is_a?(Array) ? incoming_data : incoming_data.data
116
+ self.convolution_strategy.conv(self.data, incoming_data.reverse)
117
+ end
118
+
119
+ ##
120
+ # Alias to cross_correlation
121
+ def xcorr(incoming_data)
122
+ self.cross_correlation(incoming_data)
123
+ end
124
+
125
+ ##
126
+ ## auto_correlation() => returns Array[Numeric]
127
+ # Performs autocorrelation of self.data ie:
128
+ ## includingInstance.auto_correlation # returns array of data
129
+ def auto_correlation
130
+ self.cross_correlation(self.data)
131
+ end
132
+
133
+ ##
134
+ # Alias to auto_correlation
135
+ def acorr
136
+ self.cross_correlation(self.data)
137
+ end
138
+
139
+
140
+ end
141
+
142
+ extend self::ClassMethods
143
+
144
+ end