Class: Digiproc::Strategies::PSK
- Inherits:
-
Object
- Object
- Digiproc::Strategies::PSK
- Defined in:
- lib/strategies/modulation/phase_shift_keying_strategy.rb
Instance Attribute Summary collapse
-
#carrier_frequency ⇒ Object
Returns the value of attribute carrier_frequency.
-
#carrier_signal_eqn ⇒ Object
Returns the value of attribute carrier_signal_eqn.
-
#coded_signal ⇒ Object
Returns the value of attribute coded_signal.
-
#coding_strategy ⇒ Object
Returns the value of attribute coding_strategy.
-
#m ⇒ Object
Returns the value of attribute m.
-
#modulating_signal ⇒ Object
Returns the value of attribute modulating_signal.
-
#phase_shift_eqn ⇒ Object
Returns the value of attribute phase_shift_eqn.
-
#phase_signal ⇒ Object
Returns the value of attribute phase_signal.
-
#pulse_length ⇒ Object
Returns the value of attribute pulse_length.
-
#signal_to_phase ⇒ Object
Returns the value of attribute signal_to_phase.
Instance Method Summary collapse
-
#decode ⇒ Object
Apply inverse of the PSK strategy to decode the PSK signal.
-
#initialize(carrier_signal_eqn: ->(a, fo, t, theta){ a * Math.cos(2*Math::PI * fo * t + theta) }, modulating_signal:, coding_strategy: nil, carrier_frequency: 10000, pulse_length: 0.00015) ⇒ PSK
constructor
Initialize Args modulating_signal:: Array; each element is a “symbol” (should be a string reprisenting bits), where a symnbol is a number of bits symbolizing a single character (ie symbol means character) carrier_signal_eqn (optional):: Lambda (or Proc) default value is: ->(a, fo, t, theta){ a * Math.cos(2*Math::PI * fo * t + theta) } coding_strategy (optional):: Protocol, see Digiproc::Strategies::XORDifferentialEncodingZeroAngleStrategy, default value is nil carrier_frequency (optional)::Numeric (in Hz), defaults to 10000 pulse_length (optional):: Float (in seconds), defaults to 0.00015 determines how long to apply a phase shift.
-
#output(a: 1) ⇒ Object
Input Args a (optional):: Numeric for amplitude of the signal (default value = 1) Return Digiproc::AnalogSignal of the Phase Shift Keyed signal.
-
#reciever_decode ⇒ Object
Based off of reciever Figure 4-15 INTRODUCTION TO DIGITAL COMMUNICATIONS, ZIEMER, PETERSON pg 237 NOTE: SUBOPTIMUM DETECTOR, optimum detector referenced on the above page, different reference This simulates a real-life reciever recieving the siglans and decoding them.
Constructor Details
#initialize(carrier_signal_eqn: ->(a, fo, t, theta){ a * Math.cos(2*Math::PI * fo * t + theta) }, modulating_signal:, coding_strategy: nil, carrier_frequency: 10000, pulse_length: 0.00015) ⇒ PSK
Initialize Args
- modulating_signal
-
Array; each element is a “symbol” (should be a string reprisenting bits), where a symnbol is a number of bits symbolizing a single character (ie symbol means character)
- carrier_signal_eqn (optional)
-
Lambda (or Proc) default value is: ->(a, fo, t, theta){ a * Math.cos(2*Math::PI * fo * t + theta) }
- coding_strategy (optional)
-
Protocol, see Digiproc::Strategies::XORDifferentialEncodingZeroAngleStrategy, default value is nil
carrier_frequency (optional)::Numeric (in Hz), defaults to 10000
- pulse_length (optional)
-
Float (in seconds), defaults to 0.00015 determines how long to apply a phase shift
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 12 def initialize(carrier_signal_eqn: ->(a, fo, t, theta){ a * Math.cos(2*Math::PI * fo * t + theta) }, modulating_signal: ,coding_strategy: nil, carrier_frequency: 10000, pulse_length: 0.00015) @carrier_signal_eqn, @modulating_signal, @coding_strategy, @carrier_frequency, @pulse_length = carrier_signal_eqn, modulating_signal, coding_strategy, carrier_frequency, pulse_length @m = 2 ** modulating_signal.first.length if coding_strategy.nil? @phase_shift_eqn = ->(i){ (2.0 * Math::PI * (i)) / @m } @coded_signal = @modulating_signal else @phase_shift_eqn = coding_strategy.phase_shift_eqn(@m) @coded_signal = coding_strategy.encode modulating_signal, @m, "0" end @signal_to_phase = {} for i in 0...@m do @signal_to_phase[i.to_s] = @phase_shift_eqn[i] end @phase_signal = @coded_signal.map{ |coded_symbol| @phase_shift_eqn[coded_symbol.to_i(2)] } end |
Instance Attribute Details
#carrier_frequency ⇒ Object
Returns the value of attribute carrier_frequency.
3 4 5 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 3 def carrier_frequency @carrier_frequency end |
#carrier_signal_eqn ⇒ Object
Returns the value of attribute carrier_signal_eqn.
3 4 5 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 3 def carrier_signal_eqn @carrier_signal_eqn end |
#coded_signal ⇒ Object
Returns the value of attribute coded_signal.
3 4 5 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 3 def coded_signal @coded_signal end |
#coding_strategy ⇒ Object
Returns the value of attribute coding_strategy.
3 4 5 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 3 def coding_strategy @coding_strategy end |
#m ⇒ Object
Returns the value of attribute m.
3 4 5 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 3 def m @m end |
#modulating_signal ⇒ Object
Returns the value of attribute modulating_signal.
3 4 5 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 3 def modulating_signal @modulating_signal end |
#phase_shift_eqn ⇒ Object
Returns the value of attribute phase_shift_eqn.
3 4 5 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 3 def phase_shift_eqn @phase_shift_eqn end |
#phase_signal ⇒ Object
Returns the value of attribute phase_signal.
3 4 5 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 3 def phase_signal @phase_signal end |
#pulse_length ⇒ Object
Returns the value of attribute pulse_length.
3 4 5 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 3 def pulse_length @pulse_length end |
#signal_to_phase ⇒ Object
Returns the value of attribute signal_to_phase.
3 4 5 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 3 def signal_to_phase @signal_to_phase end |
Instance Method Details
#decode ⇒ Object
Apply inverse of the PSK strategy to decode the PSK signal
47 48 49 50 51 52 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 47 def decode eqn = coding_strategy.nil? ? decode_eqn : coding_strategy.phase_to_sym(@m) sym = @phase_signal.map{ |phase| eqn[phase] } sym = coding_strategy.decode(sym) if not coding_strategy.nil? return sym end |
#output(a: 1) ⇒ Object
Input Args
- a (optional)
-
Numeric for amplitude of the signal (default value = 1)
Return Digiproc::AnalogSignal of the Phase Shift Keyed signal
35 36 37 38 39 40 41 42 43 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 35 def output(a: 1) eqn = Proc.new do |t| theta_index = (t.to_f / @pulse_length.to_f).floor @carrier_signal_eqn[a, @carrier_frequency, t, @phase_signal[theta_index]] end sample_rate = 0.01 / @carrier_frequency size = @pulse_length.to_f * @phase_signal.length / sample_rate Digiproc::AnalogSignal.new(eqn: eqn, sample_rate: sample_rate, size: size) end |
#reciever_decode ⇒ Object
Based off of reciever Figure 4-15 INTRODUCTION TO DIGITAL COMMUNICATIONS, ZIEMER, PETERSON pg 237 NOTE: SUBOPTIMUM DETECTOR, optimum detector referenced on the above page, different reference This simulates a real-life reciever recieving the siglans and decoding them
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/strategies/modulation/phase_shift_keying_strategy.rb', line 58 def reciever_decode recieved = output.to_ds.fft.magnitude ts = 1 / (@carrier_frequency / 0.01) max_freq = 1.0 / ts normalized_target = @carrier_frequency / max_freq.to_f bw = (0.57 / ts) / max_freq.to_f plt = Digiproc::QuickPlot factory = Digiproc::Factories::FilterFactory bpf = factory.filter_for(type: "bandpass", wo: normalized_target * Math::PI * 2, bw: bw * Math::PI * 2, transition_width: 0.0001, stopband_attenuation: 80) bpf.fft.calculate_at_size(2 ** 16) filtered = (bpf.fft * output.to_ds.fft(2** 16)).ifft.map(&:real) sample_interval = @pulse_length / (0.01 / @carrier_frequency) output = [] for i in (sample_interval + 1).to_i...filtered.length do output << (filtered[i] * filtered[i-sample_interval]) end lpf = factory.filter_for(type: "lowpass", wc: 2 * Math::PI / 4, transition_width: 0.0001, stopband_attenuation: 80) outft = Digiproc::FFT.new(time_data: output, size: 2 ** 16) # TODO FIND WHERE SIGNAL BEGINS AND OUTPUT THE SIGNAL BASED OFF OF # SIGNAL SIZE. ALSO, THERE SHOULD BE A RECIEVER METHOD OR SEPERATE CLASS # WHICH OUPUTS THE RAW DATA OF THE RECIEVERS data = (outft * lpf.fft).ifft.map(&:real) all_out = @phase_signal.size > 200 ? data[55000, 200 * sample_interval].concat(data[0, sample_interval * (@phase_signal.size - 200)]) : data[55000, @phase_signal.size * sample_interval] final_out = [] for i in 0...all_out.length do final_out << all_out[i] if (i + 10) % sample_interval == 0 end final_out end |