mirror of
https://github.com/NawfalMotii79/PLFM_RADAR.git
synced 2026-06-08 22:47:16 +00:00
chirp-v2 PR-B: 3-waveform mem generator + 11 new .mem files
Rewrite gen_chirp_mem.py to emit the SHORT (1 µs), MEDIUM (5 µs), and LONG
(30 µs) waveform set on both TX and RX paths. The script is now the single
source for every chirp .mem file; the legacy 6-file set on disk
(long_chirp_lut.mem, long_chirp_seg{0,1}_{i,q}.mem, short_chirp_{i,q}.mem)
is no longer regenerated and gets deleted in PR-C/PR-E when its consumer
modules are removed.
Generated artifacts (committed):
TX (8-bit unsigned offset-binary, fs_dac = 120 MHz):
tx_short_lut.mem 120 lines
tx_medium_lut.mem 600 lines
tx_long_lut.mem 3600 lines
RX (Q15 I/Q hex, fs_sys = 100 MHz, all 2048 lines for uniform BRAM sizing):
rx_short_i.mem / rx_short_q.mem 100 active + 1948 zero-pad
rx_medium_i.mem / rx_medium_q.mem 500 active + 1548 zero-pad
rx_long_seg0_i.mem / rx_long_seg0_q.mem 2048 (samples [0..2047])
rx_long_seg1_i.mem / rx_long_seg1_q.mem 952 active + 1096 zero-pad
Phase model unchanged from chirp-v1: phi(n) = 2π·F_BASEBAND_LOW·t +
π·(BW/T)·t² with F_BASEBAND_LOW=10 MHz and BW=20 MHz. The same formula now
runs three durations and two sample rates from one helper.
rx_long_seg0_i.mem is bit-exact to the legacy long_chirp_seg0_i.mem on disk
(diff -q reports identical) — proves the SHORT/MEDIUM additions did not
perturb the LONG path.
Verification:
- all 11 files have correct line counts (above)
- script is idempotent (re-run produces byte-identical output)
- ruff clean (one E501 line-length + two RUF046 redundant-int casts fixed)
- phase regression at long-seg0 against pre-chirp-v2 reference: bit-exact
No RTL or testbench changes. The legacy .mem files remain on disk for the
existing chirp_memory_loader_param.v / plfm_chirp_controller.v consumers
until PR-C and PR-E delete those modules. No module references the new
files yet.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,55 +1,41 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
gen_chirp_mem.py — Generate all chirp .mem files for AERIS-10 FPGA.
|
||||
gen_chirp_mem.py — Generate the 11 chirp .mem files for the AERIS-10 FPGA.
|
||||
|
||||
Generates the 6 chirp .mem files used by chirp_memory_loader_param.v:
|
||||
- long_chirp_seg{0,1}_{i,q}.mem (4 files, 2048 lines each)
|
||||
- short_chirp_{i,q}.mem (2 files, 50 lines each)
|
||||
3-ladder waveform set (chirp-v2 PR-B). Replaces the legacy 2-waveform script.
|
||||
The legacy 6-file output (long_chirp_seg{0,1}_{i,q}.mem, short_chirp_{i,q}.mem,
|
||||
long_chirp_lut.mem) is no longer regenerated by this script; the legacy files
|
||||
on disk are deleted in PR-C (RX) and PR-E (TX) when their consumers go away.
|
||||
|
||||
Long chirp:
|
||||
The 3000-sample baseband chirp (30 us at 100 MHz system clock) is
|
||||
segmented into 2 blocks of 2048 samples. Each segment covers a
|
||||
different time window of the chirp:
|
||||
seg0: samples 0 .. 2047
|
||||
seg1: samples 2048 .. 4095 (only 952 valid chirp samples; 1096 zeros)
|
||||
TX side (DAC LUTs, 8-bit unsigned offset-binary, fs_dac = 120 MHz):
|
||||
tx_short_lut.mem 120 samples (1 µs)
|
||||
tx_medium_lut.mem 600 samples (5 µs)
|
||||
tx_long_lut.mem 3600 samples (30 µs)
|
||||
|
||||
The memory loader stores 2*2048 = 4096 contiguous samples indexed
|
||||
by {segment_select[0], sample_addr[10:0]}. The long chirp has
|
||||
3000 samples, so:
|
||||
seg0: chirp[0..2047] — all valid data
|
||||
seg1: chirp[2048..2999] + 1096 zeros (samples past chirp end)
|
||||
RX side (matched-filter reference, Q15 I/Q hex, fs_sys = 100 MHz, all 2048 entries):
|
||||
rx_short_i.mem / rx_short_q.mem 100 active + 1948 zero-pad
|
||||
rx_medium_i.mem / rx_medium_q.mem 500 active + 1548 zero-pad
|
||||
rx_long_seg0_i.mem / rx_long_seg0_q.mem 2048 (samples 0..2047 of long chirp)
|
||||
rx_long_seg1_i.mem / rx_long_seg1_q.mem 952 active + 1096 zero-pad
|
||||
(samples 2048..2999 of long chirp)
|
||||
|
||||
Short chirp:
|
||||
50 samples (0.5 us at 100 MHz), same chirp formula with
|
||||
T_SHORT_CHIRP and CHIRP_BW.
|
||||
|
||||
Phase model (baseband, post-DDC):
|
||||
phase(n) = 2*pi*F_BASEBAND_LOW*t + pi * chirp_rate * t^2, t = n / FS_SYS
|
||||
Phase model (baseband, post-DDC for RX, pre-upmix for TX):
|
||||
phase(n) = 2π · F_BASEBAND_LOW · t + π · chirp_rate · t²
|
||||
chirp_rate = CHIRP_BW / T_chirp
|
||||
F_BASEBAND_LOW = 10 MHz (DAC chirp low-edge frequency)
|
||||
F_BASEBAND_LOW = 10 MHz
|
||||
CHIRP_BW = 20 MHz (uniform across all three waveforms — same range res)
|
||||
|
||||
This produces a F_BASEBAND_LOW..(F_BASEBAND_LOW+CHIRP_BW) baseband upchirp.
|
||||
End-to-end frequency plan (TX-I, unchanged from chirp-v1):
|
||||
DAC LUT : 10..30 MHz @ fs_dac=120 MHz
|
||||
TX upmix : LO=10.500 GHz, high-side -> RF transmitted: 10.510..10.530 GHz
|
||||
RX downmix: LO=10.380 GHz, high-side -> IF at ADC: 130..150 MHz
|
||||
DDC NCO : 120 MHz exactly (ddc_400m.v) -> baseband: 10..30 MHz
|
||||
|
||||
End-to-end frequency plan (TX-I, 2026-04-28):
|
||||
DAC LUT : 10..30 MHz @ fs_dac=120 MHz (plfm_chirp_controller.v;
|
||||
Hilbert-confirmed for both
|
||||
long and short LUTs)
|
||||
TX upmix : LO=10.500 GHz (adf4382a_manager.h:35), high-side
|
||||
-> RF transmitted: 10.510..10.530 GHz
|
||||
RX downmix: LO=10.380 GHz (adf4382a_manager.h:36), high-side
|
||||
-> IF at ADC: 130..150 MHz
|
||||
DDC NCO : 120 MHz exactly (ddc_400m.v:201)
|
||||
-> baseband: 10..30 MHz <-- matched-filter reference
|
||||
radar_scene.py uses the same F_BASEBAND_LOW and CHIRP_BW constants; both
|
||||
must stay in sync.
|
||||
|
||||
Sideband orientation (high-side at both mixers) is the conventional choice
|
||||
and consistent with all design comments / antenna match (10.25..10.75 GHz);
|
||||
loopback capture would settle it definitively. If either mixer turns out to
|
||||
be low-side, the sign of F_BASEBAND_LOW flips and/or the chirp direction
|
||||
reverses; revisit before re-generating .mem files.
|
||||
|
||||
radar_scene.py uses the same F_BASEBAND_LOW; both must stay in sync.
|
||||
|
||||
Scaling: 0.9 * 32767 (Q15)
|
||||
Scaling: 0.9 of full-scale for the Q15 (RX) path. TX LUT scales 127·0.9 ≈ 114
|
||||
into the ±127 swing around the 128 (8'd128) idle code.
|
||||
|
||||
Usage:
|
||||
python3 gen_chirp_mem.py
|
||||
@@ -60,163 +46,153 @@ import os
|
||||
import sys
|
||||
|
||||
# ============================================================================
|
||||
# AERIS-10 Parameters (matching radar_scene.py)
|
||||
# AERIS-10 Parameters
|
||||
# ============================================================================
|
||||
CHIRP_BW = 20e6 # 20 MHz sweep bandwidth
|
||||
FS_SYS = 100e6 # System clock (100 MHz, post-CIC)
|
||||
T_LONG_CHIRP = 30e-6 # 30 us long chirp duration
|
||||
T_SHORT_CHIRP = 0.5e-6 # 0.5 us short chirp duration
|
||||
FFT_SIZE = 2048
|
||||
# DAC chirp baseband low-edge frequency. The TX LUT in plfm_chirp_controller.v
|
||||
# is a 10..30 MHz upchirp at fs_dac=120 MHz (Hilbert-confirmed for both long
|
||||
# and short LUTs). With TX_LO=10.500 GHz, RX_LO=10.380 GHz (adf4382a_manager.h)
|
||||
# and the 120 MHz DDC NCO (ddc_400m.v), high-side mixing places the post-DDC
|
||||
# echo at 10..30 MHz baseband, not 0..20 MHz. The matched-filter reference
|
||||
# must include this +10 MHz DC offset.
|
||||
F_BASEBAND_LOW = 10e6
|
||||
LONG_CHIRP_SAMPLES = int(T_LONG_CHIRP * FS_SYS) # 3000
|
||||
SHORT_CHIRP_SAMPLES = int(T_SHORT_CHIRP * FS_SYS) # 50
|
||||
LONG_SEGMENTS = 2
|
||||
SCALE = 0.9 # Q15 scaling factor (matches radar_scene.py)
|
||||
Q15_MAX = 32767
|
||||
CHIRP_BW = 20e6 # 20 MHz sweep — same for all three waveforms
|
||||
FS_SYS = 100e6 # System clock for RX matched filter
|
||||
FS_DAC = 120e6 # DAC clock for TX waveform synthesis
|
||||
F_BASEBAND_LOW = 10e6 # Low edge of post-DDC baseband
|
||||
SCALE = 0.9 # Backoff from full-scale (both paths)
|
||||
|
||||
# Output directory (FPGA RTL root, where .mem files live)
|
||||
# Waveform durations (seconds) — see radar_params.vh RP_DEF_*_CHIRP_CYCLES_V2
|
||||
T_SHORT = 1e-6 # 1 µs (PR-B v2; chirp-v1 was 0.5 µs)
|
||||
T_MEDIUM = 5e-6 # 5 µs
|
||||
T_LONG = 30e-6 # 30 µs
|
||||
|
||||
# RX FFT segment size — chirp_reference_rom (PR-C) uses one 2048-entry BRAM
|
||||
# per waveform lane. LONG is the only waveform that crosses the segment
|
||||
# boundary; SHORT and MEDIUM fit in a single 2048-entry buffer with zero-pad.
|
||||
FFT_SIZE = 2048
|
||||
|
||||
# Q15 / 8-bit envelopes
|
||||
Q15_MAX = 32767
|
||||
DAC_MID = 128 # 8'd128 idle code (offset-binary)
|
||||
DAC_AMP = 127 # ±127 swing around DAC_MID
|
||||
|
||||
# Output directory: FPGA RTL root (.mem files live alongside the .v files)
|
||||
MEM_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..')
|
||||
|
||||
|
||||
def generate_full_long_chirp():
|
||||
"""
|
||||
Generate the full 3000-sample baseband chirp in Q15.
|
||||
# ============================================================================
|
||||
# Sample generation — single phase model reused for both TX and RX
|
||||
# ============================================================================
|
||||
def chirp_phase(n: int, fs: float, t_chirp: float) -> float:
|
||||
"""Phase at sample n for the LFM upchirp."""
|
||||
chirp_rate = CHIRP_BW / t_chirp
|
||||
t = n / fs
|
||||
return 2 * math.pi * F_BASEBAND_LOW * t + math.pi * chirp_rate * t * t
|
||||
|
||||
Returns:
|
||||
(chirp_i, chirp_q): lists of 3000 signed 16-bit integers
|
||||
"""
|
||||
chirp_rate = CHIRP_BW / T_LONG_CHIRP # Hz/s
|
||||
|
||||
chirp_i = []
|
||||
chirp_q = []
|
||||
|
||||
for n in range(LONG_CHIRP_SAMPLES):
|
||||
t = n / FS_SYS
|
||||
phase = 2 * math.pi * F_BASEBAND_LOW * t + math.pi * chirp_rate * t * t
|
||||
re_val = round(Q15_MAX * SCALE * math.cos(phase))
|
||||
im_val = round(Q15_MAX * SCALE * math.sin(phase))
|
||||
chirp_i.append(max(-32768, min(32767, re_val)))
|
||||
chirp_q.append(max(-32768, min(32767, im_val)))
|
||||
|
||||
def gen_rx_iq(t_chirp: float):
|
||||
"""Generate Q15 I/Q samples at fs_sys for one chirp duration."""
|
||||
n_samples = round(t_chirp * FS_SYS)
|
||||
chirp_i, chirp_q = [], []
|
||||
for n in range(n_samples):
|
||||
ph = chirp_phase(n, FS_SYS, t_chirp)
|
||||
re = max(-32768, min(32767, round(Q15_MAX * SCALE * math.cos(ph))))
|
||||
im = max(-32768, min(32767, round(Q15_MAX * SCALE * math.sin(ph))))
|
||||
chirp_i.append(re)
|
||||
chirp_q.append(im)
|
||||
return chirp_i, chirp_q
|
||||
|
||||
|
||||
def generate_short_chirp():
|
||||
"""
|
||||
Generate the 50-sample short chirp in Q15.
|
||||
|
||||
Returns:
|
||||
(chirp_i, chirp_q): lists of 50 signed 16-bit integers
|
||||
"""
|
||||
chirp_rate = CHIRP_BW / T_SHORT_CHIRP # Hz/s (much faster sweep)
|
||||
|
||||
chirp_i = []
|
||||
chirp_q = []
|
||||
|
||||
for n in range(SHORT_CHIRP_SAMPLES):
|
||||
t = n / FS_SYS
|
||||
phase = 2 * math.pi * F_BASEBAND_LOW * t + math.pi * chirp_rate * t * t
|
||||
re_val = round(Q15_MAX * SCALE * math.cos(phase))
|
||||
im_val = round(Q15_MAX * SCALE * math.sin(phase))
|
||||
chirp_i.append(max(-32768, min(32767, re_val)))
|
||||
chirp_q.append(max(-32768, min(32767, im_val)))
|
||||
|
||||
return chirp_i, chirp_q
|
||||
def gen_tx_real(t_chirp: float):
|
||||
"""Generate 8-bit unsigned offset-binary real samples at fs_dac."""
|
||||
n_samples = round(t_chirp * FS_DAC)
|
||||
samples = []
|
||||
for n in range(n_samples):
|
||||
ph = chirp_phase(n, FS_DAC, t_chirp)
|
||||
# Real-valued upchirp: cos(phase). Map ±1 → 0..255 with 128 as DC.
|
||||
v = round(DAC_AMP * SCALE * math.cos(ph)) + DAC_MID
|
||||
samples.append(max(0, min(255, v)))
|
||||
return samples
|
||||
|
||||
|
||||
def to_hex16(value):
|
||||
"""Convert signed 16-bit integer to 4-digit hex string (unsigned representation)."""
|
||||
# ============================================================================
|
||||
# .mem writers
|
||||
# ============================================================================
|
||||
def to_hex_signed16(value: int) -> str:
|
||||
"""Signed 16-bit → 4-char hex (two's complement, lowercase)."""
|
||||
if value < 0:
|
||||
value += 0x10000
|
||||
return f"{value:04x}"
|
||||
|
||||
|
||||
def write_mem_file(filename, values):
|
||||
"""Write a list of 16-bit signed integers to a .mem file (hex format)."""
|
||||
def to_hex_u8(value: int) -> str:
|
||||
"""Unsigned 8-bit → 2-char hex (uppercase, matches legacy long_chirp_lut.mem)."""
|
||||
return f"{value:02X}"
|
||||
|
||||
|
||||
def write_lines(filename: str, lines):
|
||||
path = os.path.join(MEM_DIR, filename)
|
||||
with open(path, 'w') as f:
|
||||
for v in values:
|
||||
f.write(to_hex16(v) + '\n')
|
||||
for line in lines:
|
||||
f.write(line + '\n')
|
||||
return path
|
||||
|
||||
|
||||
def write_rx_iq_padded(prefix: str, chirp_i, chirp_q, target_len: int = FFT_SIZE,
|
||||
offset: int = 0):
|
||||
"""
|
||||
Write {prefix}_i.mem and {prefix}_q.mem with `target_len` lines.
|
||||
`offset` selects which slice of the chirp to write — used for LONG segmentation.
|
||||
Cells past the chirp end are zero-padded. Cells before the chirp start (impossible
|
||||
here but kept symmetric) are also zero.
|
||||
"""
|
||||
i_lines, q_lines = [], []
|
||||
for k in range(target_len):
|
||||
src_idx = k + offset
|
||||
if 0 <= src_idx < len(chirp_i):
|
||||
i_lines.append(to_hex_signed16(chirp_i[src_idx]))
|
||||
q_lines.append(to_hex_signed16(chirp_q[src_idx]))
|
||||
else:
|
||||
i_lines.append('0000')
|
||||
q_lines.append('0000')
|
||||
write_lines(f"{prefix}_i.mem", i_lines)
|
||||
write_lines(f"{prefix}_q.mem", q_lines)
|
||||
|
||||
|
||||
def write_tx_lut(filename: str, samples):
|
||||
"""Write 8-bit TX LUT — one sample per line, exactly len(samples) lines."""
|
||||
write_lines(filename, [to_hex_u8(v) for v in samples])
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# main
|
||||
# ============================================================================
|
||||
def verify_phase_match():
|
||||
"""
|
||||
Cross-check that each generated chirp matches the closed-form phase model
|
||||
bit-exactly. radar_scene.py uses the same phase formula and constants;
|
||||
if it ever diverges, this assertion will fire.
|
||||
"""
|
||||
for name, t_chirp in [("SHORT", T_SHORT), ("MEDIUM", T_MEDIUM), ("LONG", T_LONG)]:
|
||||
i, q = gen_rx_iq(t_chirp)
|
||||
n_check = min(64, len(i))
|
||||
for n in range(n_check):
|
||||
ph = chirp_phase(n, FS_SYS, t_chirp)
|
||||
ei = max(-32768, min(32767, round(Q15_MAX * SCALE * math.cos(ph))))
|
||||
eq = max(-32768, min(32767, round(Q15_MAX * SCALE * math.sin(ph))))
|
||||
assert i[n] == ei and q[n] == eq, f"{name} phase mismatch at n={n}"
|
||||
|
||||
|
||||
def main():
|
||||
verify_phase_match()
|
||||
|
||||
# ---- Long chirp ----
|
||||
long_i, long_q = generate_full_long_chirp()
|
||||
# ---- TX LUTs (8-bit real, fs_dac = 120 MHz) ----
|
||||
write_tx_lut("tx_short_lut.mem", gen_tx_real(T_SHORT)) # 120 lines
|
||||
write_tx_lut("tx_medium_lut.mem", gen_tx_real(T_MEDIUM)) # 600 lines
|
||||
write_tx_lut("tx_long_lut.mem", gen_tx_real(T_LONG)) # 3600 lines
|
||||
|
||||
# Verify first sample matches generate_reference_chirp_q15() from radar_scene.py
|
||||
# (which only generates the first 1024 samples)
|
||||
|
||||
# Segment into 4 x 1024 blocks
|
||||
for seg in range(LONG_SEGMENTS):
|
||||
start = seg * FFT_SIZE
|
||||
end = start + FFT_SIZE
|
||||
|
||||
seg_i = []
|
||||
seg_q = []
|
||||
valid_count = 0
|
||||
|
||||
for idx in range(start, end):
|
||||
if idx < LONG_CHIRP_SAMPLES:
|
||||
seg_i.append(long_i[idx])
|
||||
seg_q.append(long_q[idx])
|
||||
valid_count += 1
|
||||
else:
|
||||
seg_i.append(0)
|
||||
seg_q.append(0)
|
||||
|
||||
FFT_SIZE - valid_count
|
||||
|
||||
write_mem_file(f"long_chirp_seg{seg}_i.mem", seg_i)
|
||||
write_mem_file(f"long_chirp_seg{seg}_q.mem", seg_q)
|
||||
|
||||
# ---- Short chirp ----
|
||||
short_i, short_q = generate_short_chirp()
|
||||
|
||||
write_mem_file("short_chirp_i.mem", short_i)
|
||||
write_mem_file("short_chirp_q.mem", short_q)
|
||||
|
||||
# ---- Verification summary ----
|
||||
|
||||
# Self-check: recompute the phase formula and verify the seg0 .mem matches.
|
||||
# radar_scene.py.generate_reference_chirp_q15() uses the same phase form
|
||||
# and the same F_BASEBAND_LOW; the two stay in sync by construction.
|
||||
chirp_rate = CHIRP_BW / T_LONG_CHIRP
|
||||
mismatches = 0
|
||||
for n in range(FFT_SIZE):
|
||||
t = n / FS_SYS
|
||||
phase = 2 * math.pi * F_BASEBAND_LOW * t + math.pi * chirp_rate * t * t
|
||||
expected_i = max(-32768, min(32767, round(Q15_MAX * SCALE * math.cos(phase))))
|
||||
expected_q = max(-32768, min(32767, round(Q15_MAX * SCALE * math.sin(phase))))
|
||||
if long_i[n] != expected_i or long_q[n] != expected_q:
|
||||
mismatches += 1
|
||||
|
||||
if mismatches == 0:
|
||||
pass
|
||||
else:
|
||||
return 1
|
||||
|
||||
# Check magnitude envelope
|
||||
max(math.sqrt(i*i + q*q) for i, q in zip(long_i, long_q, strict=False))
|
||||
|
||||
# Check seg1 zero padding (samples 3000-4095 should be zero)
|
||||
seg1_i_path = os.path.join(MEM_DIR, 'long_chirp_seg1_i.mem')
|
||||
with open(seg1_i_path) as f:
|
||||
seg1_lines = [line.strip() for line in f if line.strip()]
|
||||
# Indices 952..2047 in seg1 (global 3000..4095) should be zero
|
||||
nonzero_tail = sum(1 for line in seg1_lines[952:] if line != '0000')
|
||||
|
||||
if nonzero_tail == 0:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
# ---- RX I/Q (Q15, fs_sys = 100 MHz, all padded to FFT_SIZE=2048) ----
|
||||
short_i, short_q = gen_rx_iq(T_SHORT) # 100 active samples
|
||||
medium_i, medium_q = gen_rx_iq(T_MEDIUM) # 500 active samples
|
||||
long_i, long_q = gen_rx_iq(T_LONG) # 3000 active samples
|
||||
|
||||
write_rx_iq_padded("rx_short", short_i, short_q) # offset=0
|
||||
write_rx_iq_padded("rx_medium", medium_i, medium_q) # offset=0
|
||||
write_rx_iq_padded("rx_long_seg0", long_i, long_q, offset=0) # [0..2047]
|
||||
write_rx_iq_padded("rx_long_seg1", long_i, long_q, offset=FFT_SIZE) # [2048..2999]+pad
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,600 @@
|
||||
F2
|
||||
E3
|
||||
B9
|
||||
7F
|
||||
45
|
||||
1C
|
||||
0E
|
||||
20
|
||||
4C
|
||||
88
|
||||
C2
|
||||
E8
|
||||
F1
|
||||
DA
|
||||
A7
|
||||
6A
|
||||
32
|
||||
12
|
||||
12
|
||||
34
|
||||
6C
|
||||
AB
|
||||
DD
|
||||
F2
|
||||
E4
|
||||
B7
|
||||
78
|
||||
3C
|
||||
15
|
||||
10
|
||||
2F
|
||||
68
|
||||
A9
|
||||
DD
|
||||
F2
|
||||
E2
|
||||
B1
|
||||
6F
|
||||
33
|
||||
11
|
||||
15
|
||||
3D
|
||||
7C
|
||||
BD
|
||||
E9
|
||||
F0
|
||||
D0
|
||||
93
|
||||
4F
|
||||
1D
|
||||
0E
|
||||
29
|
||||
63
|
||||
A8
|
||||
DF
|
||||
F2
|
||||
DC
|
||||
A2
|
||||
5C
|
||||
23
|
||||
0E
|
||||
24
|
||||
5D
|
||||
A4
|
||||
DD
|
||||
F2
|
||||
DA
|
||||
9F
|
||||
57
|
||||
1F
|
||||
0E
|
||||
2B
|
||||
6B
|
||||
B3
|
||||
E7
|
||||
F0
|
||||
CB
|
||||
87
|
||||
40
|
||||
13
|
||||
15
|
||||
44
|
||||
8C
|
||||
D0
|
||||
F1
|
||||
E2
|
||||
A7
|
||||
5C
|
||||
20
|
||||
0E
|
||||
2F
|
||||
74
|
||||
BF
|
||||
ED
|
||||
EA
|
||||
B7
|
||||
6B
|
||||
28
|
||||
0E
|
||||
29
|
||||
6C
|
||||
B9
|
||||
EC
|
||||
EB
|
||||
B8
|
||||
6A
|
||||
26
|
||||
0E
|
||||
2D
|
||||
74
|
||||
C2
|
||||
EF
|
||||
E6
|
||||
AA
|
||||
59
|
||||
1C
|
||||
11
|
||||
3E
|
||||
8C
|
||||
D5
|
||||
F2
|
||||
D5
|
||||
8C
|
||||
3C
|
||||
10
|
||||
1E
|
||||
60
|
||||
B3
|
||||
EB
|
||||
EA
|
||||
B0
|
||||
5D
|
||||
1C
|
||||
11
|
||||
43
|
||||
96
|
||||
DD
|
||||
F1
|
||||
C6
|
||||
74
|
||||
28
|
||||
0E
|
||||
34
|
||||
85
|
||||
D3
|
||||
F2
|
||||
D0
|
||||
7F
|
||||
2F
|
||||
0E
|
||||
2F
|
||||
80
|
||||
D1
|
||||
F2
|
||||
D0
|
||||
7E
|
||||
2D
|
||||
0E
|
||||
34
|
||||
88
|
||||
D8
|
||||
F2
|
||||
C6
|
||||
6F
|
||||
23
|
||||
10
|
||||
43
|
||||
9D
|
||||
E4
|
||||
ED
|
||||
B0
|
||||
55
|
||||
15
|
||||
1A
|
||||
60
|
||||
BB
|
||||
F0
|
||||
DC
|
||||
8C
|
||||
33
|
||||
0E
|
||||
34
|
||||
8C
|
||||
DD
|
||||
EF
|
||||
B7
|
||||
59
|
||||
16
|
||||
1A
|
||||
64
|
||||
C2
|
||||
F2
|
||||
D3
|
||||
7B
|
||||
26
|
||||
10
|
||||
48
|
||||
A8
|
||||
EC
|
||||
E3
|
||||
94
|
||||
36
|
||||
0E
|
||||
37
|
||||
95
|
||||
E4
|
||||
EA
|
||||
A2
|
||||
41
|
||||
0E
|
||||
2F
|
||||
8C
|
||||
E0
|
||||
EC
|
||||
A7
|
||||
45
|
||||
0F
|
||||
2E
|
||||
8C
|
||||
E1
|
||||
EB
|
||||
A3
|
||||
40
|
||||
0E
|
||||
35
|
||||
96
|
||||
E7
|
||||
E6
|
||||
95
|
||||
33
|
||||
0E
|
||||
44
|
||||
A9
|
||||
EE
|
||||
DA
|
||||
7E
|
||||
23
|
||||
14
|
||||
5D
|
||||
C3
|
||||
F2
|
||||
C3
|
||||
5C
|
||||
13
|
||||
24
|
||||
82
|
||||
DF
|
||||
EB
|
||||
9D
|
||||
36
|
||||
0E
|
||||
47
|
||||
B1
|
||||
F1
|
||||
D0
|
||||
6A
|
||||
17
|
||||
20
|
||||
7C
|
||||
DD
|
||||
EB
|
||||
9C
|
||||
33
|
||||
0F
|
||||
4F
|
||||
BB
|
||||
F2
|
||||
C2
|
||||
57
|
||||
10
|
||||
2F
|
||||
98
|
||||
EB
|
||||
DC
|
||||
78
|
||||
1C
|
||||
1C
|
||||
79
|
||||
DD
|
||||
EA
|
||||
94
|
||||
2B
|
||||
12
|
||||
61
|
||||
CE
|
||||
F0
|
||||
A7
|
||||
39
|
||||
0F
|
||||
52
|
||||
C2
|
||||
F2
|
||||
B4
|
||||
43
|
||||
0E
|
||||
49
|
||||
BB
|
||||
F2
|
||||
B9
|
||||
47
|
||||
0E
|
||||
47
|
||||
B9
|
||||
F2
|
||||
B8
|
||||
45
|
||||
0E
|
||||
4B
|
||||
BF
|
||||
F2
|
||||
B0
|
||||
3D
|
||||
0F
|
||||
56
|
||||
C9
|
||||
F0
|
||||
A2
|
||||
30
|
||||
12
|
||||
68
|
||||
D8
|
||||
EA
|
||||
8C
|
||||
21
|
||||
1C
|
||||
82
|
||||
E7
|
||||
DC
|
||||
6E
|
||||
13
|
||||
2F
|
||||
A3
|
||||
F1
|
||||
C2
|
||||
4B
|
||||
0E
|
||||
4F
|
||||
C7
|
||||
F0
|
||||
9C
|
||||
28
|
||||
18
|
||||
7C
|
||||
E5
|
||||
DC
|
||||
6A
|
||||
11
|
||||
37
|
||||
B1
|
||||
F2
|
||||
B0
|
||||
36
|
||||
12
|
||||
6D
|
||||
DF
|
||||
E2
|
||||
72
|
||||
13
|
||||
34
|
||||
AF
|
||||
F2
|
||||
AE
|
||||
33
|
||||
14
|
||||
76
|
||||
E4
|
||||
DA
|
||||
63
|
||||
0F
|
||||
44
|
||||
C2
|
||||
F0
|
||||
95
|
||||
21
|
||||
21
|
||||
96
|
||||
F0
|
||||
BF
|
||||
40
|
||||
10
|
||||
6C
|
||||
E1
|
||||
DC
|
||||
63
|
||||
0F
|
||||
49
|
||||
C9
|
||||
EC
|
||||
86
|
||||
18
|
||||
2F
|
||||
AF
|
||||
F2
|
||||
A2
|
||||
26
|
||||
1E
|
||||
95
|
||||
F1
|
||||
B9
|
||||
36
|
||||
15
|
||||
80
|
||||
EC
|
||||
C9
|
||||
45
|
||||
10
|
||||
70
|
||||
E5
|
||||
D3
|
||||
51
|
||||
0E
|
||||
64
|
||||
E0
|
||||
DA
|
||||
59
|
||||
0E
|
||||
5E
|
||||
DD
|
||||
DC
|
||||
5D
|
||||
0E
|
||||
5D
|
||||
DD
|
||||
DC
|
||||
5B
|
||||
0E
|
||||
60
|
||||
DF
|
||||
D9
|
||||
55
|
||||
0E
|
||||
68
|
||||
E4
|
||||
D2
|
||||
4B
|
||||
10
|
||||
76
|
||||
EA
|
||||
C6
|
||||
3D
|
||||
15
|
||||
88
|
||||
F0
|
||||
B5
|
||||
2D
|
||||
1E
|
||||
9F
|
||||
F2
|
||||
9D
|
||||
1D
|
||||
2F
|
||||
B9
|
||||
EE
|
||||
7F
|
||||
11
|
||||
49
|
||||
D3
|
||||
E0
|
||||
5C
|
||||
0E
|
||||
6C
|
||||
E8
|
||||
C6
|
||||
39
|
||||
18
|
||||
96
|
||||
F2
|
||||
9F
|
||||
1C
|
||||
34
|
||||
C2
|
||||
EA
|
||||
6E
|
||||
0E
|
||||
60
|
||||
E4
|
||||
CB
|
||||
3C
|
||||
18
|
||||
98
|
||||
F2
|
||||
98
|
||||
17
|
||||
3E
|
||||
CE
|
||||
E2
|
||||
59
|
||||
0F
|
||||
7A
|
||||
EF
|
||||
B0
|
||||
23
|
||||
2D
|
||||
BD
|
||||
EA
|
||||
6A
|
||||
0E
|
||||
6D
|
||||
EC
|
||||
B9
|
||||
28
|
||||
29
|
||||
B9
|
||||
EB
|
||||
6B
|
||||
0E
|
||||
70
|
||||
ED
|
||||
B4
|
||||
23
|
||||
2F
|
||||
C3
|
||||
E6
|
||||
5C
|
||||
0F
|
||||
82
|
||||
F1
|
||||
9F
|
||||
17
|
||||
44
|
||||
D8
|
||||
D5
|
||||
40
|
||||
1A
|
||||
A5
|
||||
F0
|
||||
78
|
||||
0E
|
||||
6B
|
||||
ED
|
||||
B0
|
||||
1F
|
||||
38
|
||||
D0
|
||||
DA
|
||||
45
|
||||
18
|
||||
A4
|
||||
F0
|
||||
74
|
||||
0E
|
||||
74
|
||||
F0
|
||||
A2
|
||||
17
|
||||
49
|
||||
DF
|
||||
C9
|
||||
2F
|
||||
29
|
||||
C2
|
||||
E3
|
||||
4F
|
||||
15
|
||||
9F
|
||||
F0
|
||||
72
|
||||
0E
|
||||
7C
|
||||
F2
|
||||
94
|
||||
11
|
||||
5D
|
||||
EA
|
||||
B1
|
||||
1C
|
||||
43
|
||||
DD
|
||||
C8
|
||||
2B
|
||||
2F
|
||||
CD
|
||||
D9
|
||||
3C
|
||||
21
|
||||
BB
|
||||
E4
|
||||
4D
|
||||
18
|
||||
AB
|
||||
EB
|
||||
5D
|
||||
12
|
||||
9D
|
||||
EF
|
||||
6A
|
||||
0F
|
||||
91
|
||||
F1
|
||||
74
|
||||
0E
|
||||
88
|
||||
F2
|
||||
7B
|
||||
0E
|
||||
82
|
||||
F2
|
||||
7F
|
||||
0E
|
||||
80
|
||||
@@ -0,0 +1,120 @@
|
||||
F2
|
||||
E3
|
||||
B7
|
||||
7C
|
||||
40
|
||||
17
|
||||
0F
|
||||
2B
|
||||
64
|
||||
A8
|
||||
DE
|
||||
F2
|
||||
DC
|
||||
A3
|
||||
5B
|
||||
21
|
||||
0E
|
||||
2B
|
||||
6E
|
||||
BA
|
||||
EB
|
||||
EB
|
||||
B7
|
||||
68
|
||||
24
|
||||
0E
|
||||
35
|
||||
84
|
||||
D2
|
||||
F2
|
||||
D1
|
||||
80
|
||||
2E
|
||||
0E
|
||||
35
|
||||
8C
|
||||
DC
|
||||
F0
|
||||
B7
|
||||
58
|
||||
15
|
||||
1D
|
||||
6E
|
||||
CD
|
||||
F2
|
||||
C0
|
||||
5B
|
||||
13
|
||||
24
|
||||
80
|
||||
DE
|
||||
EB
|
||||
9C
|
||||
33
|
||||
0F
|
||||
52
|
||||
C0
|
||||
F2
|
||||
B7
|
||||
46
|
||||
0E
|
||||
47
|
||||
BB
|
||||
F2
|
||||
B2
|
||||
3C
|
||||
0F
|
||||
5D
|
||||
D2
|
||||
EB
|
||||
8A
|
||||
1D
|
||||
24
|
||||
98
|
||||
F0
|
||||
C0
|
||||
40
|
||||
10
|
||||
6E
|
||||
E3
|
||||
D8
|
||||
58
|
||||
0E
|
||||
5D
|
||||
DC
|
||||
DC
|
||||
5B
|
||||
0E
|
||||
64
|
||||
E3
|
||||
D1
|
||||
46
|
||||
12
|
||||
84
|
||||
F0
|
||||
AE
|
||||
24
|
||||
2B
|
||||
BB
|
||||
EB
|
||||
6C
|
||||
0E
|
||||
6E
|
||||
ED
|
||||
B2
|
||||
21
|
||||
35
|
||||
CD
|
||||
DC
|
||||
46
|
||||
18
|
||||
A8
|
||||
EE
|
||||
68
|
||||
0F
|
||||
8C
|
||||
F2
|
||||
7C
|
||||
0E
|
||||
80
|
||||
Reference in New Issue
Block a user