digiproc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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