-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdecoder_exp.py
142 lines (128 loc) · 4.6 KB
/
decoder_exp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# 32 kbps CVSD Decoder for Digital Non-secure Voice Terminals with Exponential Average Filtering
#
# Nick Andre and Robert Ruark
# 2023
import wave
import matplotlib.pyplot as plt
import numpy as np
import sys
#Set high to enable debug graphs
GRAPH_DEBUG = 0
def dnvt_to_pcm(data):
gains = []
output = []
bits = []
output_graph = []
output_filtered = []
time = []
coincidence_graph = []
input_bits = []
index = 0
current_value = 0
coincidence_counter = 0
ones_count = 0
zeros_count = 0
one_instances = 0
zero_instances = 0
coincidences = 0
syllabic_gain = 0
#Setting tuning parameters
parameters = "rob"
#parameters = "lincoln"
if(parameters == "rob"):
min_gain = 100
gain_fraction = 0.3
gain_step = int(min_gain*gain_fraction) #30
coincidence_valid = 3
signal_decay = 0.96
gain_decay = 0.99
max_gain = 18000
gain = min_gain + syllabic_gain
if(parameters == "lincoln"):
min_gain = 20 #"DELTA_MIN"
gain_step = int(310/4) #"DELTA_MAX" = 77
coincidence_valid = 3
signal_decay = 0.9692332 #"PRINCIPAL_T"
gain_decay = 0.9937694 #"SYLLABIC_T"
max_gain = 18000
gain = min_gain + syllabic_gain
for nibble in data:
bin = int(nibble, 16)
for i in range(4):
bitmask = 0b1 << (3 - i)
current_bit = 1 if bin & bitmask else 0
input_bits.append(current_bit)
#Update coincidence counting
if current_bit == 1:
one_instances += 1
if coincidence_counter < 0:
coincidence_counter = 1
else:
coincidence_counter += 1
else:
zero_instances += 1
if coincidence_counter > 0:
coincidence_counter = -1
else:
coincidence_counter -= 1
#Update syllabic gain (based on coincidence)
if abs(coincidence_counter) >= coincidence_valid:
coincidences += 1
if syllabic_gain < max_gain:
syllabic_gain += gain_step
gain = min_gain + syllabic_gain
#Update Output:
if current_bit == 1:
current_value += gain
else:
current_value -= gain
#Clip signal:
if current_value > 32767:
current_value = 32767
elif current_value < -32768:
current_value = -32768
#Append to outputs
#output.append(int(current_value).to_bytes(2, 'little', signed=True))
output_graph.append(current_value)
coincidence_graph.append(coincidence_counter)
time.append(index/32000)
bits.append(current_bit)
gains.append(gain)
index+=1
#Update gains
current_value *=signal_decay
syllabic_gain *=gain_decay
prevval1 = 0
prevval2 = 0
for i in output_graph:
filtval = 0.33*prevval1+0.33*prevval2+0.34*i
output_filtered.append(filtval)
prevval2 = prevval1
prevval1 = i
output.append(int(filtval).to_bytes(2, 'little', signed=True))
print(f'coincidences {coincidences} samples {len(data) * 4}')
imbalance = abs(one_instances - zero_instances)
imbalance_percent = imbalance/(one_instances + zero_instances)*100
print(f'Ones: {one_instances} Zeros: {zero_instances} Imbalance {imbalance} = {imbalance_percent} %')
if(GRAPH_DEBUG):
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, constrained_layout=True, sharex=True)
ax1.plot(time, gains)
ax2.plot(time, output_graph, time, output_filtered)
ax3.step(time, input_bits, 'o--')
plt.ylabel('Counts')
plt.xlabel('Time (seconds)')
ax1.set_title('Gain')
ax2.set_title('Output')
ax3.set_title('Output Bits')
plt.show()
return output
if __name__ == '__main__':
with open('cvsd_data/genesis_reencoded.hex', 'r') as f: #FDAA10255E
data = f.read()
with wave.open('wav_data/genesis_redecoded_exp.wav', 'wb') as f:
f.setsampwidth(2)
f.setnchannels(1)
f.setframerate(32000)
pcm_data = dnvt_to_pcm(data)
for frame in pcm_data:
f.writeframes(frame)