digiproc 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +48 -0
- data/LICENSE.txt +21 -0
- data/README.md +78 -0
- data/Rakefile +37 -0
- data/TODO.md +50 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/config/environment.rb +118 -0
- data/console_tests.rb +44 -0
- data/digiproc.gemspec +49 -0
- data/examples/analog_signals/analog_to_digital.rb +31 -0
- data/examples/analog_signals/companded-signals.png +0 -0
- data/examples/analog_signals/companding.rb +68 -0
- data/examples/analog_signals/fft-plot.png +0 -0
- data/examples/analog_signals/plot_Digiproc::FFT.png +0 -0
- data/examples/analog_signals/plot_Dsp::FFT.png +0 -0
- data/examples/analog_signals/quantization-outputs.png +0 -0
- data/examples/analog_signals/quantize_compand.rb +69 -0
- data/examples/binomial_distribution/bit_error.rb +14 -0
- data/examples/binomial_distribution/dice.rb +35 -0
- data/examples/digital_signals/_coded_frequency_signal,_ts_=_1_s.png +0 -0
- data/examples/digital_signals/_coded_frequency_signal,_ts_=_2_s.png +0 -0
- data/examples/digital_signals/coded_power_spectral_density,__ts_=_1_s.png +0 -0
- data/examples/digital_signals/coded_power_spectral_density,__ts_=_2_s.png +0 -0
- data/examples/digital_signals/coded_time_signal,_ts_=_1_s.png +0 -0
- data/examples/digital_signals/coded_time_signal,_ts_=_2_s.png +0 -0
- data/examples/digital_signals/freq_sig_from_eqn,_ts_=_1_s.png +0 -0
- data/examples/digital_signals/freq_sig_from_eqn,_ts_=_2_s.png +0 -0
- data/examples/digital_signals/frequency_signal,_ts_=_1_s.png +0 -0
- data/examples/digital_signals/frequency_signal,_ts_=_2_s.png +0 -0
- data/examples/digital_signals/modulate_square_pulses.rb +9 -0
- data/examples/digital_signals/modulated_sq._pulses.png +0 -0
- data/examples/digital_signals/modulated_sq._pulses_alt.png +0 -0
- data/examples/digital_signals/power_spectral_density,__ts_=_1_s.png +0 -0
- data/examples/digital_signals/power_spectral_density,__ts_=_2_s.png +0 -0
- data/examples/digital_signals/square_signals.rb +90 -0
- data/examples/digital_signals/time_signal,_ts_=_1_s.png +0 -0
- data/examples/digital_signals/time_signal,_ts_=_2_s.png +0 -0
- data/examples/encoding/gray_code.rb +22 -0
- data/examples/encoding/psk.rb +91 -0
- data/examples/encoding/system_2_phase.png +0 -0
- data/examples/encoding/system_2_xmit_signal.png +0 -0
- data/examples/encoding/system_3_phase.png +0 -0
- data/examples/encoding/system_3_xmit_signal.png +0 -0
- data/examples/encoding/system_4_xmit_signal.png +0 -0
- data/examples/encoding/xor-dpsk-phase-signal-(sys1).png +0 -0
- data/examples/encoding/xor-dpsk-xmit-signal-(sys-1).png +0 -0
- data/examples/factories/Quickplot Graph.png +0 -0
- data/examples/factories/bandpass.rb +6 -0
- data/examples/fft/plot_Dsp::FFT.png +0 -0
- data/examples/fft/recieved_data_(time_domain).png +0 -0
- data/examples/fft/simple_fft_example.rb +47 -0
- data/examples/fft/unprocessed_fft.png +0 -0
- data/examples/filters/bandpass_filter.png +0 -0
- data/examples/filters/filter_a_signal.rb +38 -0
- data/examples/filters/white_noise_db_out_of_bp_filter.png +0 -0
- data/examples/filters/white_noise_mag_out_of_bp_filter.png +0 -0
- data/examples/filters/white_noise_spectra.png +0 -0
- data/examples/functions/compute_probability.rb +29 -0
- data/examples/functions/gram_schmidt.rb +10 -0
- data/examples/functions/minimize_energy.rb +29 -0
- data/examples/functions/orthoganalize.rb +18 -0
- data/examples/functions/simple_functions.rb +81 -0
- data/examples/linear_algebra/diverging_sys.rb +13 -0
- data/examples/linear_algebra/iterative_sys_of_eqns_methods.rb +27 -0
- data/examples/modulation_schemes/dpsk_2.png +0 -0
- data/examples/modulation_schemes/dpsk_256.png +0 -0
- data/examples/modulation_schemes/dpsk_freq_domain.rb +119 -0
- data/examples/modulation_schemes/psk.rb +36 -0
- data/examples/modulation_schemes/psk_2.png +0 -0
- data/examples/modulation_schemes/psk_256.png +0 -0
- data/examples/modulation_schemes/psksystem_1_xmit_signal.png +0 -0
- data/examples/modulation_schemes/psksystem_2_xmit_signal.png +0 -0
- data/examples/modulation_schemes/psksystem_3_xmit_signal.png +0 -0
- data/examples/modulation_schemes/system_1_xmit_signal.png +0 -0
- data/examples/modulation_schemes/system_2_xmit_signal.png +0 -0
- data/examples/modulation_schemes/system_3_xmit_signal.png +0 -0
- data/examples/quickplot/PlottableClass_plot.png +0 -0
- data/examples/quickplot/decorators.rb +13 -0
- data/examples/quickplot/direct_gruff.png +0 -0
- data/examples/quickplot/plot_PlottableClass.png +0 -0
- data/examples/quickplot/quickplot_vs_others.rb +85 -0
- data/examples/quickplot/random_data_quickplot,_dark.png +0 -0
- data/examples/quickplot/random_data_quickplot.png +0 -0
- data/examples/realized_gaussian/norm_dist_plot.png +0 -0
- data/examples/realized_gaussian/norm_dist_spectrum.png +0 -0
- data/examples/realized_gaussian/realized_gaussian_example.rb +23 -0
- data/lib/concerns/convolvable.rb +144 -0
- data/lib/concerns/data_properties.rb +223 -0
- data/lib/concerns/fourier_transformable.rb +178 -0
- data/lib/concerns/initializable.rb +43 -0
- data/lib/concerns/multipliable.rb +22 -0
- data/lib/concerns/os.rb +36 -0
- data/lib/concerns/plottable.rb +248 -0
- data/lib/concerns/requires_data.rb +8 -0
- data/lib/digiproc/version.rb +8 -0
- data/lib/digiproc.rb +2 -0
- data/lib/extensions/array_extension.rb +23 -0
- data/lib/extensions/core_extensions.rb +117 -0
- data/lib/factories/factories.rb +3 -0
- data/lib/factories/filter_factory.rb +83 -0
- data/lib/factories/window_factory.rb +22 -0
- data/lib/fft.rb +255 -0
- data/lib/filters/bandpass_filter.rb +43 -0
- data/lib/filters/bandstop_filter.rb +44 -0
- data/lib/filters/digital_filter.rb +59 -0
- data/lib/filters/highpass_filter.rb +27 -0
- data/lib/filters/lowpass_filter.rb +27 -0
- data/lib/functions.rb +221 -0
- data/lib/probability/binomial_distribution.rb +84 -0
- data/lib/probability/bit_generator.rb +94 -0
- data/lib/probability/gaussian_distribution.rb +29 -0
- data/lib/probability/probability.rb +234 -0
- data/lib/probability/theoretical_gaussian_distribution.rb +59 -0
- data/lib/quick_plot.rb +96 -0
- data/lib/rbplot.rb +219 -0
- data/lib/signals/analog_signal.rb +143 -0
- data/lib/signals/digital_signal.rb +181 -0
- data/lib/strategies/code/differential_encoding_strategy.rb +69 -0
- data/lib/strategies/code/gray_code.rb +75 -0
- data/lib/strategies/code/xor_differential_encoding_strategy.rb +100 -0
- data/lib/strategies/code/xor_differential_encoding_zero_angle_strategy.rb +103 -0
- data/lib/strategies/companding/custom_companding_strategy.rb +29 -0
- data/lib/strategies/convolution/bf_conv.rb +57 -0
- data/lib/strategies/fft/brute_force_dft_strategy.rb +31 -0
- data/lib/strategies/fft/inverse_fft_conjugate_strategy.rb +44 -0
- data/lib/strategies/fft/radix2_strategy.rb +84 -0
- data/lib/strategies/gaussian/gaussian_generator.rb +49 -0
- data/lib/strategies/linear_algebra/gauss_seidel_strategy.rb +90 -0
- data/lib/strategies/linear_algebra/jacobi_strategy.rb +81 -0
- data/lib/strategies/linear_algebra/sor2_strategy.rb +98 -0
- data/lib/strategies/linear_algebra/sor_strategy.rb +108 -0
- data/lib/strategies/modulation/phase_shift_keying_strategy.rb +96 -0
- data/lib/strategies/orthogonalize/gram_schmidt.rb +50 -0
- data/lib/strategies/strategies.rb +3 -0
- data/lib/strategies/window/blackman_window.rb +32 -0
- data/lib/strategies/window/hamming_window.rb +31 -0
- data/lib/strategies/window/hanning_window.rb +31 -0
- data/lib/strategies/window/kaiser_window.rb +27 -0
- data/lib/strategies/window/rectangular_window.rb +22 -0
- data/lib/strategies/window/window.rb +42 -0
- data/lib/systems/custom_system.rb +13 -0
- data/lib/systems/hilbert_transform.rb +6 -0
- data/lib/systems/matched_filter.rb +21 -0
- data/lib/systems/raised_cosine_filter.rb +11 -0
- data/lib/systems/system.rb +19 -0
- data/lib/systems/systems.rb +3 -0
- data/playground.rb +323 -0
- data/plots/_coded_frequency_signal,_ts_=_1_s.png +0 -0
- data/plots/_coded_frequency_signal,_ts_=_2_s.png +0 -0
- data/plots/coded_freq_sig_from_eqn,_ts_=_1_s.png +0 -0
- data/plots/coded_freq_sig_from_eqn,_ts_=_2_s.png +0 -0
- data/plots/coded_power_spectral_density,__ts_=_1_s.png +0 -0
- data/plots/coded_power_spectral_density,__ts_=_2_s.png +0 -0
- data/plots/coded_time_signal,_ts_=_1_s.png +0 -0
- data/plots/coded_time_signal,_ts_=_2_s.png +0 -0
- data/plots/dpsk_2.png +0 -0
- data/plots/freq_sig_from_eqn,_ts_=_1_s.png +0 -0
- data/plots/freq_sig_from_eqn,_ts_=_2_s.png +0 -0
- data/plots/frequency_signal,_ts_=_1_s.png +0 -0
- data/plots/frequency_signal,_ts_=_2_s.png +0 -0
- data/plots/power_spectral_density,__ts_=_1_s.png +0 -0
- data/plots/power_spectral_density,__ts_=_2_s.png +0 -0
- data/plots/psk_2.png +0 -0
- data/plots/time_signal,_ts_=_1_s.png +0 -0
- data/plots/time_signal,_ts_=_2_s.png +0 -0
- data/test-title-dark.png +0 -0
- data/test-title.png +0 -0
- 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)
|
Binary file
|
Binary file
|
@@ -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"
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -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
|
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
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -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
|